blob: d3229e57504fe0a6ed950f83b33b0b8e988fdc50 [file] [log] [blame]
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001/*
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#ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
18#define ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
19
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080020#include <memory>
21#include <vector>
22
Vladimir Markoe2727152019-10-10 10:46:42 +010023#include "base/macros.h"
David Sehr3215fff2018-04-03 17:10:12 -070024#include "base/malloc_arena_pool.h"
Vladimir Markoca6fff82017-10-03 14:49:14 +010025#include "base/scoped_arena_allocator.h"
Roland Levillainccc07a92014-09-16 14:48:16 +010026#include "builder.h"
David Brazdil4833f5a2015-12-16 10:37:39 +000027#include "common_compiler_test.h"
David Sehr9e734c72018-01-04 17:56:19 -080028#include "dex/code_item_accessors-inl.h"
29#include "dex/dex_file.h"
30#include "dex/dex_instruction.h"
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080031#include "dex/standard_dex_file.h"
Vladimir Marko92f7f3c2017-10-31 11:38:30 +000032#include "driver/dex_compilation_unit.h"
Artem Serov15f95b12018-06-29 15:30:36 +010033#include "graph_checker.h"
Vladimir Marko69d310e2017-10-09 14:12:23 +010034#include "handle_scope-inl.h"
35#include "mirror/class_loader.h"
36#include "mirror/dex_cache.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070037#include "nodes.h"
David Brazdil4833f5a2015-12-16 10:37:39 +000038#include "scoped_thread_state_change.h"
39#include "ssa_builder.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010040#include "ssa_liveness_analysis.h"
41
Roland Levillain72bceff2014-09-15 18:29:00 +010042#include "gtest/gtest.h"
43
Vladimir Markoe2727152019-10-10 10:46:42 +010044namespace art HIDDEN {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010045
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000046#define NUM_INSTRUCTIONS(...) \
47 (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t))
48
Roland Levillain55dcfb52014-10-24 18:09:09 +010049#define N_REGISTERS_CODE_ITEM(NUM_REGS, ...) \
50 { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000051
Roland Levillain55dcfb52014-10-24 18:09:09 +010052#define ZERO_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(0, __VA_ARGS__)
53#define ONE_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(1, __VA_ARGS__)
54#define TWO_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(2, __VA_ARGS__)
55#define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__)
56#define FOUR_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(4, __VA_ARGS__)
57#define FIVE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(5, __VA_ARGS__)
58#define SIX_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(6, __VA_ARGS__)
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000059
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010060LiveInterval* BuildInterval(const size_t ranges[][2],
61 size_t number_of_ranges,
Vladimir Markoe764d2e2017-10-05 14:35:55 +010062 ScopedArenaAllocator* allocator,
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +000063 int reg = -1,
64 HInstruction* defined_by = nullptr) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010065 LiveInterval* interval =
66 LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +000067 if (defined_by != nullptr) {
68 defined_by->SetLiveInterval(interval);
69 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010070 for (size_t i = number_of_ranges; i > 0; --i) {
71 interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]);
72 }
73 interval->SetRegister(reg);
74 return interval;
75}
76
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000077void RemoveSuspendChecks(HGraph* graph) {
Vladimir Markofa6b93c2015-09-15 10:15:55 +010078 for (HBasicBlock* block : graph->GetBlocks()) {
David Brazdilbadd8262016-02-02 16:28:56 +000079 if (block != nullptr) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +010080 if (block->GetLoopInformation() != nullptr) {
81 block->GetLoopInformation()->SetSuspendCheck(nullptr);
82 }
David Brazdilbadd8262016-02-02 16:28:56 +000083 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
84 HInstruction* current = it.Current();
85 if (current->IsSuspendCheck()) {
86 current->GetBlock()->RemoveInstruction(current);
87 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000088 }
89 }
90 }
91}
92
Vladimir Markoca6fff82017-10-03 14:49:14 +010093class ArenaPoolAndAllocator {
94 public:
Vladimir Markoe764d2e2017-10-05 14:35:55 +010095 ArenaPoolAndAllocator()
96 : pool_(), allocator_(&pool_), arena_stack_(&pool_), scoped_allocator_(&arena_stack_) { }
Vladimir Markoca6fff82017-10-03 14:49:14 +010097
98 ArenaAllocator* GetAllocator() { return &allocator_; }
99 ArenaStack* GetArenaStack() { return &arena_stack_; }
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100100 ScopedArenaAllocator* GetScopedAllocator() { return &scoped_allocator_; }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100101
102 private:
David Sehr3215fff2018-04-03 17:10:12 -0700103 MallocArenaPool pool_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100104 ArenaAllocator allocator_;
105 ArenaStack arena_stack_;
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100106 ScopedArenaAllocator scoped_allocator_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100107};
108
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800109// Have a separate helper so the OptimizingCFITest can inherit it without causing
110// multiple inheritance errors from having two gtest as a parent twice.
111class OptimizingUnitTestHelper {
112 public:
113 OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
David Brazdilbadd8262016-02-02 16:28:56 +0000114
Vladimir Markoca6fff82017-10-03 14:49:14 +0100115 ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); }
116 ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); }
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100117 ScopedArenaAllocator* GetScopedAllocator() { return pool_and_allocator_->GetScopedAllocator(); }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100118
119 void ResetPoolAndAllocator() {
120 pool_and_allocator_.reset(new ArenaPoolAndAllocator());
121 handles_.reset(); // When getting rid of the old HGraph, we can also reset handles_.
David Brazdilbadd8262016-02-02 16:28:56 +0000122 }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100123
124 HGraph* CreateGraph() {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800125 ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator();
126
127 // Reserve a big array of 0s so the dex file constructor can offsets from the header.
128 static constexpr size_t kDexDataSize = 4 * KB;
129 const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize));
130
131 // Create the dex file based on the fake data. Call the constructor so that we can use virtual
132 // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks.
133 dex_files_.emplace_back(new StandardDexFile(
David Sehr0b426772018-07-03 23:03:42 +0000134 dex_data,
135 sizeof(StandardDexFile::Header),
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800136 "no_location",
137 /*location_checksum*/ 0,
David Sehr0b426772018-07-03 23:03:42 +0000138 /*oat_dex_file*/ nullptr,
139 /*container*/ nullptr));
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800140
141 return new (allocator) HGraph(
142 allocator,
143 pool_and_allocator_->GetArenaStack(),
144 *dex_files_.back(),
145 /*method_idx*/-1,
146 kRuntimeISA);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100147 }
148
149 // Create a control-flow graph from Dex instructions.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800150 HGraph* CreateCFG(const std::vector<uint16_t>& data,
151 DataType::Type return_type = DataType::Type::kInt32) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100152 HGraph* graph = CreateGraph();
153
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800154 // The code item data might not aligned to 4 bytes, copy it to ensure that.
155 const size_t code_item_size = data.size() * sizeof(data.front());
156 void* aligned_data = GetAllocator()->Alloc(code_item_size);
157 memcpy(aligned_data, &data[0], code_item_size);
158 CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800159 const dex::CodeItem* code_item = reinterpret_cast<const dex::CodeItem*>(aligned_data);
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800160
Vladimir Markoca6fff82017-10-03 14:49:14 +0100161 {
162 ScopedObjectAccess soa(Thread::Current());
163 if (handles_ == nullptr) {
164 handles_.reset(new VariableSizedHandleScope(soa.Self()));
165 }
Vladimir Marko69d310e2017-10-09 14:12:23 +0100166 const DexCompilationUnit* dex_compilation_unit =
167 new (graph->GetAllocator()) DexCompilationUnit(
168 handles_->NewHandle<mirror::ClassLoader>(nullptr),
Andreas Gampe3db70682018-12-26 15:12:03 -0800169 /* class_linker= */ nullptr,
Vladimir Marko92f7f3c2017-10-31 11:38:30 +0000170 graph->GetDexFile(),
Vladimir Marko69d310e2017-10-09 14:12:23 +0100171 code_item,
Andreas Gampe3db70682018-12-26 15:12:03 -0800172 /* class_def_index= */ DexFile::kDexNoIndex16,
173 /* method_idx= */ dex::kDexNoIndex,
174 /* access_flags= */ 0u,
175 /* verified_method= */ nullptr,
Vladimir Marko69d310e2017-10-09 14:12:23 +0100176 handles_->NewHandle<mirror::DexCache>(nullptr));
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800177 CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u);
Mathieu Chartier808c7a52017-12-15 11:19:33 -0800178 HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100179 bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
180 return graph_built ? graph : nullptr;
181 }
182 }
183
184 private:
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800185 std::vector<std::unique_ptr<const StandardDexFile>> dex_files_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100186 std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_;
187 std::unique_ptr<VariableSizedHandleScope> handles_;
188};
Roland Levillainccc07a92014-09-16 14:48:16 +0100189
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800190class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {};
191
Artem Serov15f95b12018-06-29 15:30:36 +0100192// OptimizingUnitTest with some handy functions to ease the graph creation.
193class ImprovedOptimizingUnitTest : public OptimizingUnitTest {
194 public:
195 ImprovedOptimizingUnitTest() : graph_(CreateGraph()),
196 entry_block_(nullptr),
197 return_block_(nullptr),
198 exit_block_(nullptr),
199 parameter_(nullptr) {}
200
201 virtual ~ImprovedOptimizingUnitTest() {}
202
203 void InitGraph() {
204 entry_block_ = new (GetAllocator()) HBasicBlock(graph_);
205 graph_->AddBlock(entry_block_);
206 graph_->SetEntryBlock(entry_block_);
207
208 return_block_ = new (GetAllocator()) HBasicBlock(graph_);
209 graph_->AddBlock(return_block_);
210
211 exit_block_ = new (GetAllocator()) HBasicBlock(graph_);
212 graph_->AddBlock(exit_block_);
213 graph_->SetExitBlock(exit_block_);
214
215 entry_block_->AddSuccessor(return_block_);
216 return_block_->AddSuccessor(exit_block_);
217
218 parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
219 dex::TypeIndex(0),
220 0,
221 DataType::Type::kInt32);
222 entry_block_->AddInstruction(parameter_);
223 return_block_->AddInstruction(new (GetAllocator()) HReturnVoid());
224 exit_block_->AddInstruction(new (GetAllocator()) HExit());
225 }
226
227 bool CheckGraph() {
228 GraphChecker checker(graph_);
229 checker.Run();
230 if (!checker.IsValid()) {
231 for (const std::string& error : checker.GetErrors()) {
232 std::cout << error << std::endl;
233 }
234 return false;
235 }
236 return true;
237 }
238
239 HEnvironment* ManuallyBuildEnvFor(HInstruction* instruction,
240 ArenaVector<HInstruction*>* current_locals) {
241 HEnvironment* environment = new (GetAllocator()) HEnvironment(
242 (GetAllocator()),
243 current_locals->size(),
244 graph_->GetArtMethod(),
245 instruction->GetDexPc(),
246 instruction);
247
248 environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals));
249 instruction->SetRawEnvironment(environment);
250 return environment;
251 }
252
253 protected:
254 HGraph* graph_;
255
256 HBasicBlock* entry_block_;
257 HBasicBlock* return_block_;
258 HBasicBlock* exit_block_;
259
260 HInstruction* parameter_;
261};
262
Roland Levillain72bceff2014-09-15 18:29:00 +0100263// Naive string diff data type.
264typedef std::list<std::pair<std::string, std::string>> diff_t;
265
266// An alias for the empty string used to make it clear that a line is
267// removed in a diff.
Igor Murashkin2ffb7032017-11-08 13:35:21 -0800268static const std::string removed = ""; // NOLINT [runtime/string] [4]
Roland Levillain72bceff2014-09-15 18:29:00 +0100269
270// Naive patch command: apply a diff to a string.
271inline std::string Patch(const std::string& original, const diff_t& diff) {
272 std::string result = original;
273 for (const auto& p : diff) {
274 std::string::size_type pos = result.find(p.first);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000275 DCHECK_NE(pos, std::string::npos)
276 << "Could not find: \"" << p.first << "\" in \"" << result << "\"";
Roland Levillain72bceff2014-09-15 18:29:00 +0100277 result.replace(pos, p.first.size(), p.second);
278 }
279 return result;
280}
281
Mingyao Yangf384f882014-10-22 16:08:18 -0700282// Returns if the instruction is removed from the graph.
283inline bool IsRemoved(HInstruction* instruction) {
284 return instruction->GetBlock() == nullptr;
285}
286
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100287} // namespace art
288
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000289#endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_