• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "assembler/assembly-emitter.h"
17 #include "canonicalization.h"
18 #include "codegen.h"
19 #include "common.h"
20 #include "compiler/optimizer/optimizations/lowering.h"
21 #include "compiler/optimizer/optimizations/regalloc/reg_alloc_linear_scan.h"
22 #include "reg_encoder.h"
23 
24 namespace ark::bytecodeopt::test {
25 
26 // NOLINTBEGIN(readability-magic-numbers)
27 
TEST_F(CommonTest,RegEncoderF32)28 TEST_F(CommonTest, RegEncoderF32)
29 {
30     auto graph = CreateEmptyGraph();
31     GRAPH(graph)
32     {
33         CONSTANT(0U, 0.0).f32();
34         CONSTANT(1U, 0.0).f32();
35         CONSTANT(2U, 0.0).f32();
36         CONSTANT(3U, 0.0).f32();
37         CONSTANT(4U, 0.0).f32();
38         CONSTANT(5U, 0.0).f32();
39         CONSTANT(6U, 0.0).f32();
40         CONSTANT(7U, 0.0).f32();
41         CONSTANT(8U, 0.0).f32();
42         CONSTANT(9U, 0.0).f32();
43         CONSTANT(10U, 0.0).f32();
44         CONSTANT(11U, 0.0).f32();
45         CONSTANT(12U, 0.0).f32();
46         CONSTANT(13U, 0.0).f32();
47         CONSTANT(14U, 0.0).f32();
48         CONSTANT(15U, 0.0).f32();
49         CONSTANT(16U, 0.0).f32();
50         CONSTANT(17U, 0.0).f32();
51         CONSTANT(18U, 0.0).f32();
52         CONSTANT(19U, 0.0).f32();
53         CONSTANT(20U, 0.0).f32();
54         CONSTANT(21U, 0.0).f32();
55         CONSTANT(22U, 0.0).f32();
56         CONSTANT(23U, 0.0).f32();
57         CONSTANT(24U, 0.0).f32();
58         CONSTANT(25U, 0.0).f32();
59         CONSTANT(26U, 0.0).f32();
60         CONSTANT(27U, 0.0).f32();
61         CONSTANT(28U, 0.0).f32();
62         CONSTANT(29U, 0.0).f32();
63         CONSTANT(30U, 0.0).f32();
64         CONSTANT(31U, 0.0).f32();
65 
66         CONSTANT(32U, 1.0).f64();
67         CONSTANT(33U, 2.0_D).f64();
68 
69         BASIC_BLOCK(2U, -1L)
70         {
71             // NOLINTNEXTLINE(google-build-using-namespace)
72             using namespace compiler::DataType;
73             INST(40U, Opcode::Sub).f64().Inputs(32U, 33U);
74             INST(41U, Opcode::Return).f64().Inputs(40U);
75         }
76     }
77 
78     EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
79     EXPECT_TRUE(graph->RunPass<RegEncoder>());
80     EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
81 
82     auto expected = CreateEmptyGraph();
83     GRAPH(expected)
84     {
85         CONSTANT(32U, 1.0).f64();
86         CONSTANT(33U, 2.0_D).f64();
87 
88         BASIC_BLOCK(2U, -1L)
89         {
90             // NOLINTNEXTLINE(google-build-using-namespace)
91             using namespace compiler::DataType;
92             INST(40U, Opcode::Sub).f64().Inputs(32U, 33U);
93             INST(41U, Opcode::Return).f64().Inputs(40U);
94         }
95     }
96 
97     EXPECT_TRUE(GraphComparator().Compare(graph, expected));
98 }
99 
TEST_F(CommonTest,RegEncoderHoldingSpillFillInst)100 TEST_F(CommonTest, RegEncoderHoldingSpillFillInst)
101 {
102     RuntimeInterfaceMock interface(2U);
103     auto graph = CreateEmptyGraph();
104     graph->SetRuntime(&interface);
105     GRAPH(graph)
106     {
107         // NOLINTNEXTLINE(google-build-using-namespace)
108         using namespace compiler::DataType;
109 
110         PARAMETER(0U, 0U).ref();
111         PARAMETER(1U, 1U).b();
112         CONSTANT(26U, 0xfffffffffffffffaU).s64();
113         CONSTANT(27U, 0x6U).s64();
114 
115         BASIC_BLOCK(2U, 3U, 4U)
116         {
117             INST(4U, Opcode::LoadObject).s64().Inputs(0U);
118             INST(10U, Opcode::LoadObject).s64().Inputs(0U);
119             INST(11U, Opcode::Add).s64().Inputs(10U, 4U);
120             CONSTANT(52U, 0x5265c00U).s64();
121             INST(15U, Opcode::Div).s64().Inputs(11U, 52U);
122             INST(16U, Opcode::Mul).s64().Inputs(15U, 52U);
123             INST(20U, Opcode::Sub).s64().Inputs(16U, 10U);
124             CONSTANT(53U, 0x2932e00U).s64();
125             INST(22U, Opcode::Add).s64().Inputs(20U, 53U);
126             INST(25U, Opcode::IfImm).SrcType(BOOL).CC(compiler::CC_EQ).Imm(0U).Inputs(1U);
127         }
128 
129         BASIC_BLOCK(3U, 4U) {}
130 
131         BASIC_BLOCK(4U, -1L)
132         {
133             INST(28U, Opcode::Phi).s64().Inputs(26U, 27U);
134             CONSTANT(54U, 0x36ee80U).s64();
135             INST(31U, Opcode::Mul).s64().Inputs(28U, 54U);
136             INST(32U, Opcode::Add).s64().Inputs(31U, 22U);
137             INST(33U, Opcode::SaveState).NoVregs();
138             INST(35U, Opcode::CallVirtual).v0id().Inputs({{REFERENCE, 0U}, {INT64, 32U}, {NO_TYPE, 33U}});
139             INST(36U, Opcode::SaveState).NoVregs();
140             INST(37U, Opcode::LoadAndInitClass).ref().Inputs(36U);
141             INST(39U, Opcode::SaveState).NoVregs();
142             INST(58U, Opcode::InitObject).ref().Inputs({{REFERENCE, 37U}, {REFERENCE, 0U}, {NO_TYPE, 39U}});
143             CONSTANT(55U, 0.0093026_D).f64();
144             CONSTANT(56U, 0.0098902_D).f64();
145             CONSTANT(57U, 0x1388U).s64();
146             INST(45U, Opcode::SaveState).NoVregs();
147             INST(47U, Opcode::CallStatic)
148                 .s64()
149                 .Inputs({{REFERENCE, 0},
150                          {REFERENCE, 58U},
151                          {BOOL, 1U},
152                          {FLOAT64, 55U},
153                          {FLOAT64, 56U},
154                          {INT64, 57U},
155                          {NO_TYPE, 45U}});
156             INST(48U, Opcode::SaveState).NoVregs();
157             INST(50U, Opcode::CallVirtual).v0id().Inputs({{REFERENCE, 0U}, {INT64, 4U}, {NO_TYPE, 48U}});
158             INST(51U, Opcode::Return).s64().Inputs(47U);
159         }
160     }
161 
162     EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
163     EXPECT_TRUE(graph->RunPass<RegEncoder>());
164     auto expected = CreateEmptyGraph();
165     GRAPH(expected)
166     {
167         // NOLINTNEXTLINE(google-build-using-namespace)
168         using namespace compiler::DataType;
169 
170         PARAMETER(0U, 0U).ref();
171         PARAMETER(1U, 1U).b();
172         CONSTANT(26U, 0xfffffffffffffffaU).s64();
173         CONSTANT(27U, 0x6U).s64();
174 
175         BASIC_BLOCK(2U, 3U, 4U)
176         {
177             INST(4U, Opcode::LoadObject).s64().Inputs(0U);
178             INST(10U, Opcode::LoadObject).s64().Inputs(0U);
179             INST(11U, Opcode::Add).s64().Inputs(10U, 4U);
180             CONSTANT(52U, 0x5265c00U).s64();
181             INST(15U, Opcode::Div).s64().Inputs(11U, 52U);
182             INST(16U, Opcode::Mul).s64().Inputs(15U, 52U);
183             INST(20U, Opcode::Sub).s64().Inputs(16U, 10U);
184             CONSTANT(53U, 0x2932e00U).s64();
185             INST(22U, Opcode::Add).s64().Inputs(20U, 53U);
186             INST(25U, Opcode::IfImm).SrcType(BOOL).CC(compiler::CC_EQ).Imm(0U).Inputs(1U);
187         }
188 
189         BASIC_BLOCK(3U, 4U)
190         {
191             // SpillFill added
192             INST(60U, Opcode::SpillFill);
193         }
194 
195         BASIC_BLOCK(4U, -1L)
196         {
197             INST(28U, Opcode::Phi).s64().Inputs(26U, 27U);
198             CONSTANT(54U, 0x36ee80U).s64();
199             INST(31U, Opcode::Mul).s64().Inputs(28U, 54U);
200             INST(32U, Opcode::Add).s64().Inputs(31U, 22U);
201             INST(33U, Opcode::SaveState).NoVregs();
202             INST(35U, Opcode::CallVirtual).v0id().Inputs({{REFERENCE, 0U}, {INT64, 32U}, {NO_TYPE, 33U}});
203             INST(36U, Opcode::SaveState).NoVregs();
204             INST(37U, Opcode::LoadAndInitClass).ref().Inputs(36U);
205             INST(39U, Opcode::SaveState).NoVregs();
206             INST(58U, Opcode::InitObject).ref().Inputs({{REFERENCE, 37U}, {REFERENCE, 0U}, {NO_TYPE, 39U}});
207             CONSTANT(55U, 0.0093026_D).f64();
208             CONSTANT(56U, 0.0098902_D).f64();
209             CONSTANT(57U, 0x1388U).s64();
210             INST(45U, Opcode::SaveState).NoVregs();
211 
212             // SpillFill added
213             INST(70U, Opcode::SpillFill);
214             INST(47U, Opcode::CallStatic)
215                 .s64()
216                 .Inputs({{REFERENCE, 0},
217                          {REFERENCE, 58U},
218                          {BOOL, 1U},
219                          {FLOAT64, 55U},
220                          {FLOAT64, 56U},
221                          {INT64, 57U},
222                          {NO_TYPE, 45U}});
223             INST(48U, Opcode::SaveState).NoVregs();
224             INST(50U, Opcode::CallVirtual).v0id().Inputs({{REFERENCE, 0U}, {INT64, 4U}, {NO_TYPE, 48U}});
225             INST(51U, Opcode::Return).s64().Inputs(47U);
226         }
227     }
228 
229     EXPECT_TRUE(GraphComparator().Compare(graph, expected));
230 }
231 
TEST_F(CommonTest,RegEncoderStoreObject)232 TEST_F(CommonTest, RegEncoderStoreObject)
233 {
234     // This test covers function CheckWidthVisitor::VisitStoreObject
235     RuntimeInterfaceMock interface(4U);
236     auto graph = CreateEmptyGraph();
237     graph->SetRuntime(&interface);
238     GRAPH(graph)
239     {
240         PARAMETER(0U, 0U).ref();
241         PARAMETER(1U, 1U).ref();
242         PARAMETER(2U, 2U).ref();
243         PARAMETER(3U, 3U).s32();
244 
245         BASIC_BLOCK(2U, -1L)
246         {
247             // NOLINTNEXTLINE(google-build-using-namespace)
248             using namespace compiler::DataType;
249 
250             INST(4U, Opcode::SaveState).NoVregs();
251             INST(6U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 0U}, {NO_TYPE, 4U}});
252             INST(9U, Opcode::StoreObject).ref().Inputs(0U, 2U);
253             INST(12U, Opcode::StoreObject).s32().Inputs(0U, 3U);
254             INST(15U, Opcode::LoadObject).ref().Inputs(1U);
255             INST(16U, Opcode::SaveState).NoVregs();
256             INST(18U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 15U}, {NO_TYPE, 16U}});
257             INST(19U, Opcode::SaveState).NoVregs();
258             INST(21U, Opcode::LoadClass).ref().Inputs(19U);
259             INST(20U, Opcode::CheckCast).Inputs(18U, 21U, 19U);
260             INST(23U, Opcode::StoreObject).ref().Inputs(0U, 18U);
261             INST(26U, Opcode::LoadObject).ref().Inputs(1U);
262             INST(27U, Opcode::SaveState).NoVregs();
263             INST(29U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 26U}, {NO_TYPE, 27U}});
264             INST(30U, Opcode::SaveState).NoVregs();
265             INST(32U, Opcode::LoadClass).ref().Inputs(30U);
266             INST(31U, Opcode::CheckCast).Inputs(29U, 32U, 30U);
267             INST(34U, Opcode::StoreObject).ref().Inputs(0U, 29U);
268             INST(37U, Opcode::LoadObject).ref().Inputs(1U);
269             INST(38U, Opcode::SaveState).NoVregs();
270             INST(40U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 37U}, {NO_TYPE, 38U}});
271             INST(41U, Opcode::SaveState).NoVregs();
272             INST(43U, Opcode::LoadClass).ref().Inputs(41U);
273             INST(42U, Opcode::CheckCast).Inputs(40U, 43U, 41U);
274             INST(45U, Opcode::StoreObject).ref().Inputs(0U, 40U);
275             INST(48U, Opcode::LoadObject).ref().Inputs(1U);
276             INST(49U, Opcode::SaveState).NoVregs();
277             INST(51U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 48U}, {NO_TYPE, 49U}});
278             INST(52U, Opcode::SaveState).NoVregs();
279             INST(54U, Opcode::LoadClass).ref().Inputs(52U);
280             INST(53U, Opcode::CheckCast).Inputs(51U, 54U, 52U);
281             INST(56U, Opcode::StoreObject).ref().Inputs(0U, 51U);
282             INST(57U, Opcode::ReturnVoid).v0id();
283         }
284     }
285 
286     EXPECT_TRUE(graph->RunPass<compiler::RegAllocLinearScan>(compiler::EmptyRegMask()));
287     EXPECT_TRUE(graph->RunPass<RegEncoder>());
288     EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
289 
290     auto expected = CreateEmptyGraph();
291     GRAPH(expected)
292     {
293         PARAMETER(0U, 0U).ref();
294         PARAMETER(1U, 1U).ref();
295         PARAMETER(2U, 2U).ref();
296         PARAMETER(3U, 3U).s32();
297 
298         BASIC_BLOCK(2U, -1L)
299         {
300             // NOLINTNEXTLINE(google-build-using-namespace)
301             using namespace compiler::DataType;
302 
303             INST(4U, Opcode::SaveState).NoVregs();
304             INST(6U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 0U}, {NO_TYPE, 4U}});
305             INST(9U, Opcode::StoreObject).ref().Inputs(0U, 2U);
306             INST(12U, Opcode::StoreObject).s32().Inputs(0U, 3U);
307             INST(15U, Opcode::LoadObject).ref().Inputs(1U);
308             INST(16U, Opcode::SaveState).NoVregs();
309             INST(18U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 15U}, {NO_TYPE, 16U}});
310             INST(60U, Opcode::SaveState).NoVregs();
311             INST(21U, Opcode::LoadClass).ref().Inputs(60U);
312             INST(20U, Opcode::CheckCast).Inputs(18U, 21U, 60U);
313             INST(23U, Opcode::StoreObject).ref().Inputs(0U, 18U);
314             INST(26U, Opcode::LoadObject).ref().Inputs(1U);
315             INST(27U, Opcode::SaveState).NoVregs();
316             INST(29U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 26U}, {NO_TYPE, 27U}});
317             INST(63U, Opcode::SaveState).NoVregs();
318             INST(32U, Opcode::LoadClass).ref().Inputs(63U);
319             INST(31U, Opcode::CheckCast).Inputs(29U, 32U, 63U);
320             INST(34U, Opcode::StoreObject).ref().Inputs(0U, 29U);
321             INST(37U, Opcode::LoadObject).ref().Inputs(1U);
322             INST(38U, Opcode::SaveState).NoVregs();
323             INST(40U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 37U}, {NO_TYPE, 38U}});
324             INST(41U, Opcode::SaveState).NoVregs();
325             INST(43U, Opcode::LoadClass).ref().Inputs(41U);
326             INST(42U, Opcode::CheckCast).Inputs(40U, 43U, 41U);
327             INST(45U, Opcode::StoreObject).ref().Inputs(0U, 40U);
328             INST(48U, Opcode::LoadObject).ref().Inputs(1U);
329             INST(49U, Opcode::SaveState).NoVregs();
330             INST(51U, Opcode::CallVirtual).ref().Inputs({{REFERENCE, 48U}, {NO_TYPE, 49U}});
331             INST(52U, Opcode::SaveState).NoVregs();
332             INST(54U, Opcode::LoadClass).ref().Inputs(52U);
333             INST(53U, Opcode::CheckCast).Inputs(51U, 54U, 52U);
334             INST(56U, Opcode::StoreObject).ref().Inputs(0U, 51U);
335             INST(57U, Opcode::ReturnVoid).v0id();
336         }
337     }
338 
339     EXPECT_TRUE(GraphComparator().Compare(graph, expected));
340 }
341 
342 // Check processing instructions with the same args by RegEncoder.
TEST_F(CommonTest,RegEncoderSameArgsInst)343 TEST_F(CommonTest, RegEncoderSameArgsInst)
344 {
345     auto srcGraph = CreateEmptyGraph();
346     ArenaVector<bool> regMask(254U, false, srcGraph->GetLocalAllocator()->Adapter());
347     srcGraph->InitUsedRegs<compiler::DataType::INT64>(&regMask);
348     GRAPH(srcGraph)
349     {
350         PARAMETER(0U, 0U).ref();
351         PARAMETER(1U, 1U).s32();
352         PARAMETER(2U, 2U).s32();
353         BASIC_BLOCK(2U, -1L)
354         {
355             INST(3U, Opcode::StoreArray).s32().Inputs(0U, 1U, 2U).SrcReg(0U, 17U).SrcReg(1U, 17U).SrcReg(2U, 5U);
356             INST(4U, Opcode::ReturnVoid).v0id();
357         }
358     }
359 
360     srcGraph->RunPass<RegEncoder>();
361 
362     auto optGraph = CreateEmptyGraph();
363     optGraph->InitUsedRegs<compiler::DataType::INT64>(&regMask);
364     GRAPH(optGraph)
365     {
366         PARAMETER(0U, 0U).ref();
367         PARAMETER(1U, 1U).s32();
368         PARAMETER(2U, 2U).s32();
369         BASIC_BLOCK(2U, -1L)
370         {
371             INST(3U, Opcode::SpillFill);
372             INST(4U, Opcode::StoreArray).s32().Inputs(0U, 1U, 2U);
373             INST(5U, Opcode::ReturnVoid).v0id();
374         }
375     }
376 
377     ASSERT_TRUE(GraphComparator().Compare(srcGraph, optGraph));
378 
379     for (auto bb : srcGraph->GetBlocksRPO()) {
380         for (auto inst : bb->AllInstsSafe()) {
381             if (inst->GetOpcode() == Opcode::StoreArray) {
382                 ASSERT_TRUE(inst->GetSrcReg(0U) == inst->GetSrcReg(1U));
383             }
384         }
385     }
386 }
387 
388 // NOLINTEND(readability-magic-numbers)
389 
390 }  // namespace ark::bytecodeopt::test
391