1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Worker #include <memory>
21*795d594fSAndroid Build Coastguard Worker #include <ostream>
22*795d594fSAndroid Build Coastguard Worker #include <string_view>
23*795d594fSAndroid Build Coastguard Worker #include <string>
24*795d594fSAndroid Build Coastguard Worker #include <tuple>
25*795d594fSAndroid Build Coastguard Worker #include <vector>
26*795d594fSAndroid Build Coastguard Worker #include <variant>
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/indenter.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/malloc_arena_pool.h"
31*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
32*795d594fSAndroid Build Coastguard Worker #include "builder.h"
33*795d594fSAndroid Build Coastguard Worker #include "common_compiler_test.h"
34*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
35*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
36*795d594fSAndroid Build Coastguard Worker #include "dex/dex_instruction.h"
37*795d594fSAndroid Build Coastguard Worker #include "dex/standard_dex_file.h"
38*795d594fSAndroid Build Coastguard Worker #include "driver/dex_compilation_unit.h"
39*795d594fSAndroid Build Coastguard Worker #include "graph_checker.h"
40*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
41*795d594fSAndroid Build Coastguard Worker #include "handle_scope-inl.h"
42*795d594fSAndroid Build Coastguard Worker #include "handle_scope.h"
43*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
44*795d594fSAndroid Build Coastguard Worker #include "mirror/dex_cache.h"
45*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
46*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change.h"
47*795d594fSAndroid Build Coastguard Worker #include "ssa_builder.h"
48*795d594fSAndroid Build Coastguard Worker #include "ssa_liveness_analysis.h"
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker #define NUM_INSTRUCTIONS(...) \
53*795d594fSAndroid Build Coastguard Worker (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t))
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker #define N_REGISTERS_CODE_ITEM(NUM_REGS, ...) \
56*795d594fSAndroid Build Coastguard Worker { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ }
57*795d594fSAndroid Build Coastguard Worker
58*795d594fSAndroid Build Coastguard Worker #define ZERO_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(0, __VA_ARGS__)
59*795d594fSAndroid Build Coastguard Worker #define ONE_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(1, __VA_ARGS__)
60*795d594fSAndroid Build Coastguard Worker #define TWO_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(2, __VA_ARGS__)
61*795d594fSAndroid Build Coastguard Worker #define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__)
62*795d594fSAndroid Build Coastguard Worker #define FOUR_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(4, __VA_ARGS__)
63*795d594fSAndroid Build Coastguard Worker #define FIVE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(5, __VA_ARGS__)
64*795d594fSAndroid Build Coastguard Worker #define SIX_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(6, __VA_ARGS__)
65*795d594fSAndroid Build Coastguard Worker
66*795d594fSAndroid Build Coastguard Worker struct InstructionDumper {
67*795d594fSAndroid Build Coastguard Worker public:
68*795d594fSAndroid Build Coastguard Worker HInstruction* ins_;
69*795d594fSAndroid Build Coastguard Worker };
70*795d594fSAndroid Build Coastguard Worker
71*795d594fSAndroid Build Coastguard Worker inline bool operator==(const InstructionDumper& a, const InstructionDumper& b) {
72*795d594fSAndroid Build Coastguard Worker return a.ins_ == b.ins_;
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker inline bool operator!=(const InstructionDumper& a, const InstructionDumper& b) {
75*795d594fSAndroid Build Coastguard Worker return !(a == b);
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker
78*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& os, const InstructionDumper& id) {
79*795d594fSAndroid Build Coastguard Worker if (id.ins_ == nullptr) {
80*795d594fSAndroid Build Coastguard Worker return os << "NULL";
81*795d594fSAndroid Build Coastguard Worker } else {
82*795d594fSAndroid Build Coastguard Worker return os << "(" << id.ins_ << "): " << id.ins_->DumpWithArgs();
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker }
85*795d594fSAndroid Build Coastguard Worker
86*795d594fSAndroid Build Coastguard Worker #define EXPECT_INS_EQ(a, b) EXPECT_EQ(InstructionDumper{a}, InstructionDumper{b})
87*795d594fSAndroid Build Coastguard Worker #define EXPECT_INS_REMOVED(a) EXPECT_TRUE(IsRemoved(a)) << "Not removed: " << (InstructionDumper{a})
88*795d594fSAndroid Build Coastguard Worker #define EXPECT_INS_RETAINED(a) EXPECT_FALSE(IsRemoved(a)) << "Removed: " << (InstructionDumper{a})
89*795d594fSAndroid Build Coastguard Worker #define ASSERT_INS_EQ(a, b) ASSERT_EQ(InstructionDumper{a}, InstructionDumper{b})
90*795d594fSAndroid Build Coastguard Worker #define ASSERT_INS_REMOVED(a) ASSERT_TRUE(IsRemoved(a)) << "Not removed: " << (InstructionDumper{a})
91*795d594fSAndroid Build Coastguard Worker #define ASSERT_INS_RETAINED(a) ASSERT_FALSE(IsRemoved(a)) << "Removed: " << (InstructionDumper{a})
92*795d594fSAndroid Build Coastguard Worker
93*795d594fSAndroid Build Coastguard Worker inline LiveInterval* BuildInterval(const size_t ranges[][2],
94*795d594fSAndroid Build Coastguard Worker size_t number_of_ranges,
95*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator* allocator,
96*795d594fSAndroid Build Coastguard Worker int reg = -1,
97*795d594fSAndroid Build Coastguard Worker HInstruction* defined_by = nullptr) {
98*795d594fSAndroid Build Coastguard Worker LiveInterval* interval =
99*795d594fSAndroid Build Coastguard Worker LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by);
100*795d594fSAndroid Build Coastguard Worker if (defined_by != nullptr) {
101*795d594fSAndroid Build Coastguard Worker defined_by->SetLiveInterval(interval);
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker for (size_t i = number_of_ranges; i > 0; --i) {
104*795d594fSAndroid Build Coastguard Worker interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]);
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker interval->SetRegister(reg);
107*795d594fSAndroid Build Coastguard Worker return interval;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker
RemoveSuspendChecks(HGraph * graph)110*795d594fSAndroid Build Coastguard Worker inline void RemoveSuspendChecks(HGraph* graph) {
111*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph->GetBlocks()) {
112*795d594fSAndroid Build Coastguard Worker if (block != nullptr) {
113*795d594fSAndroid Build Coastguard Worker if (block->GetLoopInformation() != nullptr) {
114*795d594fSAndroid Build Coastguard Worker block->GetLoopInformation()->SetSuspendCheck(nullptr);
115*795d594fSAndroid Build Coastguard Worker }
116*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
117*795d594fSAndroid Build Coastguard Worker HInstruction* current = it.Current();
118*795d594fSAndroid Build Coastguard Worker if (current->IsSuspendCheck()) {
119*795d594fSAndroid Build Coastguard Worker current->GetBlock()->RemoveInstruction(current);
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker
126*795d594fSAndroid Build Coastguard Worker class ArenaPoolAndAllocator {
127*795d594fSAndroid Build Coastguard Worker public:
ArenaPoolAndAllocator()128*795d594fSAndroid Build Coastguard Worker ArenaPoolAndAllocator()
129*795d594fSAndroid Build Coastguard Worker : pool_(), allocator_(&pool_), arena_stack_(&pool_), scoped_allocator_(&arena_stack_) { }
130*795d594fSAndroid Build Coastguard Worker
GetAllocator()131*795d594fSAndroid Build Coastguard Worker ArenaAllocator* GetAllocator() { return &allocator_; }
GetArenaStack()132*795d594fSAndroid Build Coastguard Worker ArenaStack* GetArenaStack() { return &arena_stack_; }
GetScopedAllocator()133*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator* GetScopedAllocator() { return &scoped_allocator_; }
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker private:
136*795d594fSAndroid Build Coastguard Worker MallocArenaPool pool_;
137*795d594fSAndroid Build Coastguard Worker ArenaAllocator allocator_;
138*795d594fSAndroid Build Coastguard Worker ArenaStack arena_stack_;
139*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator scoped_allocator_;
140*795d594fSAndroid Build Coastguard Worker };
141*795d594fSAndroid Build Coastguard Worker
142*795d594fSAndroid Build Coastguard Worker class AdjacencyListGraph {
143*795d594fSAndroid Build Coastguard Worker public:
144*795d594fSAndroid Build Coastguard Worker using Edge = std::pair<const std::string_view, const std::string_view>;
AdjacencyListGraph(HGraph * graph,ArenaAllocator * alloc,const std::string_view entry_name,const std::string_view exit_name,const std::vector<Edge> & adj)145*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph(
146*795d594fSAndroid Build Coastguard Worker HGraph* graph,
147*795d594fSAndroid Build Coastguard Worker ArenaAllocator* alloc,
148*795d594fSAndroid Build Coastguard Worker const std::string_view entry_name,
149*795d594fSAndroid Build Coastguard Worker const std::string_view exit_name,
150*795d594fSAndroid Build Coastguard Worker const std::vector<Edge>& adj) : graph_(graph) {
151*795d594fSAndroid Build Coastguard Worker auto create_block = [&]() {
152*795d594fSAndroid Build Coastguard Worker HBasicBlock* blk = new (alloc) HBasicBlock(graph_);
153*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(blk);
154*795d594fSAndroid Build Coastguard Worker return blk;
155*795d594fSAndroid Build Coastguard Worker };
156*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = create_block();
157*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit = create_block();
158*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry);
159*795d594fSAndroid Build Coastguard Worker graph_->SetExitBlock(exit);
160*795d594fSAndroid Build Coastguard Worker name_to_block_.Put(entry_name, entry);
161*795d594fSAndroid Build Coastguard Worker name_to_block_.Put(exit_name, exit);
162*795d594fSAndroid Build Coastguard Worker for (const auto& [src, dest] : adj) {
163*795d594fSAndroid Build Coastguard Worker HBasicBlock* src_blk = name_to_block_.GetOrCreate(src, create_block);
164*795d594fSAndroid Build Coastguard Worker HBasicBlock* dest_blk = name_to_block_.GetOrCreate(dest, create_block);
165*795d594fSAndroid Build Coastguard Worker src_blk->AddSuccessor(dest_blk);
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker graph_->ComputeDominanceInformation();
168*795d594fSAndroid Build Coastguard Worker for (auto [name, blk] : name_to_block_) {
169*795d594fSAndroid Build Coastguard Worker block_to_name_.Put(blk, name);
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker }
172*795d594fSAndroid Build Coastguard Worker
HasBlock(const HBasicBlock * blk)173*795d594fSAndroid Build Coastguard Worker bool HasBlock(const HBasicBlock* blk) const {
174*795d594fSAndroid Build Coastguard Worker return block_to_name_.find(blk) != block_to_name_.end();
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker
GetName(const HBasicBlock * blk)177*795d594fSAndroid Build Coastguard Worker std::string_view GetName(const HBasicBlock* blk) const {
178*795d594fSAndroid Build Coastguard Worker return block_to_name_.Get(blk);
179*795d594fSAndroid Build Coastguard Worker }
180*795d594fSAndroid Build Coastguard Worker
Get(const std::string_view & sv)181*795d594fSAndroid Build Coastguard Worker HBasicBlock* Get(const std::string_view& sv) const {
182*795d594fSAndroid Build Coastguard Worker return name_to_block_.Get(sv);
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph(AdjacencyListGraph&&) = default;
186*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph(const AdjacencyListGraph&) = default;
187*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph& operator=(AdjacencyListGraph&&) = default;
188*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph& operator=(const AdjacencyListGraph&) = default;
189*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os)190*795d594fSAndroid Build Coastguard Worker std::ostream& Dump(std::ostream& os) const {
191*795d594fSAndroid Build Coastguard Worker struct Namer : public BlockNamer {
192*795d594fSAndroid Build Coastguard Worker public:
193*795d594fSAndroid Build Coastguard Worker explicit Namer(const AdjacencyListGraph& alg) : BlockNamer(), alg_(alg) {}
194*795d594fSAndroid Build Coastguard Worker std::ostream& PrintName(std::ostream& os, HBasicBlock* blk) const override {
195*795d594fSAndroid Build Coastguard Worker if (alg_.HasBlock(blk)) {
196*795d594fSAndroid Build Coastguard Worker return os << alg_.GetName(blk) << " (" << blk->GetBlockId() << ")";
197*795d594fSAndroid Build Coastguard Worker } else {
198*795d594fSAndroid Build Coastguard Worker return os << "<Unnamed B" << blk->GetBlockId() << ">";
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker }
201*795d594fSAndroid Build Coastguard Worker
202*795d594fSAndroid Build Coastguard Worker const AdjacencyListGraph& alg_;
203*795d594fSAndroid Build Coastguard Worker };
204*795d594fSAndroid Build Coastguard Worker Namer namer(*this);
205*795d594fSAndroid Build Coastguard Worker return graph_->Dump(os, /* codegen_= */ nullptr, namer);
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker
208*795d594fSAndroid Build Coastguard Worker private:
209*795d594fSAndroid Build Coastguard Worker HGraph* graph_;
210*795d594fSAndroid Build Coastguard Worker SafeMap<const std::string_view, HBasicBlock*> name_to_block_;
211*795d594fSAndroid Build Coastguard Worker SafeMap<const HBasicBlock*, const std::string_view> block_to_name_;
212*795d594fSAndroid Build Coastguard Worker };
213*795d594fSAndroid Build Coastguard Worker
214*795d594fSAndroid Build Coastguard Worker // Have a separate helper so the OptimizingCFITest can inherit it without causing
215*795d594fSAndroid Build Coastguard Worker // multiple inheritance errors from having two gtest as a parent twice.
216*795d594fSAndroid Build Coastguard Worker class OptimizingUnitTestHelper {
217*795d594fSAndroid Build Coastguard Worker public:
OptimizingUnitTestHelper()218*795d594fSAndroid Build Coastguard Worker OptimizingUnitTestHelper()
219*795d594fSAndroid Build Coastguard Worker : pool_and_allocator_(new ArenaPoolAndAllocator()),
220*795d594fSAndroid Build Coastguard Worker graph_(nullptr),
221*795d594fSAndroid Build Coastguard Worker entry_block_(nullptr),
222*795d594fSAndroid Build Coastguard Worker exit_block_(nullptr) { }
223*795d594fSAndroid Build Coastguard Worker
GetAllocator()224*795d594fSAndroid Build Coastguard Worker ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); }
GetArenaStack()225*795d594fSAndroid Build Coastguard Worker ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); }
GetScopedAllocator()226*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator* GetScopedAllocator() { return pool_and_allocator_->GetScopedAllocator(); }
227*795d594fSAndroid Build Coastguard Worker
ResetPoolAndAllocator()228*795d594fSAndroid Build Coastguard Worker void ResetPoolAndAllocator() {
229*795d594fSAndroid Build Coastguard Worker pool_and_allocator_.reset(new ArenaPoolAndAllocator());
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker HGraph* CreateGraph(VariableSizedHandleScope* handles = nullptr) {
233*795d594fSAndroid Build Coastguard Worker ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator();
234*795d594fSAndroid Build Coastguard Worker
235*795d594fSAndroid Build Coastguard Worker // Reserve a big array of 0s so the dex file constructor can offsets from the header.
236*795d594fSAndroid Build Coastguard Worker static constexpr size_t kDexDataSize = 4 * KB;
237*795d594fSAndroid Build Coastguard Worker const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize));
238*795d594fSAndroid Build Coastguard Worker
239*795d594fSAndroid Build Coastguard Worker // Create the dex file based on the fake data. Call the constructor so that we can use virtual
240*795d594fSAndroid Build Coastguard Worker // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks.
241*795d594fSAndroid Build Coastguard Worker auto container =
242*795d594fSAndroid Build Coastguard Worker std::make_shared<MemoryDexFileContainer>(dex_data, sizeof(StandardDexFile::Header));
243*795d594fSAndroid Build Coastguard Worker dex_files_.emplace_back(new StandardDexFile(dex_data,
244*795d594fSAndroid Build Coastguard Worker "no_location",
245*795d594fSAndroid Build Coastguard Worker /*location_checksum*/ 0,
246*795d594fSAndroid Build Coastguard Worker /*oat_dex_file*/ nullptr,
247*795d594fSAndroid Build Coastguard Worker std::move(container)));
248*795d594fSAndroid Build Coastguard Worker
249*795d594fSAndroid Build Coastguard Worker graph_ = new (allocator) HGraph(
250*795d594fSAndroid Build Coastguard Worker allocator,
251*795d594fSAndroid Build Coastguard Worker pool_and_allocator_->GetArenaStack(),
252*795d594fSAndroid Build Coastguard Worker handles,
253*795d594fSAndroid Build Coastguard Worker *dex_files_.back(),
254*795d594fSAndroid Build Coastguard Worker /*method_idx*/-1,
255*795d594fSAndroid Build Coastguard Worker kRuntimeISA);
256*795d594fSAndroid Build Coastguard Worker return graph_;
257*795d594fSAndroid Build Coastguard Worker }
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker // Create a control-flow graph from Dex instructions.
260*795d594fSAndroid Build Coastguard Worker HGraph* CreateCFG(const std::vector<uint16_t>& data,
261*795d594fSAndroid Build Coastguard Worker DataType::Type return_type = DataType::Type::kInt32) {
262*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
263*795d594fSAndroid Build Coastguard Worker VariableSizedHandleScope handles(soa.Self());
264*795d594fSAndroid Build Coastguard Worker HGraph* graph = CreateGraph(&handles);
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker // The code item data might not aligned to 4 bytes, copy it to ensure that.
267*795d594fSAndroid Build Coastguard Worker const size_t code_item_size = data.size() * sizeof(data.front());
268*795d594fSAndroid Build Coastguard Worker void* aligned_data = GetAllocator()->Alloc(code_item_size);
269*795d594fSAndroid Build Coastguard Worker memcpy(aligned_data, &data[0], code_item_size);
270*795d594fSAndroid Build Coastguard Worker CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment);
271*795d594fSAndroid Build Coastguard Worker const dex::CodeItem* code_item = reinterpret_cast<const dex::CodeItem*>(aligned_data);
272*795d594fSAndroid Build Coastguard Worker
273*795d594fSAndroid Build Coastguard Worker {
274*795d594fSAndroid Build Coastguard Worker const DexCompilationUnit* dex_compilation_unit =
275*795d594fSAndroid Build Coastguard Worker new (graph->GetAllocator()) DexCompilationUnit(
276*795d594fSAndroid Build Coastguard Worker /* class_loader= */ Handle<mirror::ClassLoader>(), // Invalid handle.
277*795d594fSAndroid Build Coastguard Worker /* class_linker= */ nullptr,
278*795d594fSAndroid Build Coastguard Worker graph->GetDexFile(),
279*795d594fSAndroid Build Coastguard Worker code_item,
280*795d594fSAndroid Build Coastguard Worker /* class_def_idx= */ DexFile::kDexNoIndex16,
281*795d594fSAndroid Build Coastguard Worker /* method_idx= */ dex::kDexNoIndex,
282*795d594fSAndroid Build Coastguard Worker /* access_flags= */ 0u,
283*795d594fSAndroid Build Coastguard Worker /* verified_method= */ nullptr,
284*795d594fSAndroid Build Coastguard Worker /* dex_cache= */ Handle<mirror::DexCache>()); // Invalid handle.
285*795d594fSAndroid Build Coastguard Worker CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u);
286*795d594fSAndroid Build Coastguard Worker HGraphBuilder builder(graph, dex_compilation_unit, accessor, return_type);
287*795d594fSAndroid Build Coastguard Worker bool graph_built = (builder.BuildGraph() == kAnalysisSuccess);
288*795d594fSAndroid Build Coastguard Worker return graph_built ? graph : nullptr;
289*795d594fSAndroid Build Coastguard Worker }
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker
292*795d594fSAndroid Build Coastguard Worker // Create simple graph with "entry", "main" and "exit" blocks, return the "main" block.
293*795d594fSAndroid Build Coastguard Worker // Adds `HGoto` to the "entry" block and `HExit` to the "exit block. Leaves "main" block empty.
294*795d594fSAndroid Build Coastguard Worker HBasicBlock* InitEntryMainExitGraph(VariableSizedHandleScope* handles = nullptr) {
295*795d594fSAndroid Build Coastguard Worker CreateGraph(handles);
296*795d594fSAndroid Build Coastguard Worker entry_block_ = AddNewBlock();
297*795d594fSAndroid Build Coastguard Worker HBasicBlock* main_block = AddNewBlock();
298*795d594fSAndroid Build Coastguard Worker exit_block_ = AddNewBlock();
299*795d594fSAndroid Build Coastguard Worker
300*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry_block_);
301*795d594fSAndroid Build Coastguard Worker graph_->SetExitBlock(exit_block_);
302*795d594fSAndroid Build Coastguard Worker
303*795d594fSAndroid Build Coastguard Worker entry_block_->AddSuccessor(main_block);
304*795d594fSAndroid Build Coastguard Worker main_block->AddSuccessor(exit_block_);
305*795d594fSAndroid Build Coastguard Worker
306*795d594fSAndroid Build Coastguard Worker MakeGoto(entry_block_);
307*795d594fSAndroid Build Coastguard Worker MakeExit(exit_block_);
308*795d594fSAndroid Build Coastguard Worker
309*795d594fSAndroid Build Coastguard Worker return main_block;
310*795d594fSAndroid Build Coastguard Worker }
311*795d594fSAndroid Build Coastguard Worker
312*795d594fSAndroid Build Coastguard Worker // Creates a graph identical to `InitEntryMainExitGraph()` and adds `HReturnVoid`.
313*795d594fSAndroid Build Coastguard Worker HBasicBlock* InitEntryMainExitGraphWithReturnVoid(VariableSizedHandleScope* handles = nullptr) {
314*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraph(handles);
315*795d594fSAndroid Build Coastguard Worker MakeReturnVoid(return_block);
316*795d594fSAndroid Build Coastguard Worker return return_block;
317*795d594fSAndroid Build Coastguard Worker }
318*795d594fSAndroid Build Coastguard Worker
319*795d594fSAndroid Build Coastguard Worker // Insert "if_block", "then_block" and "else_block" before a given `merge_block`. Return the
320*795d594fSAndroid Build Coastguard Worker // new blocks. Adds `HGoto` to "then_block" and "else_block". Adds `HIf` to the "if_block"
321*795d594fSAndroid Build Coastguard Worker // if the caller provides a `condition`.
322*795d594fSAndroid Build Coastguard Worker std::tuple<HBasicBlock*, HBasicBlock*, HBasicBlock*> CreateDiamondPattern(
323*795d594fSAndroid Build Coastguard Worker HBasicBlock* merge_block, HInstruction* condition = nullptr) {
324*795d594fSAndroid Build Coastguard Worker HBasicBlock* if_block = AddNewBlock();
325*795d594fSAndroid Build Coastguard Worker HBasicBlock* then_block = AddNewBlock();
326*795d594fSAndroid Build Coastguard Worker HBasicBlock* else_block = AddNewBlock();
327*795d594fSAndroid Build Coastguard Worker
328*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = merge_block->GetSinglePredecessor();
329*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(merge_block, if_block);
330*795d594fSAndroid Build Coastguard Worker
331*795d594fSAndroid Build Coastguard Worker if_block->AddSuccessor(then_block);
332*795d594fSAndroid Build Coastguard Worker if_block->AddSuccessor(else_block);
333*795d594fSAndroid Build Coastguard Worker then_block->AddSuccessor(merge_block);
334*795d594fSAndroid Build Coastguard Worker else_block->AddSuccessor(merge_block);
335*795d594fSAndroid Build Coastguard Worker
336*795d594fSAndroid Build Coastguard Worker if (condition != nullptr) {
337*795d594fSAndroid Build Coastguard Worker MakeIf(if_block, condition);
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker MakeGoto(then_block);
340*795d594fSAndroid Build Coastguard Worker MakeGoto(else_block);
341*795d594fSAndroid Build Coastguard Worker
342*795d594fSAndroid Build Coastguard Worker return {if_block, then_block, else_block};
343*795d594fSAndroid Build Coastguard Worker }
344*795d594fSAndroid Build Coastguard Worker
345*795d594fSAndroid Build Coastguard Worker // Insert "pre-header", "loop-header" and "loop-body" blocks before a given `loop_exit` block
346*795d594fSAndroid Build Coastguard Worker // and connect them in a `while (...) { ... }` loop pattern. Return the new blocks.
347*795d594fSAndroid Build Coastguard Worker // Adds `HGoto` to the "pre-header" and "loop-body" blocks but leaves the "loop-header" block
348*795d594fSAndroid Build Coastguard Worker // empty, leaving the construction of an appropriate condition and `HIf` to the caller.
349*795d594fSAndroid Build Coastguard Worker // Note: The `loop_exit` shall be the "then" successor of the "loop-header". If the `loop_exit`
350*795d594fSAndroid Build Coastguard Worker // is needed as the "else" successor, use `HBlock::SwapSuccessors()` to adjust the order.
CreateWhileLoop(HBasicBlock * loop_exit)351*795d594fSAndroid Build Coastguard Worker std::tuple<HBasicBlock*, HBasicBlock*, HBasicBlock*> CreateWhileLoop(HBasicBlock* loop_exit) {
352*795d594fSAndroid Build Coastguard Worker HBasicBlock* pre_header = AddNewBlock();
353*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header = AddNewBlock();
354*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_body = AddNewBlock();
355*795d594fSAndroid Build Coastguard Worker
356*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = loop_exit->GetSinglePredecessor();
357*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(loop_exit, pre_header);
358*795d594fSAndroid Build Coastguard Worker
359*795d594fSAndroid Build Coastguard Worker pre_header->AddSuccessor(loop_header);
360*795d594fSAndroid Build Coastguard Worker loop_header->AddSuccessor(loop_exit); // true successor
361*795d594fSAndroid Build Coastguard Worker loop_header->AddSuccessor(loop_body); // false successor
362*795d594fSAndroid Build Coastguard Worker loop_body->AddSuccessor(loop_header);
363*795d594fSAndroid Build Coastguard Worker
364*795d594fSAndroid Build Coastguard Worker MakeGoto(pre_header);
365*795d594fSAndroid Build Coastguard Worker MakeGoto(loop_body);
366*795d594fSAndroid Build Coastguard Worker
367*795d594fSAndroid Build Coastguard Worker return {pre_header, loop_header, loop_body};
368*795d594fSAndroid Build Coastguard Worker }
369*795d594fSAndroid Build Coastguard Worker
370*795d594fSAndroid Build Coastguard Worker // Insert "pre-header" and "loop" blocks before a given `loop_exit` block and connect them in a
371*795d594fSAndroid Build Coastguard Worker // `do { ... } while (...);` loop pattern. Return the new blocks. Adds `HGoto` to the "pre-header"
372*795d594fSAndroid Build Coastguard Worker // block but leaves the "loop" block empty, leaving the construction of an appropriate condition
373*795d594fSAndroid Build Coastguard Worker // and `HIf` to the caller.
374*795d594fSAndroid Build Coastguard Worker // Note: The `loop_exit` shall be the "then" successor of the "loop". If the `loop_exit`
375*795d594fSAndroid Build Coastguard Worker // is needed as the "else" successor, use `HBlock::SwapSuccessors()` to adjust the order.
CreateDoWhileLoop(HBasicBlock * loop_exit)376*795d594fSAndroid Build Coastguard Worker std::tuple<HBasicBlock*, HBasicBlock*> CreateDoWhileLoop(HBasicBlock* loop_exit) {
377*795d594fSAndroid Build Coastguard Worker HBasicBlock* pre_header = AddNewBlock();
378*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop = AddNewBlock();
379*795d594fSAndroid Build Coastguard Worker
380*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = loop_exit->GetSinglePredecessor();
381*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(loop_exit, pre_header);
382*795d594fSAndroid Build Coastguard Worker
383*795d594fSAndroid Build Coastguard Worker pre_header->AddSuccessor(loop);
384*795d594fSAndroid Build Coastguard Worker loop->AddSuccessor(loop_exit); // true successor
385*795d594fSAndroid Build Coastguard Worker loop->AddSuccessor(loop); // false successor
386*795d594fSAndroid Build Coastguard Worker
387*795d594fSAndroid Build Coastguard Worker MakeGoto(pre_header);
388*795d594fSAndroid Build Coastguard Worker
389*795d594fSAndroid Build Coastguard Worker return {pre_header, loop};
390*795d594fSAndroid Build Coastguard Worker }
391*795d594fSAndroid Build Coastguard Worker
AddNewBlock()392*795d594fSAndroid Build Coastguard Worker HBasicBlock* AddNewBlock() {
393*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
394*795d594fSAndroid Build Coastguard Worker graph_->AddBlock(block);
395*795d594fSAndroid Build Coastguard Worker return block;
396*795d594fSAndroid Build Coastguard Worker }
397*795d594fSAndroid Build Coastguard Worker
398*795d594fSAndroid Build Coastguard Worker // Run GraphChecker with all checks.
399*795d594fSAndroid Build Coastguard Worker //
400*795d594fSAndroid Build Coastguard Worker // Return: the status whether the run is successful.
401*795d594fSAndroid Build Coastguard Worker bool CheckGraph(std::ostream& oss = std::cerr) {
402*795d594fSAndroid Build Coastguard Worker return CheckGraph(graph_, oss);
403*795d594fSAndroid Build Coastguard Worker }
404*795d594fSAndroid Build Coastguard Worker
ManuallyBuildEnvFor(HInstruction * instruction,ArenaVector<HInstruction * > * current_locals)405*795d594fSAndroid Build Coastguard Worker HEnvironment* ManuallyBuildEnvFor(HInstruction* instruction,
406*795d594fSAndroid Build Coastguard Worker ArenaVector<HInstruction*>* current_locals) {
407*795d594fSAndroid Build Coastguard Worker HEnvironment* environment = HEnvironment::Create(
408*795d594fSAndroid Build Coastguard Worker GetAllocator(),
409*795d594fSAndroid Build Coastguard Worker current_locals->size(),
410*795d594fSAndroid Build Coastguard Worker graph_->GetArtMethod(),
411*795d594fSAndroid Build Coastguard Worker instruction->GetDexPc(),
412*795d594fSAndroid Build Coastguard Worker instruction);
413*795d594fSAndroid Build Coastguard Worker
414*795d594fSAndroid Build Coastguard Worker environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals));
415*795d594fSAndroid Build Coastguard Worker instruction->SetRawEnvironment(environment);
416*795d594fSAndroid Build Coastguard Worker return environment;
417*795d594fSAndroid Build Coastguard Worker }
418*795d594fSAndroid Build Coastguard Worker
EnsurePredecessorOrder(HBasicBlock * target,std::initializer_list<HBasicBlock * > preds)419*795d594fSAndroid Build Coastguard Worker void EnsurePredecessorOrder(HBasicBlock* target, std::initializer_list<HBasicBlock*> preds) {
420*795d594fSAndroid Build Coastguard Worker // Make sure the given preds and block predecessors have the same blocks.
421*795d594fSAndroid Build Coastguard Worker BitVector bv(preds.size(), false, Allocator::GetCallocAllocator());
422*795d594fSAndroid Build Coastguard Worker auto preds_and_idx = ZipCount(MakeIterationRange(target->GetPredecessors()));
423*795d594fSAndroid Build Coastguard Worker bool correct_preds = preds.size() == target->GetPredecessors().size() &&
424*795d594fSAndroid Build Coastguard Worker std::all_of(preds.begin(), preds.end(), [&](HBasicBlock* pred) {
425*795d594fSAndroid Build Coastguard Worker return std::any_of(preds_and_idx.begin(),
426*795d594fSAndroid Build Coastguard Worker preds_and_idx.end(),
427*795d594fSAndroid Build Coastguard Worker // Make sure every target predecessor is used only
428*795d594fSAndroid Build Coastguard Worker // once.
429*795d594fSAndroid Build Coastguard Worker [&](std::pair<HBasicBlock*, uint32_t> cur) {
430*795d594fSAndroid Build Coastguard Worker if (cur.first == pred && !bv.IsBitSet(cur.second)) {
431*795d594fSAndroid Build Coastguard Worker bv.SetBit(cur.second);
432*795d594fSAndroid Build Coastguard Worker return true;
433*795d594fSAndroid Build Coastguard Worker } else {
434*795d594fSAndroid Build Coastguard Worker return false;
435*795d594fSAndroid Build Coastguard Worker }
436*795d594fSAndroid Build Coastguard Worker });
437*795d594fSAndroid Build Coastguard Worker }) &&
438*795d594fSAndroid Build Coastguard Worker bv.NumSetBits() == preds.size();
439*795d594fSAndroid Build Coastguard Worker auto dump_list = [](auto it) {
440*795d594fSAndroid Build Coastguard Worker std::ostringstream oss;
441*795d594fSAndroid Build Coastguard Worker oss << "[";
442*795d594fSAndroid Build Coastguard Worker bool first = true;
443*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* b : it) {
444*795d594fSAndroid Build Coastguard Worker if (!first) {
445*795d594fSAndroid Build Coastguard Worker oss << ", ";
446*795d594fSAndroid Build Coastguard Worker }
447*795d594fSAndroid Build Coastguard Worker first = false;
448*795d594fSAndroid Build Coastguard Worker oss << b->GetBlockId();
449*795d594fSAndroid Build Coastguard Worker }
450*795d594fSAndroid Build Coastguard Worker oss << "]";
451*795d594fSAndroid Build Coastguard Worker return oss.str();
452*795d594fSAndroid Build Coastguard Worker };
453*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(correct_preds) << "Predecessors of " << target->GetBlockId() << " are "
454*795d594fSAndroid Build Coastguard Worker << dump_list(target->GetPredecessors()) << " not "
455*795d594fSAndroid Build Coastguard Worker << dump_list(preds);
456*795d594fSAndroid Build Coastguard Worker if (correct_preds) {
457*795d594fSAndroid Build Coastguard Worker std::copy(preds.begin(), preds.end(), target->predecessors_.begin());
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker }
460*795d594fSAndroid Build Coastguard Worker
SetupFromAdjacencyList(const std::string_view entry_name,const std::string_view exit_name,const std::vector<AdjacencyListGraph::Edge> & adj)461*795d594fSAndroid Build Coastguard Worker AdjacencyListGraph SetupFromAdjacencyList(const std::string_view entry_name,
462*795d594fSAndroid Build Coastguard Worker const std::string_view exit_name,
463*795d594fSAndroid Build Coastguard Worker const std::vector<AdjacencyListGraph::Edge>& adj) {
464*795d594fSAndroid Build Coastguard Worker return AdjacencyListGraph(graph_, GetAllocator(), entry_name, exit_name, adj);
465*795d594fSAndroid Build Coastguard Worker }
466*795d594fSAndroid Build Coastguard Worker
ManuallyBuildEnvFor(HInstruction * ins,const std::initializer_list<HInstruction * > & env)467*795d594fSAndroid Build Coastguard Worker void ManuallyBuildEnvFor(HInstruction* ins, const std::initializer_list<HInstruction*>& env) {
468*795d594fSAndroid Build Coastguard Worker ArenaVector<HInstruction*> current_locals(env, GetAllocator()->Adapter(kArenaAllocInstruction));
469*795d594fSAndroid Build Coastguard Worker OptimizingUnitTestHelper::ManuallyBuildEnvFor(ins, ¤t_locals);
470*795d594fSAndroid Build Coastguard Worker }
471*795d594fSAndroid Build Coastguard Worker
472*795d594fSAndroid Build Coastguard Worker HLoadClass* MakeLoadClass(HBasicBlock* block,
473*795d594fSAndroid Build Coastguard Worker std::optional<dex::TypeIndex> ti = std::nullopt,
474*795d594fSAndroid Build Coastguard Worker std::optional<Handle<mirror::Class>> klass = std::nullopt,
475*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
476*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
477*795d594fSAndroid Build Coastguard Worker HLoadClass* load_class = new (GetAllocator()) HLoadClass(
478*795d594fSAndroid Build Coastguard Worker graph_->GetCurrentMethod(),
479*795d594fSAndroid Build Coastguard Worker ti ? *ti : dex::TypeIndex(class_idx_++),
480*795d594fSAndroid Build Coastguard Worker graph_->GetDexFile(),
481*795d594fSAndroid Build Coastguard Worker /* klass= */ klass ? *klass : null_klass_,
482*795d594fSAndroid Build Coastguard Worker /* is_referrers_class= */ false,
483*795d594fSAndroid Build Coastguard Worker dex_pc,
484*795d594fSAndroid Build Coastguard Worker /* needs_access_check= */ false);
485*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, load_class);
486*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(load_class, env);
487*795d594fSAndroid Build Coastguard Worker return load_class;
488*795d594fSAndroid Build Coastguard Worker }
489*795d594fSAndroid Build Coastguard Worker
490*795d594fSAndroid Build Coastguard Worker HNewInstance* MakeNewInstance(HBasicBlock* block,
491*795d594fSAndroid Build Coastguard Worker HInstruction* cls,
492*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
493*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
494*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(cls->IsLoadClass() || cls->IsClinitCheck()) << *cls;
495*795d594fSAndroid Build Coastguard Worker HLoadClass* load =
496*795d594fSAndroid Build Coastguard Worker cls->IsLoadClass() ? cls->AsLoadClass() : cls->AsClinitCheck()->GetLoadClass();
497*795d594fSAndroid Build Coastguard Worker HNewInstance* new_instance = new (GetAllocator()) HNewInstance(
498*795d594fSAndroid Build Coastguard Worker cls,
499*795d594fSAndroid Build Coastguard Worker dex_pc,
500*795d594fSAndroid Build Coastguard Worker load->GetTypeIndex(),
501*795d594fSAndroid Build Coastguard Worker graph_->GetDexFile(),
502*795d594fSAndroid Build Coastguard Worker /* finalizable= */ false,
503*795d594fSAndroid Build Coastguard Worker QuickEntrypointEnum::kQuickAllocObjectInitialized);
504*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, new_instance);
505*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(new_instance, env);
506*795d594fSAndroid Build Coastguard Worker return new_instance;
507*795d594fSAndroid Build Coastguard Worker }
508*795d594fSAndroid Build Coastguard Worker
509*795d594fSAndroid Build Coastguard Worker HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block,
510*795d594fSAndroid Build Coastguard Worker HInstruction* object,
511*795d594fSAndroid Build Coastguard Worker HInstruction* data,
512*795d594fSAndroid Build Coastguard Worker MemberOffset off,
513*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
514*795d594fSAndroid Build Coastguard Worker CHECK(data != nullptr);
515*795d594fSAndroid Build Coastguard Worker return MakeIFieldSet(block, object, data, data->GetType(), off, dex_pc);
516*795d594fSAndroid Build Coastguard Worker }
517*795d594fSAndroid Build Coastguard Worker
518*795d594fSAndroid Build Coastguard Worker HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block,
519*795d594fSAndroid Build Coastguard Worker HInstruction* object,
520*795d594fSAndroid Build Coastguard Worker HInstruction* data,
521*795d594fSAndroid Build Coastguard Worker DataType::Type field_type,
522*795d594fSAndroid Build Coastguard Worker MemberOffset off,
523*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
524*795d594fSAndroid Build Coastguard Worker HInstanceFieldSet* ifield_set = new (GetAllocator()) HInstanceFieldSet(
525*795d594fSAndroid Build Coastguard Worker object,
526*795d594fSAndroid Build Coastguard Worker data,
527*795d594fSAndroid Build Coastguard Worker /* field= */ nullptr,
528*795d594fSAndroid Build Coastguard Worker field_type,
529*795d594fSAndroid Build Coastguard Worker /* field_offset= */ off,
530*795d594fSAndroid Build Coastguard Worker /* is_volatile= */ false,
531*795d594fSAndroid Build Coastguard Worker kUnknownFieldIndex,
532*795d594fSAndroid Build Coastguard Worker kUnknownClassDefIndex,
533*795d594fSAndroid Build Coastguard Worker graph_->GetDexFile(),
534*795d594fSAndroid Build Coastguard Worker dex_pc);
535*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, ifield_set);
536*795d594fSAndroid Build Coastguard Worker return ifield_set;
537*795d594fSAndroid Build Coastguard Worker }
538*795d594fSAndroid Build Coastguard Worker
539*795d594fSAndroid Build Coastguard Worker HInstanceFieldGet* MakeIFieldGet(HBasicBlock* block,
540*795d594fSAndroid Build Coastguard Worker HInstruction* object,
541*795d594fSAndroid Build Coastguard Worker DataType::Type type,
542*795d594fSAndroid Build Coastguard Worker MemberOffset off,
543*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
544*795d594fSAndroid Build Coastguard Worker HInstanceFieldGet* ifield_get = new (GetAllocator()) HInstanceFieldGet(
545*795d594fSAndroid Build Coastguard Worker object,
546*795d594fSAndroid Build Coastguard Worker /* field= */ nullptr,
547*795d594fSAndroid Build Coastguard Worker /* field_type= */ type,
548*795d594fSAndroid Build Coastguard Worker /* field_offset= */ off,
549*795d594fSAndroid Build Coastguard Worker /* is_volatile= */ false,
550*795d594fSAndroid Build Coastguard Worker kUnknownFieldIndex,
551*795d594fSAndroid Build Coastguard Worker kUnknownClassDefIndex,
552*795d594fSAndroid Build Coastguard Worker graph_->GetDexFile(),
553*795d594fSAndroid Build Coastguard Worker dex_pc);
554*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, ifield_get);
555*795d594fSAndroid Build Coastguard Worker return ifield_get;
556*795d594fSAndroid Build Coastguard Worker }
557*795d594fSAndroid Build Coastguard Worker
558*795d594fSAndroid Build Coastguard Worker HNewArray* MakeNewArray(HBasicBlock* block,
559*795d594fSAndroid Build Coastguard Worker HInstruction* cls,
560*795d594fSAndroid Build Coastguard Worker HInstruction* length,
561*795d594fSAndroid Build Coastguard Worker size_t component_size_shift = DataType::SizeShift(DataType::Type::kInt32),
562*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
563*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
564*795d594fSAndroid Build Coastguard Worker HNewArray* new_array =
565*795d594fSAndroid Build Coastguard Worker new (GetAllocator()) HNewArray(cls, length, dex_pc, component_size_shift);
566*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, new_array);
567*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(new_array, env);
568*795d594fSAndroid Build Coastguard Worker return new_array;
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker
571*795d594fSAndroid Build Coastguard Worker HArraySet* MakeArraySet(HBasicBlock* block,
572*795d594fSAndroid Build Coastguard Worker HInstruction* array,
573*795d594fSAndroid Build Coastguard Worker HInstruction* index,
574*795d594fSAndroid Build Coastguard Worker HInstruction* value,
575*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
576*795d594fSAndroid Build Coastguard Worker CHECK(value != nullptr);
577*795d594fSAndroid Build Coastguard Worker return MakeArraySet(block, array, index, value, value->GetType(), dex_pc);
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
580*795d594fSAndroid Build Coastguard Worker HArraySet* MakeArraySet(HBasicBlock* block,
581*795d594fSAndroid Build Coastguard Worker HInstruction* array,
582*795d594fSAndroid Build Coastguard Worker HInstruction* index,
583*795d594fSAndroid Build Coastguard Worker HInstruction* value,
584*795d594fSAndroid Build Coastguard Worker DataType::Type type,
585*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
586*795d594fSAndroid Build Coastguard Worker HArraySet* array_set = new (GetAllocator()) HArraySet(array, index, value, type, dex_pc);
587*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, array_set);
588*795d594fSAndroid Build Coastguard Worker return array_set;
589*795d594fSAndroid Build Coastguard Worker }
590*795d594fSAndroid Build Coastguard Worker
591*795d594fSAndroid Build Coastguard Worker HArrayGet* MakeArrayGet(HBasicBlock* block,
592*795d594fSAndroid Build Coastguard Worker HInstruction* array,
593*795d594fSAndroid Build Coastguard Worker HInstruction* index,
594*795d594fSAndroid Build Coastguard Worker DataType::Type type,
595*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
596*795d594fSAndroid Build Coastguard Worker HArrayGet* array_get = new (GetAllocator()) HArrayGet(array, index, type, dex_pc);
597*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, array_get);
598*795d594fSAndroid Build Coastguard Worker return array_get;
599*795d594fSAndroid Build Coastguard Worker }
600*795d594fSAndroid Build Coastguard Worker
601*795d594fSAndroid Build Coastguard Worker HArrayLength* MakeArrayLength(HBasicBlock* block,
602*795d594fSAndroid Build Coastguard Worker HInstruction* array,
603*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
604*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = new (GetAllocator()) HArrayLength(array, dex_pc);
605*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, array_length);
606*795d594fSAndroid Build Coastguard Worker return array_length;
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker HNullCheck* MakeNullCheck(HBasicBlock* block,
610*795d594fSAndroid Build Coastguard Worker HInstruction* value,
611*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
612*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
613*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = new (GetAllocator()) HNullCheck(value, dex_pc);
614*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, null_check);
615*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(null_check, env);
616*795d594fSAndroid Build Coastguard Worker return null_check;
617*795d594fSAndroid Build Coastguard Worker }
618*795d594fSAndroid Build Coastguard Worker
619*795d594fSAndroid Build Coastguard Worker HBoundsCheck* MakeBoundsCheck(HBasicBlock* block,
620*795d594fSAndroid Build Coastguard Worker HInstruction* index,
621*795d594fSAndroid Build Coastguard Worker HInstruction* length,
622*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
623*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
624*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check = new (GetAllocator()) HBoundsCheck(index, length, dex_pc);
625*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, bounds_check);
626*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(bounds_check, env);
627*795d594fSAndroid Build Coastguard Worker return bounds_check;
628*795d594fSAndroid Build Coastguard Worker }
629*795d594fSAndroid Build Coastguard Worker
630*795d594fSAndroid Build Coastguard Worker HVecStore* MakeVecStore(HBasicBlock* block,
631*795d594fSAndroid Build Coastguard Worker HInstruction* base,
632*795d594fSAndroid Build Coastguard Worker HInstruction* index,
633*795d594fSAndroid Build Coastguard Worker HInstruction* value,
634*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
635*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
636*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
637*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
638*795d594fSAndroid Build Coastguard Worker SideEffects side_effects = SideEffects::ArrayWriteOfType(packed_type);
639*795d594fSAndroid Build Coastguard Worker HVecStore* vec_store = new (GetAllocator()) HVecStore(
640*795d594fSAndroid Build Coastguard Worker GetAllocator(), base, index, value, packed_type, side_effects, num_of_elements, dex_pc);
641*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, vec_store);
642*795d594fSAndroid Build Coastguard Worker return vec_store;
643*795d594fSAndroid Build Coastguard Worker }
644*795d594fSAndroid Build Coastguard Worker
645*795d594fSAndroid Build Coastguard Worker HVecPredSetAll* MakeVecPredSetAll(HBasicBlock* block,
646*795d594fSAndroid Build Coastguard Worker HInstruction* input,
647*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
648*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
649*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
650*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
651*795d594fSAndroid Build Coastguard Worker HVecPredSetAll* predicate = new (GetAllocator()) HVecPredSetAll(
652*795d594fSAndroid Build Coastguard Worker GetAllocator(), input, packed_type, num_of_elements, dex_pc);
653*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, predicate);
654*795d594fSAndroid Build Coastguard Worker return predicate;
655*795d594fSAndroid Build Coastguard Worker }
656*795d594fSAndroid Build Coastguard Worker
657*795d594fSAndroid Build Coastguard Worker HVecReplicateScalar* MakeVecReplicateScalar(
658*795d594fSAndroid Build Coastguard Worker HBasicBlock* block,
659*795d594fSAndroid Build Coastguard Worker HInstruction* scalar,
660*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
661*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
662*795d594fSAndroid Build Coastguard Worker HVecPredSetOperation* predicate = nullptr,
663*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
664*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
665*795d594fSAndroid Build Coastguard Worker HVecReplicateScalar* vec_replicate_scalar = new (GetAllocator()) HVecReplicateScalar(
666*795d594fSAndroid Build Coastguard Worker GetAllocator(), scalar, packed_type, num_of_elements, dex_pc);
667*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, vec_replicate_scalar);
668*795d594fSAndroid Build Coastguard Worker if (predicate != nullptr) {
669*795d594fSAndroid Build Coastguard Worker vec_replicate_scalar->SetMergingGoverningPredicate(predicate);
670*795d594fSAndroid Build Coastguard Worker }
671*795d594fSAndroid Build Coastguard Worker return vec_replicate_scalar;
672*795d594fSAndroid Build Coastguard Worker }
673*795d594fSAndroid Build Coastguard Worker
674*795d594fSAndroid Build Coastguard Worker HVecPredToBoolean* MakeVecPredToBoolean(
675*795d594fSAndroid Build Coastguard Worker HBasicBlock* block,
676*795d594fSAndroid Build Coastguard Worker HInstruction* input,
677*795d594fSAndroid Build Coastguard Worker HVecPredToBoolean::PCondKind pred_cond,
678*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
679*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
680*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
681*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
682*795d594fSAndroid Build Coastguard Worker HVecPredToBoolean* vec_pred_to_boolean = new (GetAllocator()) HVecPredToBoolean(
683*795d594fSAndroid Build Coastguard Worker GetAllocator(),
684*795d594fSAndroid Build Coastguard Worker input,
685*795d594fSAndroid Build Coastguard Worker pred_cond,
686*795d594fSAndroid Build Coastguard Worker packed_type,
687*795d594fSAndroid Build Coastguard Worker num_of_elements,
688*795d594fSAndroid Build Coastguard Worker dex_pc);
689*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, vec_pred_to_boolean);
690*795d594fSAndroid Build Coastguard Worker return vec_pred_to_boolean;
691*795d594fSAndroid Build Coastguard Worker }
692*795d594fSAndroid Build Coastguard Worker
693*795d594fSAndroid Build Coastguard Worker HVecPredWhile* MakeVecPredWhile(HBasicBlock* block,
694*795d594fSAndroid Build Coastguard Worker HInstruction* left,
695*795d594fSAndroid Build Coastguard Worker HInstruction* right,
696*795d594fSAndroid Build Coastguard Worker HVecPredWhile::CondKind cond,
697*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
698*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
699*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
700*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
701*795d594fSAndroid Build Coastguard Worker HVecPredWhile* vec_pred_while = new (GetAllocator()) HVecPredWhile(
702*795d594fSAndroid Build Coastguard Worker GetAllocator(),
703*795d594fSAndroid Build Coastguard Worker left,
704*795d594fSAndroid Build Coastguard Worker right,
705*795d594fSAndroid Build Coastguard Worker cond,
706*795d594fSAndroid Build Coastguard Worker packed_type,
707*795d594fSAndroid Build Coastguard Worker num_of_elements,
708*795d594fSAndroid Build Coastguard Worker dex_pc);
709*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, vec_pred_while);
710*795d594fSAndroid Build Coastguard Worker return vec_pred_while;
711*795d594fSAndroid Build Coastguard Worker }
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect* MakeInvokeStatic(HBasicBlock* block,
714*795d594fSAndroid Build Coastguard Worker DataType::Type return_type,
715*795d594fSAndroid Build Coastguard Worker const std::vector<HInstruction*>& args,
716*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
717*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
718*795d594fSAndroid Build Coastguard Worker MethodReference method_reference{/* file= */ &graph_->GetDexFile(), /* index= */ method_idx_++};
719*795d594fSAndroid Build Coastguard Worker size_t num_64bit_args = std::count_if(args.begin(), args.end(), [](HInstruction* insn) {
720*795d594fSAndroid Build Coastguard Worker return DataType::Is64BitType(insn->GetType());
721*795d594fSAndroid Build Coastguard Worker });
722*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect* invoke = new (GetAllocator())
723*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect(GetAllocator(),
724*795d594fSAndroid Build Coastguard Worker args.size(),
725*795d594fSAndroid Build Coastguard Worker /* number_of_out_vregs= */ args.size() + num_64bit_args,
726*795d594fSAndroid Build Coastguard Worker return_type,
727*795d594fSAndroid Build Coastguard Worker dex_pc,
728*795d594fSAndroid Build Coastguard Worker method_reference,
729*795d594fSAndroid Build Coastguard Worker /* resolved_method= */ nullptr,
730*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect::DispatchInfo{},
731*795d594fSAndroid Build Coastguard Worker InvokeType::kStatic,
732*795d594fSAndroid Build Coastguard Worker /* resolved_method_reference= */ method_reference,
733*795d594fSAndroid Build Coastguard Worker HInvokeStaticOrDirect::ClinitCheckRequirement::kNone,
734*795d594fSAndroid Build Coastguard Worker !graph_->IsDebuggable());
735*795d594fSAndroid Build Coastguard Worker for (auto [ins, idx] : ZipCount(MakeIterationRange(args))) {
736*795d594fSAndroid Build Coastguard Worker invoke->SetRawInputAt(idx, ins);
737*795d594fSAndroid Build Coastguard Worker }
738*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, invoke);
739*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(invoke, env);
740*795d594fSAndroid Build Coastguard Worker return invoke;
741*795d594fSAndroid Build Coastguard Worker }
742*795d594fSAndroid Build Coastguard Worker
743*795d594fSAndroid Build Coastguard Worker template <typename Type>
744*795d594fSAndroid Build Coastguard Worker Type* MakeBinOp(HBasicBlock* block,
745*795d594fSAndroid Build Coastguard Worker DataType::Type result_type,
746*795d594fSAndroid Build Coastguard Worker HInstruction* left,
747*795d594fSAndroid Build Coastguard Worker HInstruction* right,
748*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
749*795d594fSAndroid Build Coastguard Worker static_assert(std::is_base_of_v<HBinaryOperation, Type>);
750*795d594fSAndroid Build Coastguard Worker Type* insn = new (GetAllocator()) Type(result_type, left, right, dex_pc);
751*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, insn);
752*795d594fSAndroid Build Coastguard Worker return insn;
753*795d594fSAndroid Build Coastguard Worker }
754*795d594fSAndroid Build Coastguard Worker
755*795d594fSAndroid Build Coastguard Worker HCondition* MakeCondition(HBasicBlock* block,
756*795d594fSAndroid Build Coastguard Worker IfCondition cond,
757*795d594fSAndroid Build Coastguard Worker HInstruction* first,
758*795d594fSAndroid Build Coastguard Worker HInstruction* second,
759*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
760*795d594fSAndroid Build Coastguard Worker HCondition* condition = HCondition::Create(graph_, cond, first, second, dex_pc);
761*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, condition);
762*795d594fSAndroid Build Coastguard Worker return condition;
763*795d594fSAndroid Build Coastguard Worker }
764*795d594fSAndroid Build Coastguard Worker
765*795d594fSAndroid Build Coastguard Worker HVecCondition* MakeVecCondition(HBasicBlock* block,
766*795d594fSAndroid Build Coastguard Worker IfCondition cond,
767*795d594fSAndroid Build Coastguard Worker HInstruction* first,
768*795d594fSAndroid Build Coastguard Worker HInstruction* second,
769*795d594fSAndroid Build Coastguard Worker DataType::Type packed_type,
770*795d594fSAndroid Build Coastguard Worker size_t vector_size_in_bytes = kDefaultTestVectorSizeInBytes,
771*795d594fSAndroid Build Coastguard Worker HVecPredSetOperation* predicate = nullptr,
772*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
773*795d594fSAndroid Build Coastguard Worker size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type);
774*795d594fSAndroid Build Coastguard Worker HVecCondition* condition = HVecCondition::Create(graph_,
775*795d594fSAndroid Build Coastguard Worker cond,
776*795d594fSAndroid Build Coastguard Worker first,
777*795d594fSAndroid Build Coastguard Worker second,
778*795d594fSAndroid Build Coastguard Worker packed_type,
779*795d594fSAndroid Build Coastguard Worker num_of_elements,
780*795d594fSAndroid Build Coastguard Worker dex_pc);
781*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, condition);
782*795d594fSAndroid Build Coastguard Worker if (predicate != nullptr) {
783*795d594fSAndroid Build Coastguard Worker condition->SetMergingGoverningPredicate(predicate);
784*795d594fSAndroid Build Coastguard Worker }
785*795d594fSAndroid Build Coastguard Worker return condition;
786*795d594fSAndroid Build Coastguard Worker }
787*795d594fSAndroid Build Coastguard Worker
788*795d594fSAndroid Build Coastguard Worker HSelect* MakeSelect(HBasicBlock* block,
789*795d594fSAndroid Build Coastguard Worker HInstruction* condition,
790*795d594fSAndroid Build Coastguard Worker HInstruction* true_value,
791*795d594fSAndroid Build Coastguard Worker HInstruction* false_value,
792*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
793*795d594fSAndroid Build Coastguard Worker HSelect* select = new (GetAllocator()) HSelect(condition, true_value, false_value, dex_pc);
794*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, select);
795*795d594fSAndroid Build Coastguard Worker return select;
796*795d594fSAndroid Build Coastguard Worker }
797*795d594fSAndroid Build Coastguard Worker
798*795d594fSAndroid Build Coastguard Worker HSuspendCheck* MakeSuspendCheck(HBasicBlock* block,
799*795d594fSAndroid Build Coastguard Worker std::initializer_list<HInstruction*> env = {},
800*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc = kNoDexPc) {
801*795d594fSAndroid Build Coastguard Worker HSuspendCheck* suspend_check = new (GetAllocator()) HSuspendCheck(dex_pc);
802*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(block, suspend_check);
803*795d594fSAndroid Build Coastguard Worker ManuallyBuildEnvFor(suspend_check, env);
804*795d594fSAndroid Build Coastguard Worker return suspend_check;
805*795d594fSAndroid Build Coastguard Worker }
806*795d594fSAndroid Build Coastguard Worker
AddOrInsertInstruction(HBasicBlock * block,HInstruction * instruction)807*795d594fSAndroid Build Coastguard Worker void AddOrInsertInstruction(HBasicBlock* block, HInstruction* instruction) {
808*795d594fSAndroid Build Coastguard Worker CHECK(!instruction->IsControlFlow());
809*795d594fSAndroid Build Coastguard Worker if (block->GetLastInstruction() != nullptr && block->GetLastInstruction()->IsControlFlow()) {
810*795d594fSAndroid Build Coastguard Worker block->InsertInstructionBefore(instruction, block->GetLastInstruction());
811*795d594fSAndroid Build Coastguard Worker } else {
812*795d594fSAndroid Build Coastguard Worker block->AddInstruction(instruction);
813*795d594fSAndroid Build Coastguard Worker }
814*795d594fSAndroid Build Coastguard Worker }
815*795d594fSAndroid Build Coastguard Worker
816*795d594fSAndroid Build Coastguard Worker HIf* MakeIf(HBasicBlock* block, HInstruction* cond, uint32_t dex_pc = kNoDexPc) {
817*795d594fSAndroid Build Coastguard Worker HIf* if_insn = new (GetAllocator()) HIf(cond, dex_pc);
818*795d594fSAndroid Build Coastguard Worker block->AddInstruction(if_insn);
819*795d594fSAndroid Build Coastguard Worker return if_insn;
820*795d594fSAndroid Build Coastguard Worker }
821*795d594fSAndroid Build Coastguard Worker
822*795d594fSAndroid Build Coastguard Worker HGoto* MakeGoto(HBasicBlock* block, uint32_t dex_pc = kNoDexPc) {
823*795d594fSAndroid Build Coastguard Worker HGoto* goto_insn = new (GetAllocator()) HGoto(dex_pc);
824*795d594fSAndroid Build Coastguard Worker block->AddInstruction(goto_insn);
825*795d594fSAndroid Build Coastguard Worker return goto_insn;
826*795d594fSAndroid Build Coastguard Worker }
827*795d594fSAndroid Build Coastguard Worker
828*795d594fSAndroid Build Coastguard Worker HReturnVoid* MakeReturnVoid(HBasicBlock* block, uint32_t dex_pc = kNoDexPc) {
829*795d594fSAndroid Build Coastguard Worker HReturnVoid* return_void = new (GetAllocator()) HReturnVoid(dex_pc);
830*795d594fSAndroid Build Coastguard Worker block->AddInstruction(return_void);
831*795d594fSAndroid Build Coastguard Worker return return_void;
832*795d594fSAndroid Build Coastguard Worker }
833*795d594fSAndroid Build Coastguard Worker
834*795d594fSAndroid Build Coastguard Worker HReturn* MakeReturn(HBasicBlock* block, HInstruction* value, uint32_t dex_pc = kNoDexPc) {
835*795d594fSAndroid Build Coastguard Worker HReturn* return_insn = new (GetAllocator()) HReturn(value, dex_pc);
836*795d594fSAndroid Build Coastguard Worker block->AddInstruction(return_insn);
837*795d594fSAndroid Build Coastguard Worker return return_insn;
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker
MakeExit(HBasicBlock * exit_block)840*795d594fSAndroid Build Coastguard Worker HExit* MakeExit(HBasicBlock* exit_block) {
841*795d594fSAndroid Build Coastguard Worker HExit* exit = new (GetAllocator()) HExit();
842*795d594fSAndroid Build Coastguard Worker exit_block->AddInstruction(exit);
843*795d594fSAndroid Build Coastguard Worker return exit;
844*795d594fSAndroid Build Coastguard Worker }
845*795d594fSAndroid Build Coastguard Worker
MakePhi(HBasicBlock * block,const std::vector<HInstruction * > & ins)846*795d594fSAndroid Build Coastguard Worker HPhi* MakePhi(HBasicBlock* block, const std::vector<HInstruction*>& ins) {
847*795d594fSAndroid Build Coastguard Worker EXPECT_GE(ins.size(), 2u) << "Phi requires at least 2 inputs";
848*795d594fSAndroid Build Coastguard Worker DataType::Type type = DataType::Kind(ins[0]->GetType());
849*795d594fSAndroid Build Coastguard Worker HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), kNoRegNumber, ins.size(), type);
850*795d594fSAndroid Build Coastguard Worker for (auto [i, idx] : ZipCount(MakeIterationRange(ins))) {
851*795d594fSAndroid Build Coastguard Worker phi->SetRawInputAt(idx, i);
852*795d594fSAndroid Build Coastguard Worker }
853*795d594fSAndroid Build Coastguard Worker block->AddPhi(phi);
854*795d594fSAndroid Build Coastguard Worker return phi;
855*795d594fSAndroid Build Coastguard Worker }
856*795d594fSAndroid Build Coastguard Worker
MakeLinearLoopVar(HBasicBlock * header,HBasicBlock * body,int32_t initial,int32_t increment)857*795d594fSAndroid Build Coastguard Worker std::tuple<HPhi*, HAdd*> MakeLinearLoopVar(HBasicBlock* header,
858*795d594fSAndroid Build Coastguard Worker HBasicBlock* body,
859*795d594fSAndroid Build Coastguard Worker int32_t initial,
860*795d594fSAndroid Build Coastguard Worker int32_t increment) {
861*795d594fSAndroid Build Coastguard Worker HInstruction* initial_const = graph_->GetIntConstant(initial);
862*795d594fSAndroid Build Coastguard Worker HInstruction* increment_const = graph_->GetIntConstant(increment);
863*795d594fSAndroid Build Coastguard Worker return MakeLinearLoopVar(header, body, initial_const, increment_const);
864*795d594fSAndroid Build Coastguard Worker }
865*795d594fSAndroid Build Coastguard Worker
MakeLinearLoopVar(HBasicBlock * header,HBasicBlock * body,HInstruction * initial,HInstruction * increment)866*795d594fSAndroid Build Coastguard Worker std::tuple<HPhi*, HAdd*> MakeLinearLoopVar(HBasicBlock* header,
867*795d594fSAndroid Build Coastguard Worker HBasicBlock* body,
868*795d594fSAndroid Build Coastguard Worker HInstruction* initial,
869*795d594fSAndroid Build Coastguard Worker HInstruction* increment) {
870*795d594fSAndroid Build Coastguard Worker HPhi* phi = MakePhi(header, {initial, /* placeholder */ initial});
871*795d594fSAndroid Build Coastguard Worker HAdd* add = MakeBinOp<HAdd>(body, phi->GetType(), phi, increment);
872*795d594fSAndroid Build Coastguard Worker phi->ReplaceInput(add, 1u); // Update back-edge input.
873*795d594fSAndroid Build Coastguard Worker return {phi, add};
874*795d594fSAndroid Build Coastguard Worker }
875*795d594fSAndroid Build Coastguard Worker
DefaultTypeIndexForType(DataType::Type type)876*795d594fSAndroid Build Coastguard Worker dex::TypeIndex DefaultTypeIndexForType(DataType::Type type) {
877*795d594fSAndroid Build Coastguard Worker switch (type) {
878*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
879*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(1);
880*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
881*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
882*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(2);
883*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
884*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
885*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(3);
886*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint32:
887*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
888*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(4);
889*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint64:
890*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
891*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(5);
892*795d594fSAndroid Build Coastguard Worker case DataType::Type::kReference:
893*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(6);
894*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
895*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(7);
896*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
897*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(8);
898*795d594fSAndroid Build Coastguard Worker case DataType::Type::kVoid:
899*795d594fSAndroid Build Coastguard Worker EXPECT_TRUE(false) << "No type for void!";
900*795d594fSAndroid Build Coastguard Worker return dex::TypeIndex(1000);
901*795d594fSAndroid Build Coastguard Worker }
902*795d594fSAndroid Build Coastguard Worker }
903*795d594fSAndroid Build Coastguard Worker
904*795d594fSAndroid Build Coastguard Worker // Creates a parameter. The instruction is automatically added to the entry-block.
905*795d594fSAndroid Build Coastguard Worker HParameterValue* MakeParam(DataType::Type type, std::optional<dex::TypeIndex> ti = std::nullopt) {
906*795d594fSAndroid Build Coastguard Worker HParameterValue* val = new (GetAllocator()) HParameterValue(
907*795d594fSAndroid Build Coastguard Worker graph_->GetDexFile(), ti ? *ti : DefaultTypeIndexForType(type), param_count_++, type);
908*795d594fSAndroid Build Coastguard Worker AddOrInsertInstruction(graph_->GetEntryBlock(), val);
909*795d594fSAndroid Build Coastguard Worker return val;
910*795d594fSAndroid Build Coastguard Worker }
911*795d594fSAndroid Build Coastguard Worker
912*795d594fSAndroid Build Coastguard Worker protected:
CheckGraph(HGraph * graph,std::ostream & oss)913*795d594fSAndroid Build Coastguard Worker bool CheckGraph(HGraph* graph, std::ostream& oss) {
914*795d594fSAndroid Build Coastguard Worker GraphChecker checker(graph);
915*795d594fSAndroid Build Coastguard Worker checker.Run();
916*795d594fSAndroid Build Coastguard Worker checker.Dump(oss);
917*795d594fSAndroid Build Coastguard Worker return checker.IsValid();
918*795d594fSAndroid Build Coastguard Worker }
919*795d594fSAndroid Build Coastguard Worker
920*795d594fSAndroid Build Coastguard Worker std::vector<std::unique_ptr<const StandardDexFile>> dex_files_;
921*795d594fSAndroid Build Coastguard Worker std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_;
922*795d594fSAndroid Build Coastguard Worker
923*795d594fSAndroid Build Coastguard Worker HGraph* graph_;
924*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry_block_;
925*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit_block_;
926*795d594fSAndroid Build Coastguard Worker
927*795d594fSAndroid Build Coastguard Worker size_t param_count_ = 0;
928*795d594fSAndroid Build Coastguard Worker size_t class_idx_ = 42;
929*795d594fSAndroid Build Coastguard Worker uint32_t method_idx_ = 100;
930*795d594fSAndroid Build Coastguard Worker
931*795d594fSAndroid Build Coastguard Worker // The default size of vectors to use for tests, in bytes. 16 bytes (128 bits) is used as it is
932*795d594fSAndroid Build Coastguard Worker // commonly the smallest size of vector used in vector extensions.
933*795d594fSAndroid Build Coastguard Worker static constexpr size_t kDefaultTestVectorSizeInBytes = 16;
934*795d594fSAndroid Build Coastguard Worker
935*795d594fSAndroid Build Coastguard Worker ScopedNullHandle<mirror::Class> null_klass_;
936*795d594fSAndroid Build Coastguard Worker };
937*795d594fSAndroid Build Coastguard Worker
938*795d594fSAndroid Build Coastguard Worker class OptimizingUnitTest : public CommonArtTest, public OptimizingUnitTestHelper {};
939*795d594fSAndroid Build Coastguard Worker
940*795d594fSAndroid Build Coastguard Worker // Naive string diff data type.
941*795d594fSAndroid Build Coastguard Worker using diff_t = std::list<std::pair<std::string, std::string>>;
942*795d594fSAndroid Build Coastguard Worker
943*795d594fSAndroid Build Coastguard Worker // An alias for the empty string used to make it clear that a line is
944*795d594fSAndroid Build Coastguard Worker // removed in a diff.
945*795d594fSAndroid Build Coastguard Worker static const std::string removed = ""; // NOLINT [runtime/string] [4]
946*795d594fSAndroid Build Coastguard Worker
947*795d594fSAndroid Build Coastguard Worker // Naive patch command: apply a diff to a string.
Patch(const std::string & original,const diff_t & diff)948*795d594fSAndroid Build Coastguard Worker inline std::string Patch(const std::string& original, const diff_t& diff) {
949*795d594fSAndroid Build Coastguard Worker std::string result = original;
950*795d594fSAndroid Build Coastguard Worker for (const auto& p : diff) {
951*795d594fSAndroid Build Coastguard Worker std::string::size_type pos = result.find(p.first);
952*795d594fSAndroid Build Coastguard Worker DCHECK_NE(pos, std::string::npos)
953*795d594fSAndroid Build Coastguard Worker << "Could not find: \"" << p.first << "\" in \"" << result << "\"";
954*795d594fSAndroid Build Coastguard Worker result.replace(pos, p.first.size(), p.second);
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker return result;
957*795d594fSAndroid Build Coastguard Worker }
958*795d594fSAndroid Build Coastguard Worker
959*795d594fSAndroid Build Coastguard Worker // Returns if the instruction is removed from the graph.
IsRemoved(HInstruction * instruction)960*795d594fSAndroid Build Coastguard Worker inline bool IsRemoved(HInstruction* instruction) {
961*795d594fSAndroid Build Coastguard Worker return instruction->GetBlock() == nullptr;
962*795d594fSAndroid Build Coastguard Worker }
963*795d594fSAndroid Build Coastguard Worker
964*795d594fSAndroid Build Coastguard Worker inline std::ostream& operator<<(std::ostream& oss, const AdjacencyListGraph& alg) {
965*795d594fSAndroid Build Coastguard Worker return alg.Dump(oss);
966*795d594fSAndroid Build Coastguard Worker }
967*795d594fSAndroid Build Coastguard Worker
968*795d594fSAndroid Build Coastguard Worker class PatternMatchGraphVisitor final : public HGraphVisitor {
969*795d594fSAndroid Build Coastguard Worker private:
970*795d594fSAndroid Build Coastguard Worker struct HandlerWrapper {
971*795d594fSAndroid Build Coastguard Worker public:
~HandlerWrapperHandlerWrapper972*795d594fSAndroid Build Coastguard Worker virtual ~HandlerWrapper() {}
973*795d594fSAndroid Build Coastguard Worker virtual void operator()(HInstruction* h) = 0;
974*795d594fSAndroid Build Coastguard Worker };
975*795d594fSAndroid Build Coastguard Worker
976*795d594fSAndroid Build Coastguard Worker template <HInstruction::InstructionKind kKind, typename F>
977*795d594fSAndroid Build Coastguard Worker struct KindWrapper;
978*795d594fSAndroid Build Coastguard Worker
979*795d594fSAndroid Build Coastguard Worker #define GEN_HANDLER(nm, unused) \
980*795d594fSAndroid Build Coastguard Worker template <typename F> \
981*795d594fSAndroid Build Coastguard Worker struct KindWrapper<HInstruction::InstructionKind::k##nm, F> : public HandlerWrapper { \
982*795d594fSAndroid Build Coastguard Worker public: \
983*795d594fSAndroid Build Coastguard Worker explicit KindWrapper(F f) : f_(f) {} \
984*795d594fSAndroid Build Coastguard Worker void operator()(HInstruction* h) override { \
985*795d594fSAndroid Build Coastguard Worker if constexpr (std::is_invocable_v<F, H##nm*>) { \
986*795d594fSAndroid Build Coastguard Worker f_(h->As##nm()); \
987*795d594fSAndroid Build Coastguard Worker } else { \
988*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Incorrect call with " << #nm; \
989*795d594fSAndroid Build Coastguard Worker } \
990*795d594fSAndroid Build Coastguard Worker } \
991*795d594fSAndroid Build Coastguard Worker \
992*795d594fSAndroid Build Coastguard Worker private: \
993*795d594fSAndroid Build Coastguard Worker F f_; \
994*795d594fSAndroid Build Coastguard Worker };
995*795d594fSAndroid Build Coastguard Worker
FOR_EACH_CONCRETE_INSTRUCTION(GEN_HANDLER)996*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONCRETE_INSTRUCTION(GEN_HANDLER)
997*795d594fSAndroid Build Coastguard Worker #undef GEN_HANDLER
998*795d594fSAndroid Build Coastguard Worker
999*795d594fSAndroid Build Coastguard Worker template <typename F>
1000*795d594fSAndroid Build Coastguard Worker std::unique_ptr<HandlerWrapper> GetWrapper(HInstruction::InstructionKind kind, F f) {
1001*795d594fSAndroid Build Coastguard Worker switch (kind) {
1002*795d594fSAndroid Build Coastguard Worker #define GEN_GETTER(nm, unused) \
1003*795d594fSAndroid Build Coastguard Worker case HInstruction::InstructionKind::k##nm: \
1004*795d594fSAndroid Build Coastguard Worker return std::unique_ptr<HandlerWrapper>( \
1005*795d594fSAndroid Build Coastguard Worker new KindWrapper<HInstruction::InstructionKind::k##nm, F>(f));
1006*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONCRETE_INSTRUCTION(GEN_GETTER)
1007*795d594fSAndroid Build Coastguard Worker #undef GEN_GETTER
1008*795d594fSAndroid Build Coastguard Worker default:
1009*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unable to handle kind " << kind;
1010*795d594fSAndroid Build Coastguard Worker return nullptr;
1011*795d594fSAndroid Build Coastguard Worker }
1012*795d594fSAndroid Build Coastguard Worker }
1013*795d594fSAndroid Build Coastguard Worker
1014*795d594fSAndroid Build Coastguard Worker public:
1015*795d594fSAndroid Build Coastguard Worker template <typename... Inst>
PatternMatchGraphVisitor(HGraph * graph,Inst...handlers)1016*795d594fSAndroid Build Coastguard Worker explicit PatternMatchGraphVisitor(HGraph* graph, Inst... handlers) : HGraphVisitor(graph) {
1017*795d594fSAndroid Build Coastguard Worker FillHandlers(handlers...);
1018*795d594fSAndroid Build Coastguard Worker }
1019*795d594fSAndroid Build Coastguard Worker
VisitInstruction(HInstruction * instruction)1020*795d594fSAndroid Build Coastguard Worker void VisitInstruction(HInstruction* instruction) override {
1021*795d594fSAndroid Build Coastguard Worker auto& h = handlers_[instruction->GetKind()];
1022*795d594fSAndroid Build Coastguard Worker if (h.get() != nullptr) {
1023*795d594fSAndroid Build Coastguard Worker (*h)(instruction);
1024*795d594fSAndroid Build Coastguard Worker }
1025*795d594fSAndroid Build Coastguard Worker }
1026*795d594fSAndroid Build Coastguard Worker
1027*795d594fSAndroid Build Coastguard Worker private:
1028*795d594fSAndroid Build Coastguard Worker template <typename Func>
GetKind()1029*795d594fSAndroid Build Coastguard Worker constexpr HInstruction::InstructionKind GetKind() {
1030*795d594fSAndroid Build Coastguard Worker #define CHECK_INST(nm, unused) \
1031*795d594fSAndroid Build Coastguard Worker if constexpr (std::is_invocable_v<Func, H##nm*>) { \
1032*795d594fSAndroid Build Coastguard Worker return HInstruction::InstructionKind::k##nm; \
1033*795d594fSAndroid Build Coastguard Worker }
1034*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONCRETE_INSTRUCTION(CHECK_INST);
1035*795d594fSAndroid Build Coastguard Worker #undef CHECK_INST
1036*795d594fSAndroid Build Coastguard Worker static_assert(!std::is_invocable_v<Func, HInstruction*>,
1037*795d594fSAndroid Build Coastguard Worker "Use on generic HInstruction not allowed");
1038*795d594fSAndroid Build Coastguard Worker #define STATIC_ASSERT_ABSTRACT(nm, unused) && !std::is_invocable_v<Func, H##nm*>
1039*795d594fSAndroid Build Coastguard Worker static_assert(true FOR_EACH_ABSTRACT_INSTRUCTION(STATIC_ASSERT_ABSTRACT),
1040*795d594fSAndroid Build Coastguard Worker "Must not be abstract instruction");
1041*795d594fSAndroid Build Coastguard Worker #undef STATIC_ASSERT_ABSTRACT
1042*795d594fSAndroid Build Coastguard Worker #define STATIC_ASSERT_CONCRETE(nm, unused) || std::is_invocable_v<Func, H##nm*>
1043*795d594fSAndroid Build Coastguard Worker static_assert(false FOR_EACH_CONCRETE_INSTRUCTION(STATIC_ASSERT_CONCRETE),
1044*795d594fSAndroid Build Coastguard Worker "Must be a concrete instruction");
1045*795d594fSAndroid Build Coastguard Worker #undef STATIC_ASSERT_CONCRETE
1046*795d594fSAndroid Build Coastguard Worker return HInstruction::InstructionKind::kLastInstructionKind;
1047*795d594fSAndroid Build Coastguard Worker }
1048*795d594fSAndroid Build Coastguard Worker template <typename First>
FillHandlers(First h1)1049*795d594fSAndroid Build Coastguard Worker void FillHandlers(First h1) {
1050*795d594fSAndroid Build Coastguard Worker HInstruction::InstructionKind type = GetKind<First>();
1051*795d594fSAndroid Build Coastguard Worker CHECK_NE(type, HInstruction::kLastInstructionKind)
1052*795d594fSAndroid Build Coastguard Worker << "Unknown instruction kind. Only concrete ones please.";
1053*795d594fSAndroid Build Coastguard Worker handlers_[type] = GetWrapper(type, h1);
1054*795d594fSAndroid Build Coastguard Worker }
1055*795d594fSAndroid Build Coastguard Worker
1056*795d594fSAndroid Build Coastguard Worker template <typename First, typename... Inst>
FillHandlers(First h1,Inst...handlers)1057*795d594fSAndroid Build Coastguard Worker void FillHandlers(First h1, Inst... handlers) {
1058*795d594fSAndroid Build Coastguard Worker FillHandlers(h1);
1059*795d594fSAndroid Build Coastguard Worker FillHandlers<Inst...>(handlers...);
1060*795d594fSAndroid Build Coastguard Worker }
1061*795d594fSAndroid Build Coastguard Worker
1062*795d594fSAndroid Build Coastguard Worker std::array<std::unique_ptr<HandlerWrapper>, HInstruction::InstructionKind::kLastInstructionKind>
1063*795d594fSAndroid Build Coastguard Worker handlers_;
1064*795d594fSAndroid Build Coastguard Worker };
1065*795d594fSAndroid Build Coastguard Worker
1066*795d594fSAndroid Build Coastguard Worker template <typename... Target>
1067*795d594fSAndroid Build Coastguard Worker std::tuple<std::vector<Target*>...> FindAllInstructions(
1068*795d594fSAndroid Build Coastguard Worker HGraph* graph,
1069*795d594fSAndroid Build Coastguard Worker std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
1070*795d594fSAndroid Build Coastguard Worker std::nullopt) {
1071*795d594fSAndroid Build Coastguard Worker std::tuple<std::vector<Target*>...> res;
1072*795d594fSAndroid Build Coastguard Worker PatternMatchGraphVisitor vis(
1073*795d594fSAndroid Build Coastguard Worker graph, [&](Target* t) { std::get<std::vector<Target*>>(res).push_back(t); }...);
1074*795d594fSAndroid Build Coastguard Worker
1075*795d594fSAndroid Build Coastguard Worker if (std::holds_alternative<std::initializer_list<HBasicBlock*>>(blks)) {
1076*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* blk : std::get<std::initializer_list<HBasicBlock*>>(blks)) {
1077*795d594fSAndroid Build Coastguard Worker vis.VisitBasicBlock(blk);
1078*795d594fSAndroid Build Coastguard Worker }
1079*795d594fSAndroid Build Coastguard Worker } else if (std::holds_alternative<std::nullopt_t>(blks)) {
1080*795d594fSAndroid Build Coastguard Worker vis.VisitInsertionOrder();
1081*795d594fSAndroid Build Coastguard Worker } else {
1082*795d594fSAndroid Build Coastguard Worker vis.VisitBasicBlock(std::get<HBasicBlock*>(blks));
1083*795d594fSAndroid Build Coastguard Worker }
1084*795d594fSAndroid Build Coastguard Worker return res;
1085*795d594fSAndroid Build Coastguard Worker }
1086*795d594fSAndroid Build Coastguard Worker
1087*795d594fSAndroid Build Coastguard Worker template <typename... Target>
1088*795d594fSAndroid Build Coastguard Worker std::tuple<Target*...> FindSingleInstructions(
1089*795d594fSAndroid Build Coastguard Worker HGraph* graph,
1090*795d594fSAndroid Build Coastguard Worker std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
1091*795d594fSAndroid Build Coastguard Worker std::nullopt) {
1092*795d594fSAndroid Build Coastguard Worker std::tuple<Target*...> res;
1093*795d594fSAndroid Build Coastguard Worker PatternMatchGraphVisitor vis(graph, [&](Target* t) {
1094*795d594fSAndroid Build Coastguard Worker EXPECT_EQ(std::get<Target*>(res), nullptr)
1095*795d594fSAndroid Build Coastguard Worker << *std::get<Target*>(res) << " already found but found " << *t << "!";
1096*795d594fSAndroid Build Coastguard Worker std::get<Target*>(res) = t;
1097*795d594fSAndroid Build Coastguard Worker }...);
1098*795d594fSAndroid Build Coastguard Worker if (std::holds_alternative<std::initializer_list<HBasicBlock*>>(blks)) {
1099*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* blk : std::get<std::initializer_list<HBasicBlock*>>(blks)) {
1100*795d594fSAndroid Build Coastguard Worker vis.VisitBasicBlock(blk);
1101*795d594fSAndroid Build Coastguard Worker }
1102*795d594fSAndroid Build Coastguard Worker } else if (std::holds_alternative<std::nullopt_t>(blks)) {
1103*795d594fSAndroid Build Coastguard Worker vis.VisitInsertionOrder();
1104*795d594fSAndroid Build Coastguard Worker } else {
1105*795d594fSAndroid Build Coastguard Worker vis.VisitBasicBlock(std::get<HBasicBlock*>(blks));
1106*795d594fSAndroid Build Coastguard Worker }
1107*795d594fSAndroid Build Coastguard Worker return res;
1108*795d594fSAndroid Build Coastguard Worker }
1109*795d594fSAndroid Build Coastguard Worker
1110*795d594fSAndroid Build Coastguard Worker template <typename Target>
1111*795d594fSAndroid Build Coastguard Worker Target* FindSingleInstruction(
1112*795d594fSAndroid Build Coastguard Worker HGraph* graph,
1113*795d594fSAndroid Build Coastguard Worker std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
1114*795d594fSAndroid Build Coastguard Worker std::nullopt) {
1115*795d594fSAndroid Build Coastguard Worker return std::get<Target*>(FindSingleInstructions<Target>(graph, blks));
1116*795d594fSAndroid Build Coastguard Worker }
1117*795d594fSAndroid Build Coastguard Worker
1118*795d594fSAndroid Build Coastguard Worker } // namespace art
1119*795d594fSAndroid Build Coastguard Worker
1120*795d594fSAndroid Build Coastguard Worker #endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
1121