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 <fstream>
18 
19 #include "base/arena_allocator.h"
20 #include "builder.h"
21 #include "code_generator.h"
22 #include "dex/dex_file.h"
23 #include "dex/dex_instruction.h"
24 #include "driver/compiler_options.h"
25 #include "graph_visualizer.h"
26 #include "nodes.h"
27 #include "optimizing_unit_test.h"
28 #include "pretty_printer.h"
29 #include "ssa_liveness_analysis.h"
30 
31 namespace art {
32 
33 class LinearizeTest : public OptimizingUnitTest {
34  protected:
35   template <size_t number_of_blocks>
36   void TestCode(const std::vector<uint16_t>& data,
37                 const uint32_t (&expected_order)[number_of_blocks]);
38 };
39 
40 template <size_t number_of_blocks>
TestCode(const std::vector<uint16_t> & data,const uint32_t (& expected_order)[number_of_blocks])41 void LinearizeTest::TestCode(const std::vector<uint16_t>& data,
42                              const uint32_t (&expected_order)[number_of_blocks]) {
43   HGraph* graph = CreateCFG(data);
44   std::unique_ptr<CompilerOptions> compiler_options =
45       CommonCompilerTest::CreateCompilerOptions(kRuntimeISA, "default");
46   std::unique_ptr<CodeGenerator> codegen = CodeGenerator::Create(graph, *compiler_options);
47   SsaLivenessAnalysis liveness(graph, codegen.get(), GetScopedAllocator());
48   liveness.Analyze();
49 
50   ASSERT_EQ(graph->GetLinearOrder().size(), number_of_blocks);
51   for (size_t i = 0; i < number_of_blocks; ++i) {
52     ASSERT_EQ(graph->GetLinearOrder()[i]->GetBlockId(), expected_order[i]);
53   }
54 }
55 
TEST_F(LinearizeTest,CFG1)56 TEST_F(LinearizeTest, CFG1) {
57   // Structure of this graph (+ are back edges)
58   //            Block0
59   //              |
60   //            Block1
61   //              |
62   //            Block2 ++++++
63   //            /   \       +
64   //       Block5   Block7  +
65   //         |        |     +
66   //       Block6   Block3  +
67   //               + /   \  +
68   //           Block4   Block8
69 
70   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
71     Instruction::CONST_4 | 0 | 0,
72     Instruction::IF_EQ, 5,
73     Instruction::IF_EQ, 0xFFFE,
74     Instruction::GOTO | 0xFE00,
75     Instruction::RETURN_VOID);
76 
77   const uint32_t blocks[] = {0, 1, 2, 7, 3, 4, 8, 5, 6};
78   TestCode(data, blocks);
79 }
80 
TEST_F(LinearizeTest,CFG2)81 TEST_F(LinearizeTest, CFG2) {
82   // Structure of this graph (+ are back edges)
83   //            Block0
84   //              |
85   //            Block1
86   //              |
87   //            Block2 ++++++
88   //            /   \       +
89   //       Block3   Block7  +
90   //         |        |     +
91   //       Block6   Block4  +
92   //               + /   \  +
93   //           Block5   Block8
94 
95   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
96     Instruction::CONST_4 | 0 | 0,
97     Instruction::IF_EQ, 3,
98     Instruction::RETURN_VOID,
99     Instruction::IF_EQ, 0xFFFD,
100     Instruction::GOTO | 0xFE00);
101 
102   const uint32_t blocks[] = {0, 1, 2, 7, 4, 5, 8, 3, 6};
103   TestCode(data, blocks);
104 }
105 
TEST_F(LinearizeTest,CFG3)106 TEST_F(LinearizeTest, CFG3) {
107   // Structure of this graph (+ are back edges)
108   //            Block0
109   //              |
110   //            Block1
111   //              |
112   //            Block2 ++++++
113   //            /   \       +
114   //       Block3   Block8  +
115   //         |        |     +
116   //       Block7   Block5  +
117   //                 / +  \ +
118   //           Block6  + Block9
119   //             |     +
120   //           Block4 ++
121   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
122     Instruction::CONST_4 | 0 | 0,
123     Instruction::IF_EQ, 4,
124     Instruction::RETURN_VOID,
125     Instruction::GOTO | 0x0100,
126     Instruction::IF_EQ, 0xFFFC,
127     Instruction::GOTO | 0xFD00);
128 
129   const uint32_t blocks[] = {0, 1, 2, 8, 5, 6, 4, 9, 3, 7};
130   TestCode(data, blocks);
131 }
132 
TEST_F(LinearizeTest,CFG4)133 TEST_F(LinearizeTest, CFG4) {
134   /* Structure of this graph (+ are back edges)
135   //            Block0
136   //              |
137   //            Block1
138   //              |
139   //            Block2
140   //            / +  \
141   //       Block6 + Block8
142   //         |    +   |
143   //       Block7 + Block3 +++++++
144   //              +  /  \        +
145   //           Block9   Block10  +
146   //                      |      +
147   //                    Block4   +
148   //                  + /    \   +
149   //                Block5  Block11
150   */
151   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
152     Instruction::CONST_4 | 0 | 0,
153     Instruction::IF_EQ, 7,
154     Instruction::IF_EQ, 0xFFFE,
155     Instruction::IF_EQ, 0xFFFE,
156     Instruction::GOTO | 0xFE00,
157     Instruction::RETURN_VOID);
158 
159   const uint32_t blocks[] = {0, 1, 2, 8, 3, 10, 4, 5, 11, 9, 6, 7};
160   TestCode(data, blocks);
161 }
162 
TEST_F(LinearizeTest,CFG5)163 TEST_F(LinearizeTest, CFG5) {
164   /* Structure of this graph (+ are back edges)
165   //            Block0
166   //              |
167   //            Block1
168   //              |
169   //            Block2
170   //            / +  \
171   //       Block3 + Block8
172   //         |    +   |
173   //       Block7 + Block4 +++++++
174   //              +  /  \        +
175   //           Block9   Block10  +
176   //                      |      +
177   //                    Block5   +
178   //                   +/    \   +
179   //                Block6  Block11
180   */
181   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
182     Instruction::CONST_4 | 0 | 0,
183     Instruction::IF_EQ, 3,
184     Instruction::RETURN_VOID,
185     Instruction::IF_EQ, 0xFFFD,
186     Instruction::IF_EQ, 0xFFFE,
187     Instruction::GOTO | 0xFE00);
188 
189   const uint32_t blocks[] = {0, 1, 2, 8, 4, 10, 5, 6, 11, 9, 3, 7};
190   TestCode(data, blocks);
191 }
192 
TEST_F(LinearizeTest,CFG6)193 TEST_F(LinearizeTest, CFG6) {
194   //            Block0
195   //              |
196   //            Block1
197   //              |
198   //            Block2 ++++++++++++++
199   //              |                 +
200   //            Block3              +
201   //            /     \             +
202   //       Block8     Block4        +
203   //         |         /   \        +
204   //       Block5 <- Block9 Block6  +
205   //         |
206   //       Block7
207   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
208     Instruction::CONST_4 | 0 | 0,
209     Instruction::GOTO | 0x0100,
210     Instruction::IF_EQ, 0x0004,
211     Instruction::IF_EQ, 0x0003,
212     Instruction::RETURN_VOID,
213     Instruction::GOTO | 0xFA00);
214 
215   const uint32_t blocks[] = {0, 1, 2, 3, 4, 6, 9, 8, 5, 7};
216   TestCode(data, blocks);
217 }
218 
TEST_F(LinearizeTest,CFG7)219 TEST_F(LinearizeTest, CFG7) {
220   // Structure of this graph (+ are back edges)
221   //            Block0
222   //              |
223   //            Block1
224   //              |
225   //            Block2 ++++++++
226   //              |           +
227   //            Block3        +
228   //            /    \        +
229   //        Block4  Block8    +
230   //        /  \        |     +
231   //   Block5 Block9 - Block6 +
232   //     |
233   //   Block7
234   //
235   const std::vector<uint16_t> data = ONE_REGISTER_CODE_ITEM(
236     Instruction::CONST_4 | 0 | 0,
237     Instruction::GOTO | 0x0100,
238     Instruction::IF_EQ, 0x0005,
239     Instruction::IF_EQ, 0x0003,
240     Instruction::RETURN_VOID,
241     Instruction::GOTO | 0xFA00);
242 
243   const uint32_t blocks[] = {0, 1, 2, 3, 4, 9, 8, 6, 5, 7};
244   TestCode(data, blocks);
245 }
246 
247 }  // namespace art
248