blob: 2c757f8535585e83b37dc3d30faa8ede7cadc0c3 [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
David Sehr3215fff2018-04-03 17:10:12 -070023#include "base/malloc_arena_pool.h"
Vladimir Markoca6fff82017-10-03 14:49:14 +010024#include "base/scoped_arena_allocator.h"
Roland Levillainccc07a92014-09-16 14:48:16 +010025#include "builder.h"
David Brazdil4833f5a2015-12-16 10:37:39 +000026#include "common_compiler_test.h"
David Sehr9e734c72018-01-04 17:56:19 -080027#include "dex/code_item_accessors-inl.h"
28#include "dex/dex_file.h"
29#include "dex/dex_instruction.h"
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -080030#include "dex/standard_dex_file.h"
Vladimir Marko92f7f3c2017-10-31 11:38:30 +000031#include "driver/dex_compilation_unit.h"
Artem Serov15f95b12018-06-29 15:30:36 +010032#include "graph_checker.h"
Vladimir Marko69d310e2017-10-09 14:12:23 +010033#include "handle_scope-inl.h"
34#include "mirror/class_loader.h"
35#include "mirror/dex_cache.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070036#include "nodes.h"
David Brazdil4833f5a2015-12-16 10:37:39 +000037#include "scoped_thread_state_change.h"
38#include "ssa_builder.h"
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010039#include "ssa_liveness_analysis.h"
40
Roland Levillain72bceff2014-09-15 18:29:00 +010041#include "gtest/gtest.h"
42
Vladimir Marko0a516052019-10-14 13:00:44 +000043namespace art {
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010044
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000045#define NUM_INSTRUCTIONS(...) \
46 (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t))
47
Roland Levillain55dcfb52014-10-24 18:09:09 +010048#define N_REGISTERS_CODE_ITEM(NUM_REGS, ...) \
49 { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000050
Roland Levillain55dcfb52014-10-24 18:09:09 +010051#define ZERO_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(0, __VA_ARGS__)
52#define ONE_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(1, __VA_ARGS__)
53#define TWO_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(2, __VA_ARGS__)
54#define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__)
55#define FOUR_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(4, __VA_ARGS__)
56#define FIVE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(5, __VA_ARGS__)
57#define SIX_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(6, __VA_ARGS__)
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000058
Christopher Ferrisfc5e2ef2020-05-08 00:08:42 +000059LiveInterval* BuildInterval(const size_t ranges[][2],
60 size_t number_of_ranges,
61 ScopedArenaAllocator* allocator,
62 int reg = -1,
63 HInstruction* defined_by = nullptr) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010064 LiveInterval* interval =
65 LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by);
Nicolas Geoffraydd8f8872015-01-15 15:37:37 +000066 if (defined_by != nullptr) {
67 defined_by->SetLiveInterval(interval);
68 }
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010069 for (size_t i = number_of_ranges; i > 0; --i) {
70 interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]);
71 }
72 interval->SetRegister(reg);
73 return interval;
74}
75
Christopher Ferrisfc5e2ef2020-05-08 00:08:42 +000076void RemoveSuspendChecks(HGraph* graph) {
Vladimir Markofa6b93c2015-09-15 10:15:55 +010077 for (HBasicBlock* block : graph->GetBlocks()) {
David Brazdilbadd8262016-02-02 16:28:56 +000078 if (block != nullptr) {
Alexandre Rames22aa54b2016-10-18 09:32:29 +010079 if (block->GetLoopInformation() != nullptr) {
80 block->GetLoopInformation()->SetSuspendCheck(nullptr);
81 }
David Brazdilbadd8262016-02-02 16:28:56 +000082 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
83 HInstruction* current = it.Current();
84 if (current->IsSuspendCheck()) {
85 current->GetBlock()->RemoveInstruction(current);
86 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +000087 }
88 }
89 }
90}
91
Vladimir Markoca6fff82017-10-03 14:49:14 +010092class ArenaPoolAndAllocator {
93 public:
Vladimir Markoe764d2e2017-10-05 14:35:55 +010094 ArenaPoolAndAllocator()
95 : pool_(), allocator_(&pool_), arena_stack_(&pool_), scoped_allocator_(&arena_stack_) { }
Vladimir Markoca6fff82017-10-03 14:49:14 +010096
97 ArenaAllocator* GetAllocator() { return &allocator_; }
98 ArenaStack* GetArenaStack() { return &arena_stack_; }
Vladimir Markoe764d2e2017-10-05 14:35:55 +010099 ScopedArenaAllocator* GetScopedAllocator() { return &scoped_allocator_; }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100100
101 private:
David Sehr3215fff2018-04-03 17:10:12 -0700102 MallocArenaPool pool_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100103 ArenaAllocator allocator_;
104 ArenaStack arena_stack_;
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100105 ScopedArenaAllocator scoped_allocator_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100106};
107
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800108// Have a separate helper so the OptimizingCFITest can inherit it without causing
109// multiple inheritance errors from having two gtest as a parent twice.
110class OptimizingUnitTestHelper {
111 public:
112 OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { }
David Brazdilbadd8262016-02-02 16:28:56 +0000113
Vladimir Markoca6fff82017-10-03 14:49:14 +0100114 ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); }
115 ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); }
Vladimir Markoe764d2e2017-10-05 14:35:55 +0100116 ScopedArenaAllocator* GetScopedAllocator() { return pool_and_allocator_->GetScopedAllocator(); }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100117
118 void ResetPoolAndAllocator() {
119 pool_and_allocator_.reset(new ArenaPoolAndAllocator());
David Brazdilbadd8262016-02-02 16:28:56 +0000120 }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100121
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100122 HGraph* CreateGraph(VariableSizedHandleScope* handles = nullptr) {
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800123 ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator();
124
125 // Reserve a big array of 0s so the dex file constructor can offsets from the header.
126 static constexpr size_t kDexDataSize = 4 * KB;
127 const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize));
128
129 // Create the dex file based on the fake data. Call the constructor so that we can use virtual
130 // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks.
131 dex_files_.emplace_back(new StandardDexFile(
David Sehr0b426772018-07-03 23:03:42 +0000132 dex_data,
133 sizeof(StandardDexFile::Header),
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800134 "no_location",
135 /*location_checksum*/ 0,
David Sehr0b426772018-07-03 23:03:42 +0000136 /*oat_dex_file*/ nullptr,
137 /*container*/ nullptr));
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800138
139 return new (allocator) HGraph(
140 allocator,
141 pool_and_allocator_->GetArenaStack(),
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100142 handles,
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800143 *dex_files_.back(),
144 /*method_idx*/-1,
145 kRuntimeISA);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100146 }
147
148 // Create a control-flow graph from Dex instructions.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800149 HGraph* CreateCFG(const std::vector<uint16_t>& data,
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100150 DataType::Type return_type = DataType::Type::kInt32,
151 VariableSizedHandleScope* handles = nullptr) {
152 HGraph* graph = CreateGraph(handles);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100153
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 {
Vladimir Marko69d310e2017-10-09 14:12:23 +0100162 const DexCompilationUnit* dex_compilation_unit =
163 new (graph->GetAllocator()) DexCompilationUnit(
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100164 /* class_loader= */ Handle<mirror::ClassLoader>(), // Invalid handle.
Andreas Gampe3db70682018-12-26 15:12:03 -0800165 /* class_linker= */ nullptr,
Vladimir Marko92f7f3c2017-10-31 11:38:30 +0000166 graph->GetDexFile(),
Vladimir Marko69d310e2017-10-09 14:12:23 +0100167 code_item,
Andreas Gampe3db70682018-12-26 15:12:03 -0800168 /* class_def_index= */ DexFile::kDexNoIndex16,
169 /* method_idx= */ dex::kDexNoIndex,
170 /* access_flags= */ 0u,
171 /* verified_method= */ nullptr,
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100172 /* dex_cache= */ Handle<mirror::DexCache>()); // Invalid handle.
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800173 CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u);
Vladimir Marko02ca05a2020-05-12 13:58:51 +0100174 HGraphBuilder builder(graph, dex_compilation_unit, accessor, return_type);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100175 bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
176 return graph_built ? graph : nullptr;
177 }
178 }
179
Evgeny Astigeevich7ee34a12019-12-10 11:36:33 +0000180 // Run GraphChecker with all checks.
181 //
182 // Return: the status whether the run is successful.
183 bool CheckGraph(HGraph* graph) {
184 return CheckGraph(graph, /*check_ref_type_info=*/true);
185 }
186
187 // Run GraphChecker with all checks except reference type information checks.
188 //
189 // Return: the status whether the run is successful.
190 bool CheckGraphSkipRefTypeInfoChecks(HGraph* graph) {
191 return CheckGraph(graph, /*check_ref_type_info=*/false);
192 }
193
Vladimir Markoca6fff82017-10-03 14:49:14 +0100194 private:
Evgeny Astigeevich7ee34a12019-12-10 11:36:33 +0000195 bool CheckGraph(HGraph* graph, bool check_ref_type_info) {
196 GraphChecker checker(graph);
197 checker.SetRefTypeInfoCheckEnabled(check_ref_type_info);
198 checker.Run();
199 checker.Dump(std::cerr);
200 return checker.IsValid();
201 }
202
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800203 std::vector<std::unique_ptr<const StandardDexFile>> dex_files_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100204 std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100205};
Roland Levillainccc07a92014-09-16 14:48:16 +0100206
Mathieu Chartierfa3db3d2018-01-12 14:42:18 -0800207class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {};
208
Artem Serov15f95b12018-06-29 15:30:36 +0100209// OptimizingUnitTest with some handy functions to ease the graph creation.
210class ImprovedOptimizingUnitTest : public OptimizingUnitTest {
211 public:
212 ImprovedOptimizingUnitTest() : graph_(CreateGraph()),
213 entry_block_(nullptr),
214 return_block_(nullptr),
Evgeny Astigeevich52506e22019-12-04 15:59:37 +0000215 exit_block_(nullptr) {}
Artem Serov15f95b12018-06-29 15:30:36 +0100216
217 virtual ~ImprovedOptimizingUnitTest() {}
218
219 void InitGraph() {
220 entry_block_ = new (GetAllocator()) HBasicBlock(graph_);
221 graph_->AddBlock(entry_block_);
222 graph_->SetEntryBlock(entry_block_);
223
224 return_block_ = new (GetAllocator()) HBasicBlock(graph_);
225 graph_->AddBlock(return_block_);
226
227 exit_block_ = new (GetAllocator()) HBasicBlock(graph_);
228 graph_->AddBlock(exit_block_);
229 graph_->SetExitBlock(exit_block_);
230
231 entry_block_->AddSuccessor(return_block_);
232 return_block_->AddSuccessor(exit_block_);
233
Evgeny Astigeevich52506e22019-12-04 15:59:37 +0000234 CreateParameters();
235 for (HInstruction* parameter : parameters_) {
236 entry_block_->AddInstruction(parameter);
237 }
238
Artem Serov15f95b12018-06-29 15:30:36 +0100239 return_block_->AddInstruction(new (GetAllocator()) HReturnVoid());
240 exit_block_->AddInstruction(new (GetAllocator()) HExit());
241 }
242
243 bool CheckGraph() {
Evgeny Astigeevich7ee34a12019-12-10 11:36:33 +0000244 return OptimizingUnitTestHelper::CheckGraph(graph_);
245 }
246
247 bool CheckGraphSkipRefTypeInfoChecks() {
248 return OptimizingUnitTestHelper::CheckGraphSkipRefTypeInfoChecks(graph_);
Artem Serov15f95b12018-06-29 15:30:36 +0100249 }
250
251 HEnvironment* ManuallyBuildEnvFor(HInstruction* instruction,
252 ArenaVector<HInstruction*>* current_locals) {
253 HEnvironment* environment = new (GetAllocator()) HEnvironment(
254 (GetAllocator()),
255 current_locals->size(),
256 graph_->GetArtMethod(),
257 instruction->GetDexPc(),
258 instruction);
259
260 environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals));
261 instruction->SetRawEnvironment(environment);
262 return environment;
263 }
264
265 protected:
Evgeny Astigeevich52506e22019-12-04 15:59:37 +0000266 // Create parameters to be added to the graph entry block.
267 // Subclasses can override it to create parameters they need.
268 virtual void CreateParameters() { /* do nothing */ }
269
Artem Serov15f95b12018-06-29 15:30:36 +0100270 HGraph* graph_;
271
272 HBasicBlock* entry_block_;
273 HBasicBlock* return_block_;
274 HBasicBlock* exit_block_;
275
Evgeny Astigeevich52506e22019-12-04 15:59:37 +0000276 std::vector<HInstruction*> parameters_;
Artem Serov15f95b12018-06-29 15:30:36 +0100277};
278
Roland Levillain72bceff2014-09-15 18:29:00 +0100279// Naive string diff data type.
280typedef std::list<std::pair<std::string, std::string>> diff_t;
281
282// An alias for the empty string used to make it clear that a line is
283// removed in a diff.
Igor Murashkin2ffb7032017-11-08 13:35:21 -0800284static const std::string removed = ""; // NOLINT [runtime/string] [4]
Roland Levillain72bceff2014-09-15 18:29:00 +0100285
286// Naive patch command: apply a diff to a string.
287inline std::string Patch(const std::string& original, const diff_t& diff) {
288 std::string result = original;
289 for (const auto& p : diff) {
290 std::string::size_type pos = result.find(p.first);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000291 DCHECK_NE(pos, std::string::npos)
292 << "Could not find: \"" << p.first << "\" in \"" << result << "\"";
Roland Levillain72bceff2014-09-15 18:29:00 +0100293 result.replace(pos, p.first.size(), p.second);
294 }
295 return result;
296}
297
Mingyao Yangf384f882014-10-22 16:08:18 -0700298// Returns if the instruction is removed from the graph.
299inline bool IsRemoved(HInstruction* instruction) {
300 return instruction->GetBlock() == nullptr;
301}
302
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100303} // namespace art
304
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000305#endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_