| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 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 |  | 
| Mathieu Chartier | b666f48 | 2015-02-18 14:33:14 -0800 | [diff] [blame] | 17 | #include "base/arena_allocator.h" | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 18 | #include "builder.h" | 
| Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 19 | #include "code_generator.h" | 
| Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 20 | #include "code_generator_x86.h" | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 21 | #include "dex_file.h" | 
 | 22 | #include "dex_instruction.h" | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 23 | #include "driver/compiler_options.h" | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 24 | #include "nodes.h" | 
 | 25 | #include "optimizing_unit_test.h" | 
| Nicolas Geoffray | 360231a | 2014-10-08 21:07:48 +0100 | [diff] [blame] | 26 | #include "prepare_for_register_allocation.h" | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 27 | #include "ssa_liveness_analysis.h" | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 28 |  | 
 | 29 | #include "gtest/gtest.h" | 
 | 30 |  | 
 | 31 | namespace art { | 
 | 32 |  | 
 | 33 | static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) { | 
| David Brazdil | 5e8b137 | 2015-01-23 14:39:08 +0000 | [diff] [blame] | 34 |   HGraph* graph = new (allocator) HGraph(allocator); | 
 | 35 |   HGraphBuilder builder(graph); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 36 |   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); | 
| David Brazdil | 5e8b137 | 2015-01-23 14:39:08 +0000 | [diff] [blame] | 37 |   builder.BuildGraph(*item); | 
| Nicolas Geoffray | fbc695f | 2014-09-15 15:33:30 +0000 | [diff] [blame] | 38 |   // Suspend checks implementation may change in the future, and this test relies | 
 | 39 |   // on how instructions are ordered. | 
 | 40 |   RemoveSuspendChecks(graph); | 
| Nicolas Geoffray | e53798a | 2014-12-01 10:31:54 +0000 | [diff] [blame] | 41 |   graph->TryBuildingSsa(); | 
| Nicolas Geoffray | 360231a | 2014-10-08 21:07:48 +0100 | [diff] [blame] | 42 |   // `Inline` conditions into ifs. | 
 | 43 |   PrepareForRegisterAllocation(graph).Run(); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 44 |   return graph; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | TEST(LiveRangesTest, CFG1) { | 
 | 48 |   /* | 
 | 49 |    * Test the following snippet: | 
 | 50 |    *  return 0; | 
 | 51 |    * | 
 | 52 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 53 |    *       2: constant0 | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 54 |    *       4: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 55 |    *           | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 56 |    *       8: return | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 57 |    *           | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 58 |    *       12: exit | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 59 |    */ | 
 | 60 |   const uint16_t data[] = ONE_REGISTER_CODE_ITEM( | 
 | 61 |     Instruction::CONST_4 | 0 | 0, | 
 | 62 |     Instruction::RETURN); | 
 | 63 |  | 
 | 64 |   ArenaPool pool; | 
 | 65 |   ArenaAllocator allocator(&pool); | 
 | 66 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Nicolas Geoffray | 31d76b4 | 2014-06-09 15:02:22 +0100 | [diff] [blame] | 67 |  | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 68 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 69 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 70 |   liveness.Analyze(); | 
 | 71 |  | 
 | 72 |   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 73 |   LiveRange* range = interval->GetFirstRange(); | 
 | 74 |   ASSERT_EQ(2u, range->GetStart()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 75 |   // Last use is the return instruction. | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 76 |   ASSERT_EQ(8u, range->GetEnd()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 77 |   HBasicBlock* block = graph->GetBlocks().Get(1); | 
| Roland Levillain | 476df55 | 2014-10-09 17:51:36 +0100 | [diff] [blame] | 78 |   ASSERT_TRUE(block->GetLastInstruction()->IsReturn()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 79 |   ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition()); | 
 | 80 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 81 | } | 
 | 82 |  | 
 | 83 | TEST(LiveRangesTest, CFG2) { | 
 | 84 |   /* | 
 | 85 |    * Test the following snippet: | 
 | 86 |    *  var a = 0; | 
 | 87 |    *  if (0 == 0) { | 
 | 88 |    *  } else { | 
 | 89 |    *  } | 
 | 90 |    *  return a; | 
 | 91 |    * | 
 | 92 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 93 |    *       2: constant0 | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 94 |    *       4: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 95 |    *           | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 96 |    *       8: equal | 
 | 97 |    *       10: if | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 98 |    *       /       \ | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 99 |    *   14: goto   18: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 100 |    *       \       / | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 101 |    *       22: return | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 102 |    *         | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 103 |    *       26: exit | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 104 |    */ | 
 | 105 |   const uint16_t data[] = ONE_REGISTER_CODE_ITEM( | 
 | 106 |     Instruction::CONST_4 | 0 | 0, | 
 | 107 |     Instruction::IF_EQ, 3, | 
 | 108 |     Instruction::GOTO | 0x100, | 
 | 109 |     Instruction::RETURN | 0 << 8); | 
 | 110 |  | 
 | 111 |   ArenaPool pool; | 
 | 112 |   ArenaAllocator allocator(&pool); | 
 | 113 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 114 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 115 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 116 |   liveness.Analyze(); | 
 | 117 |  | 
 | 118 |   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 119 |   LiveRange* range = interval->GetFirstRange(); | 
 | 120 |   ASSERT_EQ(2u, range->GetStart()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 121 |   // Last use is the return instruction. | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 122 |   ASSERT_EQ(22u, range->GetEnd()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 123 |   HBasicBlock* block = graph->GetBlocks().Get(3); | 
| Roland Levillain | 476df55 | 2014-10-09 17:51:36 +0100 | [diff] [blame] | 124 |   ASSERT_TRUE(block->GetLastInstruction()->IsReturn()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 125 |   ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition()); | 
 | 126 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 127 | } | 
 | 128 |  | 
 | 129 | TEST(LiveRangesTest, CFG3) { | 
 | 130 |   /* | 
 | 131 |    * Test the following snippet: | 
 | 132 |    *  var a = 0; | 
 | 133 |    *  if (0 == 0) { | 
 | 134 |    *  } else { | 
 | 135 |    *    a = 4; | 
 | 136 |    *  } | 
 | 137 |    *  return a; | 
 | 138 |    * | 
 | 139 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 140 |    *       2: constant0 | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 141 |    *       4: constant4 | 
 | 142 |    *       6: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 143 |    *           | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 144 |    *       10: equal | 
 | 145 |    *       12: if | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 146 |    *       /       \ | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 147 |    *   16: goto   20: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 148 |    *       \       / | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 149 |    *       22: phi | 
 | 150 |    *       24: return | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 151 |    *         | | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 152 |    *       28: exit | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 153 |    */ | 
 | 154 |   const uint16_t data[] = ONE_REGISTER_CODE_ITEM( | 
 | 155 |     Instruction::CONST_4 | 0 | 0, | 
 | 156 |     Instruction::IF_EQ, 3, | 
 | 157 |     Instruction::CONST_4 | 4 << 12 | 0, | 
 | 158 |     Instruction::RETURN | 0 << 8); | 
 | 159 |  | 
 | 160 |   ArenaPool pool; | 
 | 161 |   ArenaAllocator allocator(&pool); | 
 | 162 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 163 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 164 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 165 |   liveness.Analyze(); | 
 | 166 |  | 
| Nicolas Geoffray | ec7e472 | 2014-06-06 11:24:33 +0100 | [diff] [blame] | 167 |   // Test for the 4 constant. | 
 | 168 |   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 169 |   LiveRange* range = interval->GetFirstRange(); | 
| Nicolas Geoffray | ec7e472 | 2014-06-06 11:24:33 +0100 | [diff] [blame] | 170 |   ASSERT_EQ(4u, range->GetStart()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 171 |   // Last use is the phi at the return block so instruction is live until | 
 | 172 |   // the end of the then block. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 173 |   ASSERT_EQ(18u, range->GetEnd()); | 
 | 174 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 175 |  | 
| Nicolas Geoffray | ec7e472 | 2014-06-06 11:24:33 +0100 | [diff] [blame] | 176 |   // Test for the 0 constant. | 
 | 177 |   interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 178 |   // The then branch is a hole for this constant, therefore its interval has 2 ranges. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 179 |   // First range starts from the definition and ends at the if block. | 
 | 180 |   range = interval->GetFirstRange(); | 
| Nicolas Geoffray | ec7e472 | 2014-06-06 11:24:33 +0100 | [diff] [blame] | 181 |   ASSERT_EQ(2u, range->GetStart()); | 
 | 182 |   // 14 is the end of the if block. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 183 |   ASSERT_EQ(14u, range->GetEnd()); | 
 | 184 |   // Second range is the else block. | 
 | 185 |   range = range->GetNext(); | 
 | 186 |   ASSERT_EQ(18u, range->GetStart()); | 
 | 187 |   // Last use is the phi at the return block. | 
 | 188 |   ASSERT_EQ(22u, range->GetEnd()); | 
 | 189 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 190 |  | 
 | 191 |   // Test for the phi. | 
| Nicolas Geoffray | e503832 | 2014-07-04 09:41:32 +0100 | [diff] [blame] | 192 |   interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 193 |   range = interval->GetFirstRange(); | 
| Nicolas Geoffray | e503832 | 2014-07-04 09:41:32 +0100 | [diff] [blame] | 194 |   ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 195 |   ASSERT_EQ(22u, range->GetStart()); | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 196 |   ASSERT_EQ(24u, range->GetEnd()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 197 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 198 | } | 
 | 199 |  | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 200 | TEST(LiveRangesTest, Loop1) { | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 201 |   /* | 
 | 202 |    * Test the following snippet: | 
 | 203 |    *  var a = 0; | 
 | 204 |    *  while (a == a) { | 
 | 205 |    *    a = 4; | 
 | 206 |    *  } | 
 | 207 |    *  return 5; | 
 | 208 |    * | 
 | 209 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 210 |    *       2: constant0 | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 211 |    *       4: constant4 | 
 | 212 |    *       6: constant5 | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 213 |    *       8: goto | 
 | 214 |    *           | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 215 |    *       12: goto | 
 | 216 |    *           | | 
 | 217 |    *       14: phi | 
 | 218 |    *       16: equal | 
 | 219 |    *       18: if +++++ | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 220 |    *        |       \ + | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 221 |    *        |     22: goto | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 222 |    *        | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 223 |    *       26: return | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 224 |    *         | | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 225 |    *       30: exit | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 226 |    */ | 
 | 227 |  | 
 | 228 |   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( | 
 | 229 |     Instruction::CONST_4 | 0 | 0, | 
 | 230 |     Instruction::IF_EQ, 4, | 
 | 231 |     Instruction::CONST_4 | 4 << 12 | 0, | 
 | 232 |     Instruction::GOTO | 0xFD00, | 
 | 233 |     Instruction::CONST_4 | 5 << 12 | 1 << 8, | 
 | 234 |     Instruction::RETURN | 1 << 8); | 
 | 235 |  | 
 | 236 |   ArenaPool pool; | 
 | 237 |   ArenaAllocator allocator(&pool); | 
 | 238 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Nicolas Geoffray | 9ebc72c | 2014-09-25 16:33:42 +0100 | [diff] [blame] | 239 |   RemoveSuspendChecks(graph); | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 240 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8a16d97 | 2014-09-11 10:30:02 +0100 | [diff] [blame] | 241 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 242 |   liveness.Analyze(); | 
 | 243 |  | 
 | 244 |   // Test for the 0 constant. | 
 | 245 |   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 246 |   LiveRange* range = interval->GetFirstRange(); | 
 | 247 |   ASSERT_EQ(2u, range->GetStart()); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 248 |   // Last use is the loop phi so instruction is live until | 
 | 249 |   // the end of the pre loop header. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 250 |   ASSERT_EQ(14u, range->GetEnd()); | 
 | 251 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 252 |  | 
 | 253 |   // Test for the 4 constant. | 
 | 254 |   interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 255 |   range = interval->GetFirstRange(); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 256 |   // The instruction is live until the end of the loop. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 257 |   ASSERT_EQ(4u, range->GetStart()); | 
 | 258 |   ASSERT_EQ(24u, range->GetEnd()); | 
 | 259 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 260 |  | 
 | 261 |   // Test for the 5 constant. | 
 | 262 |   interval = liveness.GetInstructionFromSsaIndex(2)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 263 |   range = interval->GetFirstRange(); | 
 | 264 |   // The instruction is live until the return instruction after the loop. | 
 | 265 |   ASSERT_EQ(6u, range->GetStart()); | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 266 |   ASSERT_EQ(26u, range->GetEnd()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 267 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 268 |  | 
 | 269 |   // Test for the phi. | 
 | 270 |   interval = liveness.GetInstructionFromSsaIndex(3)->GetLiveInterval(); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 271 |   range = interval->GetFirstRange(); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 272 |   // Instruction is consumed by the if. | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 273 |   ASSERT_EQ(14u, range->GetStart()); | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 274 |   ASSERT_EQ(17u, range->GetEnd()); | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 275 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 276 | } | 
 | 277 |  | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 278 | TEST(LiveRangesTest, Loop2) { | 
 | 279 |   /* | 
 | 280 |    * Test the following snippet: | 
 | 281 |    *  var a = 0; | 
 | 282 |    *  while (a == a) { | 
 | 283 |    *    a = a + a; | 
 | 284 |    *  } | 
 | 285 |    *  return a; | 
 | 286 |    * | 
 | 287 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 288 |    *       2: constant0 | 
 | 289 |    *       4: goto | 
 | 290 |    *           | | 
 | 291 |    *       8: goto | 
 | 292 |    *           | | 
 | 293 |    *       10: phi | 
 | 294 |    *       12: equal | 
 | 295 |    *       14: if +++++ | 
 | 296 |    *        |       \ + | 
 | 297 |    *        |     18: suspend | 
 | 298 |    *        |     20: add | 
 | 299 |    *        |     22: goto | 
 | 300 |    *        | | 
 | 301 |    *       26: return | 
 | 302 |    *         | | 
 | 303 |    *       30: exit | 
 | 304 |    * | 
 | 305 |    * We want to make sure the phi at 10 has a lifetime hole after the add at 20. | 
 | 306 |    */ | 
 | 307 |  | 
 | 308 |   const uint16_t data[] = ONE_REGISTER_CODE_ITEM( | 
 | 309 |     Instruction::CONST_4 | 0 | 0, | 
 | 310 |     Instruction::IF_EQ, 6, | 
 | 311 |     Instruction::ADD_INT, 0, 0, | 
 | 312 |     Instruction::GOTO | 0xFB00, | 
 | 313 |     Instruction::RETURN | 0 << 8); | 
 | 314 |  | 
 | 315 |   ArenaPool pool; | 
 | 316 |   ArenaAllocator allocator(&pool); | 
 | 317 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 318 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 319 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
 | 320 |   liveness.Analyze(); | 
 | 321 |  | 
 | 322 |   // Test for the 0 constant. | 
 | 323 |   HIntConstant* constant = liveness.GetInstructionFromSsaIndex(0)->AsIntConstant(); | 
 | 324 |   LiveInterval* interval = constant->GetLiveInterval(); | 
 | 325 |   LiveRange* range = interval->GetFirstRange(); | 
 | 326 |   ASSERT_EQ(2u, range->GetStart()); | 
 | 327 |   // Last use is the loop phi so instruction is live until | 
 | 328 |   // the end of the pre loop header. | 
 | 329 |   ASSERT_EQ(10u, range->GetEnd()); | 
 | 330 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 331 |  | 
 | 332 |   // Test for the loop phi. | 
 | 333 |   HPhi* phi = liveness.GetInstructionFromSsaIndex(1)->AsPhi(); | 
 | 334 |   interval = phi->GetLiveInterval(); | 
 | 335 |   range = interval->GetFirstRange(); | 
 | 336 |   ASSERT_EQ(10u, range->GetStart()); | 
 | 337 |   ASSERT_EQ(21u, range->GetEnd()); | 
 | 338 |   range = range->GetNext(); | 
 | 339 |   ASSERT_TRUE(range != nullptr); | 
 | 340 |   ASSERT_EQ(24u, range->GetStart()); | 
| Nicolas Geoffray | 8e3964b | 2014-10-17 11:06:38 +0100 | [diff] [blame] | 341 |   ASSERT_EQ(26u, range->GetEnd()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 342 |  | 
 | 343 |   // Test for the add instruction. | 
 | 344 |   HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd(); | 
 | 345 |   interval = add->GetLiveInterval(); | 
 | 346 |   range = interval->GetFirstRange(); | 
 | 347 |   ASSERT_EQ(20u, range->GetStart()); | 
 | 348 |   ASSERT_EQ(24u, range->GetEnd()); | 
 | 349 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 350 | } | 
 | 351 |  | 
 | 352 | TEST(LiveRangesTest, CFG4) { | 
 | 353 |   /* | 
 | 354 |    * Test the following snippet: | 
 | 355 |    *  var a = 0; | 
 | 356 |    *  var b = 4; | 
 | 357 |    *  if (a == a) { | 
 | 358 |    *    a = b + a; | 
 | 359 |    *  } else { | 
 | 360 |    *    a = b + a | 
 | 361 |    *  } | 
 | 362 |    *  return b; | 
 | 363 |    * | 
 | 364 |    * Which becomes the following graph (numbered by lifetime position): | 
 | 365 |    *       2: constant0 | 
 | 366 |    *       4: constant4 | 
 | 367 |    *       6: goto | 
 | 368 |    *           | | 
 | 369 |    *       10: equal | 
 | 370 |    *       12: if | 
 | 371 |    *       /       \ | 
 | 372 |    *   16: add    22: add | 
 | 373 |    *   18: goto   24: goto | 
 | 374 |    *       \       / | 
 | 375 |    *       26: phi | 
 | 376 |    *       28: return | 
 | 377 |    *         | | 
 | 378 |    *       32: exit | 
 | 379 |    * | 
 | 380 |    * We want to make sure the constant0 has a lifetime hole after the 16: add. | 
 | 381 |    */ | 
 | 382 |   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( | 
 | 383 |     Instruction::CONST_4 | 0 | 0, | 
 | 384 |     Instruction::CONST_4 | 4 << 12 | 1 << 8, | 
 | 385 |     Instruction::IF_EQ, 5, | 
 | 386 |     Instruction::ADD_INT, 1 << 8, | 
 | 387 |     Instruction::GOTO | 0x300, | 
 | 388 |     Instruction::ADD_INT, 1 << 8, | 
| Nicolas Geoffray | a3c00e5 | 2014-11-25 11:18:37 +0000 | [diff] [blame] | 389 |     Instruction::RETURN); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 390 |  | 
 | 391 |   ArenaPool pool; | 
 | 392 |   ArenaAllocator allocator(&pool); | 
 | 393 |   HGraph* graph = BuildGraph(data, &allocator); | 
| Calin Juravle | cd6dffe | 2015-01-08 17:35:35 +0000 | [diff] [blame] | 394 |   x86::CodeGeneratorX86 codegen(graph, CompilerOptions()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 395 |   SsaLivenessAnalysis liveness(*graph, &codegen); | 
 | 396 |   liveness.Analyze(); | 
 | 397 |  | 
 | 398 |   // Test for the 0 constant. | 
 | 399 |   LiveInterval* interval = liveness.GetInstructionFromSsaIndex(0)->GetLiveInterval(); | 
 | 400 |   LiveRange* range = interval->GetFirstRange(); | 
 | 401 |   ASSERT_EQ(2u, range->GetStart()); | 
| Mark Mendell | 09b8463 | 2015-02-13 17:48:38 -0500 | [diff] [blame] | 402 |   ASSERT_EQ(17u, range->GetEnd()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 403 |   range = range->GetNext(); | 
 | 404 |   ASSERT_TRUE(range != nullptr); | 
 | 405 |   ASSERT_EQ(20u, range->GetStart()); | 
| Mark Mendell | 09b8463 | 2015-02-13 17:48:38 -0500 | [diff] [blame] | 406 |   ASSERT_EQ(23u, range->GetEnd()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 407 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 408 |  | 
 | 409 |   // Test for the 4 constant. | 
 | 410 |   interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval(); | 
 | 411 |   range = interval->GetFirstRange(); | 
 | 412 |   ASSERT_EQ(4u, range->GetStart()); | 
| Nicolas Geoffray | a3c00e5 | 2014-11-25 11:18:37 +0000 | [diff] [blame] | 413 |   ASSERT_EQ(17u, range->GetEnd()); | 
 | 414 |   range = range->GetNext(); | 
 | 415 |   ASSERT_EQ(20u, range->GetStart()); | 
 | 416 |   ASSERT_EQ(23u, range->GetEnd()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 417 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 418 |  | 
 | 419 |   // Test for the first add. | 
 | 420 |   HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd(); | 
 | 421 |   interval = add->GetLiveInterval(); | 
 | 422 |   range = interval->GetFirstRange(); | 
 | 423 |   ASSERT_EQ(16u, range->GetStart()); | 
 | 424 |   ASSERT_EQ(20u, range->GetEnd()); | 
 | 425 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 426 |  | 
 | 427 |   // Test for the second add. | 
 | 428 |   add = liveness.GetInstructionFromSsaIndex(3)->AsAdd(); | 
 | 429 |   interval = add->GetLiveInterval(); | 
 | 430 |   range = interval->GetFirstRange(); | 
 | 431 |   ASSERT_EQ(22u, range->GetStart()); | 
 | 432 |   ASSERT_EQ(26u, range->GetEnd()); | 
 | 433 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 434 |  | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 435 |   HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi(); | 
| David Brazdil | ea55b93 | 2015-01-27 17:12:29 +0000 | [diff] [blame] | 436 |   ASSERT_TRUE(phi->GetUses().HasOnlyOneUse()); | 
| Nicolas Geoffray | 8ddb00c | 2014-09-29 12:00:40 +0100 | [diff] [blame] | 437 |   interval = phi->GetLiveInterval(); | 
 | 438 |   range = interval->GetFirstRange(); | 
 | 439 |   ASSERT_EQ(26u, range->GetStart()); | 
 | 440 |   ASSERT_EQ(28u, range->GetEnd()); | 
 | 441 |   ASSERT_TRUE(range->GetNext() == nullptr); | 
 | 442 | } | 
 | 443 |  | 
| Nicolas Geoffray | ddb311f | 2014-05-16 09:28:54 +0100 | [diff] [blame] | 444 | }  // namespace art |