• 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 "libpandabase/utils/utils.h"
17 #include "common.h"
18 #include "check_resolver.h"
19 #include "compiler/optimizer/optimizations/cleanup.h"
20 #include "compiler/optimizer/optimizations/lowering.h"
21 
22 namespace ark::bytecodeopt::test {
23 
24 class LoweringTest : public CommonTest {};
25 
26 // NOLINTBEGIN(readability-magic-numbers)
27 
28 // Checks the results of lowering pass if negative operands are used
TEST_F(IrBuilderTest,Lowering)29 TEST_F(IrBuilderTest, Lowering)
30 {
31     // ISA opcodes with expected lowering IR opcodes
32     std::map<std::string, compiler::Opcode> opcodes = {
33         {"add", compiler::Opcode::SubI}, {"sub", compiler::Opcode::AddI}, {"mul", compiler::Opcode::MulI},
34         {"and", compiler::Opcode::AndI}, {"xor", compiler::Opcode::XorI}, {"or", compiler::Opcode::OrI},
35         {"div", compiler::Opcode::DivI}, {"mod", compiler::Opcode::ModI},
36     };
37 
38     const std::string templateSource = R"(
39     .function i32 main() {
40         movi v0, 0x3
41         movi v1, 0xffffffffffffffe2
42         OPCODE v0, v1
43         return
44     }
45     )";
46 
47     for (auto const &opcode : opcodes) {
48         // Specialize template source to the current opcode
49         std::string source(templateSource);
50         size_t startPos = source.find("OPCODE");
51         source.replace(startPos, 6U, opcode.first);
52 
53         ASSERT_TRUE(ParseToGraph(source, "main"));
54 #ifndef NDEBUG
55         GetGraph()->SetLowLevelInstructionsEnabled();
56 #endif
57         GetGraph()->RunPass<CheckResolver>();
58         GetGraph()->RunPass<compiler::Lowering>();
59         GetGraph()->RunPass<compiler::Cleanup>();
60 
61         int32_t imm = -30_I;
62         // Note: `AddI -30` is handled as `SubI 30`. `SubI -30` is handled as `AddI 30`.
63         if (opcode.second == compiler::Opcode::AddI || opcode.second == compiler::Opcode::SubI) {
64             imm = 30_I;
65         }
66 
67         auto expected = CreateEmptyGraph();
68         GRAPH(expected)
69         {
70             CONSTANT(1U, 3U).s32();
71 
72             BASIC_BLOCK(2U, -1L)
73             {
74                 INST(2U, opcode.second).s32().Inputs(1U).Imm(imm);
75                 INST(3U, Opcode::Return).s32().Inputs(2U);
76             }
77         }
78 
79         EXPECT_TRUE(GraphComparator().Compare(GetGraph(), expected));
80     }
81 }
82 
83 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
TEST_F(LoweringTest,AddSub)84 TEST_F(LoweringTest, AddSub)
85 {
86     auto init = CreateEmptyGraph();
87     GRAPH(init)
88     {
89         PARAMETER(0U, 0U).u32();
90         PARAMETER(1U, 1U).u64();
91         PARAMETER(2U, 2U).f32();
92         CONSTANT(3U, 12U).s32();
93         CONSTANT(4U, 150U).s32();
94         CONSTANT(5U, 0U).s64();
95         CONSTANT(6U, 1.2F).f32();
96         CONSTANT(7U, -1L).s32();
97 
98         BASIC_BLOCK(2U, -1L)
99         {
100             INST(8U, Opcode::Add).u32().Inputs(0U, 3U);
101             INST(9U, Opcode::Sub).u32().Inputs(0U, 3U);
102             INST(10U, Opcode::Add).u32().Inputs(0U, 4U);
103             INST(11U, Opcode::Sub).u32().Inputs(0U, 4U);
104             INST(12U, Opcode::Add).u64().Inputs(1U, 5U);
105             INST(13U, Opcode::Sub).f32().Inputs(2U, 6U);
106             INST(14U, Opcode::Sub).u32().Inputs(0U, 7U);
107             INST(15U, Opcode::SaveState).NoVregs();
108             INST(20U, Opcode::CallStatic).b().InputsAutoType(8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U);
109             INST(21U, Opcode::Return).b().Inputs(20U);
110         }
111     }
112 #ifndef NDEBUG
113     init->SetLowLevelInstructionsEnabled();
114 #endif
115     init->RunPass<compiler::Lowering>();
116     init->RunPass<compiler::Cleanup>();
117 
118     auto expected = CreateEmptyGraph();
119     GRAPH(expected)
120     {
121         PARAMETER(0U, 0U).u32();
122         PARAMETER(1U, 1U).u64();
123         PARAMETER(2U, 2U).f32();
124         CONSTANT(4U, 150U).s32();
125         CONSTANT(5U, 0U).s64();
126         CONSTANT(6U, 1.2F).f32();
127 
128         BASIC_BLOCK(2U, -1L)
129         {
130             INST(22U, Opcode::AddI).u32().Inputs(0U).Imm(0xcU);
131             INST(23U, Opcode::SubI).u32().Inputs(0U).Imm(0xcU);
132             INST(10U, Opcode::Add).u32().Inputs(0U, 4U);
133             INST(11U, Opcode::Sub).u32().Inputs(0U, 4U);
134             INST(12U, Opcode::Add).u64().Inputs(1U, 5U);
135             INST(13U, Opcode::Sub).f32().Inputs(2U, 6U);
136             INST(24U, Opcode::AddI).u32().Inputs(0U).Imm(1U);
137             INST(19U, Opcode::SaveState).NoVregs();
138             INST(20U, Opcode::CallStatic).b().InputsAutoType(22U, 23U, 10U, 11U, 12U, 13U, 24U, 19U);
139             INST(21U, Opcode::Return).b().Inputs(20U);
140         }
141     }
142     EXPECT_TRUE(GraphComparator().Compare(init, expected));
143 }
144 
145 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
TEST_F(LoweringTest,MulDivMod)146 TEST_F(LoweringTest, MulDivMod)
147 {
148     auto init = CreateEmptyGraph();
149     GRAPH(init)
150     {
151         PARAMETER(0U, 0U).u32();
152         PARAMETER(1U, 1U).u64();
153         PARAMETER(2U, 2U).f32();
154         CONSTANT(3U, 12U).s32();
155         CONSTANT(4U, 150U).s32();
156         CONSTANT(5U, 0U).s64();
157         CONSTANT(6U, 1.2F).f32();
158         CONSTANT(7U, -1L).s32();
159 
160         BASIC_BLOCK(2U, -1L)
161         {
162             INST(8U, Opcode::Div).s32().Inputs(0U, 3U);
163             INST(9U, Opcode::Div).u32().Inputs(0U, 4U);
164             INST(10U, Opcode::Div).u64().Inputs(1U, 5U);
165             INST(11U, Opcode::Div).f32().Inputs(2U, 6U);
166             INST(12U, Opcode::Div).s32().Inputs(0U, 7U);
167 
168             INST(13U, Opcode::Mod).s32().Inputs(0U, 3U);
169             INST(14U, Opcode::Mod).u32().Inputs(0U, 4U);
170             INST(15U, Opcode::Mod).u64().Inputs(1U, 5U);
171             INST(16U, Opcode::Mod).f32().Inputs(2U, 6U);
172             INST(17U, Opcode::Mod).s32().Inputs(0U, 7U);
173 
174             INST(18U, Opcode::Mul).s32().Inputs(0U, 3U);
175             INST(19U, Opcode::Mul).u32().Inputs(0U, 4U);
176             INST(20U, Opcode::Mul).u64().Inputs(1U, 5U);
177             INST(21U, Opcode::Mul).f32().Inputs(2U, 6U);
178             INST(22U, Opcode::Mul).s32().Inputs(0U, 7U);
179             INST(31U, Opcode::SaveState).NoVregs();
180             INST(23U, Opcode::CallStatic)
181                 .b()
182                 .InputsAutoType(8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U, 16U, 17U, 18U, 19U, 20U, 21U, 22U, 31U);
183             INST(24U, Opcode::Return).b().Inputs(23U);
184         }
185     }
186 
187 #ifndef NDEBUG
188     init->SetLowLevelInstructionsEnabled();
189 #endif
190     init->RunPass<compiler::Lowering>();
191     init->RunPass<compiler::Cleanup>();
192 
193     auto expected = CreateEmptyGraph();
194     GRAPH(expected)
195     {
196         PARAMETER(0U, 0U).u32();
197         PARAMETER(1U, 1U).u64();
198         PARAMETER(2U, 2U).f32();
199         CONSTANT(4U, 150U).s32();
200         CONSTANT(5U, 0U).s64();
201         CONSTANT(6U, 1.2F).f32();
202 
203         BASIC_BLOCK(2U, -1L)
204         {
205             INST(25U, Opcode::DivI).s32().Inputs(0U).Imm(0xcU);
206             INST(9U, Opcode::Div).u32().Inputs(0U, 4U);
207             INST(10U, Opcode::Div).u64().Inputs(1U, 5U);
208             INST(11U, Opcode::Div).f32().Inputs(2U, 6U);
209             INST(26U, Opcode::DivI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
210             INST(27U, Opcode::ModI).s32().Inputs(0U).Imm(0xcU);
211             INST(14U, Opcode::Mod).u32().Inputs(0U, 4U);
212             INST(15U, Opcode::Mod).u64().Inputs(1U, 5U);
213             INST(16U, Opcode::Mod).f32().Inputs(2U, 6U);
214             INST(28U, Opcode::ModI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
215             INST(29U, Opcode::MulI).s32().Inputs(0U).Imm(0xcU);
216             INST(19U, Opcode::Mul).u32().Inputs(0U, 4U);
217             INST(20U, Opcode::Mul).u64().Inputs(1U, 5U);
218             INST(21U, Opcode::Mul).f32().Inputs(2U, 6U);
219             INST(30U, Opcode::MulI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
220             INST(31U, Opcode::SaveState).NoVregs();
221             INST(23U, Opcode::CallStatic)
222                 .b()
223                 .InputsAutoType(25U, 9U, 10U, 11U, 26U, 27U, 14U, 15U, 16U, 28U, 29U, 19U, 20U, 21U, 30U, 31U);
224             INST(24U, Opcode::Return).b().Inputs(23U);
225         }
226     }
227     EXPECT_TRUE(GraphComparator().Compare(init, expected));
228 }
229 
230 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
TEST_F(LoweringTest,Logic)231 TEST_F(LoweringTest, Logic)
232 {
233     auto init = CreateEmptyGraph();
234     GRAPH(init)
235     {
236         PARAMETER(0U, 0U).u32();
237         PARAMETER(24U, 1U).s64();
238         CONSTANT(1U, 12U).s32();
239         CONSTANT(2U, 50U).s32();
240         CONSTANT(25U, 0U).s64();
241         CONSTANT(27U, 300U).s32();
242 
243         BASIC_BLOCK(2U, -1L)
244         {
245             INST(3U, Opcode::Or).u32().Inputs(0U, 1U);
246             INST(5U, Opcode::Or).u32().Inputs(0U, 2U);
247             INST(6U, Opcode::And).u32().Inputs(0U, 1U);
248             INST(8U, Opcode::And).u32().Inputs(0U, 2U);
249             INST(9U, Opcode::Xor).u32().Inputs(0U, 1U);
250             INST(11U, Opcode::Xor).u32().Inputs(0U, 2U);
251             INST(12U, Opcode::Or).u8().Inputs(0U, 1U);
252             INST(13U, Opcode::And).u32().Inputs(0U, 0U);
253             INST(26U, Opcode::And).s64().Inputs(24U, 25U);
254             INST(28U, Opcode::Xor).u32().Inputs(0U, 27U);
255             INST(29U, Opcode::Or).s64().Inputs(24U, 25U);
256             INST(30U, Opcode::Xor).s64().Inputs(24U, 25U);
257             INST(31U, Opcode::And).u32().Inputs(0U, 27U);
258             INST(32U, Opcode::Or).u32().Inputs(0U, 27U);
259             INST(15U, Opcode::SaveState).NoVregs();
260             INST(14U, Opcode::CallStatic)
261                 .b()
262                 .InputsAutoType(3U, 5U, 6U, 8U, 9U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
263             INST(23U, Opcode::Return).b().Inputs(14U);
264         }
265     }
266 
267 #ifndef NDEBUG
268     init->SetLowLevelInstructionsEnabled();
269 #endif
270     init->RunPass<compiler::Lowering>();
271     init->RunPass<compiler::Cleanup>();
272 
273     auto expected = CreateEmptyGraph();
274     GRAPH(expected)
275     {
276         PARAMETER(0U, 0U).u32();
277         PARAMETER(24U, 1U).s64();
278         CONSTANT(1U, 12U).s32();
279         CONSTANT(25U, 0U).s64();
280 
281         BASIC_BLOCK(2U, -1L)
282         {
283             INST(33U, Opcode::OrI).u32().Inputs(0U).Imm(0xcU);
284             INST(34U, Opcode::OrI).u32().Inputs(0U).Imm(0x32U);
285             INST(35U, Opcode::AndI).u32().Inputs(0U).Imm(0xcU);
286             INST(36U, Opcode::AndI).u32().Inputs(0U).Imm(0x32U);
287             INST(37U, Opcode::XorI).u32().Inputs(0U).Imm(0xcU);
288             INST(38U, Opcode::XorI).u32().Inputs(0U).Imm(0x32U);
289             INST(12U, Opcode::Or).u8().Inputs(0U, 1U);
290             INST(13U, Opcode::And).u32().Inputs(0U, 0U);
291             INST(26U, Opcode::And).s64().Inputs(24U, 25U);
292             INST(39U, Opcode::XorI).u32().Inputs(0U).Imm(0x12cU);
293             INST(29U, Opcode::Or).s64().Inputs(24U, 25U);
294             INST(30U, Opcode::Xor).s64().Inputs(24U, 25U);
295             INST(40U, Opcode::AndI).u32().Inputs(0U).Imm(0x12cU);
296             INST(41U, Opcode::OrI).u32().Inputs(0U).Imm(0x12cU);
297             INST(15U, Opcode::SaveState).NoVregs();
298             INST(14U, Opcode::CallStatic)
299                 .b()
300                 .InputsAutoType(33U, 34U, 35U, 36U, 37U, 38U, 12U, 13U, 26U, 39U, 29U, 30U, 40U, 41U, 15U);
301             INST(23U, Opcode::Return).b().Inputs(14U);
302         }
303     }
304     EXPECT_TRUE(GraphComparator().Compare(init, expected));
305 }
306 
307 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
TEST_F(LoweringTest,Shift)308 TEST_F(LoweringTest, Shift)
309 {
310     auto init = CreateEmptyGraph();
311     GRAPH(init)
312     {
313         PARAMETER(0U, 0U).u32();
314         PARAMETER(24U, 1U).s64();
315         CONSTANT(1U, 12U).s32();
316         CONSTANT(2U, 64U).s32();
317         CONSTANT(25U, 0U).s64();
318         CONSTANT(27U, 200U).s32();
319 
320         BASIC_BLOCK(2U, -1L)
321         {
322             INST(3U, Opcode::Shr).u32().Inputs(0U, 1U);
323             INST(5U, Opcode::Shr).u32().Inputs(0U, 2U);
324             INST(6U, Opcode::AShr).u32().Inputs(0U, 1U);
325             INST(8U, Opcode::AShr).u32().Inputs(0U, 2U);
326             INST(9U, Opcode::Shl).u32().Inputs(0U, 1U);
327             INST(11U, Opcode::Shl).u32().Inputs(0U, 2U);
328             INST(12U, Opcode::Shl).u8().Inputs(0U, 1U);
329             INST(13U, Opcode::Shr).u32().Inputs(0U, 0U);
330             INST(26U, Opcode::Shr).s64().Inputs(24U, 25U);
331             INST(28U, Opcode::AShr).s32().Inputs(0U, 27U);
332             INST(29U, Opcode::AShr).s64().Inputs(24U, 25U);
333             INST(30U, Opcode::Shl).s64().Inputs(24U, 25U);
334             INST(31U, Opcode::Shr).s32().Inputs(0U, 27U);
335             INST(32U, Opcode::Shl).s32().Inputs(0U, 27U);
336             INST(15U, Opcode::SaveState).NoVregs();
337             INST(14U, Opcode::CallStatic)
338                 .b()
339                 .InputsAutoType(3U, 5U, 6U, 8U, 9U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
340             INST(23U, Opcode::Return).b().Inputs(14U);
341         }
342     }
343 #ifndef NDEBUG
344     init->SetLowLevelInstructionsEnabled();
345 #endif
346     init->RunPass<compiler::Lowering>();
347     init->RunPass<compiler::Cleanup>();
348 
349     auto expected = CreateEmptyGraph();
350     GRAPH(expected)
351     {
352         PARAMETER(0U, 0U).u32();
353         PARAMETER(24U, 1U).s64();
354         CONSTANT(1U, 12U).s32();
355         CONSTANT(2U, 64U).s32();
356         CONSTANT(25U, 0U).s64();
357         CONSTANT(27U, 200U).s32();
358 
359         BASIC_BLOCK(2U, -1L)
360         {
361             INST(33U, Opcode::ShrI).u32().Inputs(0U).Imm(0xcU);
362             INST(5U, Opcode::Shr).u32().Inputs(0U, 2U);
363             INST(34U, Opcode::AShrI).u32().Inputs(0U).Imm(0xcU);
364             INST(8U, Opcode::AShr).u32().Inputs(0U, 2U);
365             INST(35U, Opcode::ShlI).u32().Inputs(0U).Imm(0xcU);
366             INST(11U, Opcode::Shl).u32().Inputs(0U, 2U);
367             INST(12U, Opcode::Shl).u8().Inputs(0U, 1U);
368             INST(13U, Opcode::Shr).u32().Inputs(0U, 0U);
369             INST(26U, Opcode::Shr).s64().Inputs(24U, 25U);
370             INST(28U, Opcode::AShr).s32().Inputs(0U, 27U);
371             INST(29U, Opcode::AShr).s64().Inputs(24U, 25U);
372             INST(30U, Opcode::Shl).s64().Inputs(24U, 25U);
373             INST(31U, Opcode::Shr).s32().Inputs(0U, 27U);
374             INST(32U, Opcode::Shl).s32().Inputs(0U, 27U);
375             INST(15U, Opcode::SaveState).NoVregs();
376             INST(14U, Opcode::CallStatic)
377                 .b()
378                 .InputsAutoType(33U, 5U, 34U, 8U, 35U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
379             INST(23U, Opcode::Return).b().Inputs(14U);
380         }
381     }
382     EXPECT_TRUE(GraphComparator().Compare(init, expected));
383 }
384 
385 // NOLINTEND(readability-magic-numbers)
386 
387 }  // namespace ark::bytecodeopt::test
388