• 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 
TEST_F(LoweringTest,AddSub)83 TEST_F(LoweringTest, AddSub)
84 {
85     auto init = CreateEmptyGraph();
86     GRAPH(init)
87     {
88         PARAMETER(0U, 0U).u32();
89         PARAMETER(1U, 1U).u64();
90         PARAMETER(2U, 2U).f32();
91         CONSTANT(3U, 12U).s32();
92         CONSTANT(4U, 150U).s32();
93         CONSTANT(5U, 0U).s64();
94         CONSTANT(6U, 1.2F).f32();
95         CONSTANT(7U, -1L).s32();
96 
97         BASIC_BLOCK(2U, -1L)
98         {
99             INST(8U, Opcode::Add).u32().Inputs(0U, 3U);
100             INST(9U, Opcode::Sub).u32().Inputs(0U, 3U);
101             INST(10U, Opcode::Add).u32().Inputs(0U, 4U);
102             INST(11U, Opcode::Sub).u32().Inputs(0U, 4U);
103             INST(12U, Opcode::Add).u64().Inputs(1U, 5U);
104             INST(13U, Opcode::Sub).f32().Inputs(2U, 6U);
105             INST(14U, Opcode::Sub).u32().Inputs(0U, 7U);
106             INST(15U, Opcode::SaveState).NoVregs();
107             INST(20U, Opcode::CallStatic).b().InputsAutoType(8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U);
108             INST(21U, Opcode::Return).b().Inputs(20U);
109         }
110     }
111 #ifndef NDEBUG
112     init->SetLowLevelInstructionsEnabled();
113 #endif
114     init->RunPass<compiler::Lowering>();
115     init->RunPass<compiler::Cleanup>();
116 
117     auto expected = CreateEmptyGraph();
118     GRAPH(expected)
119     {
120         PARAMETER(0U, 0U).u32();
121         PARAMETER(1U, 1U).u64();
122         PARAMETER(2U, 2U).f32();
123         CONSTANT(4U, 150U).s32();
124         CONSTANT(5U, 0U).s64();
125         CONSTANT(6U, 1.2F).f32();
126 
127         BASIC_BLOCK(2U, -1L)
128         {
129             INST(22U, Opcode::AddI).u32().Inputs(0U).Imm(0xcU);
130             INST(23U, Opcode::SubI).u32().Inputs(0U).Imm(0xcU);
131             INST(10U, Opcode::Add).u32().Inputs(0U, 4U);
132             INST(11U, Opcode::Sub).u32().Inputs(0U, 4U);
133             INST(12U, Opcode::Add).u64().Inputs(1U, 5U);
134             INST(13U, Opcode::Sub).f32().Inputs(2U, 6U);
135             INST(24U, Opcode::AddI).u32().Inputs(0U).Imm(1U);
136             INST(19U, Opcode::SaveState).NoVregs();
137             INST(20U, Opcode::CallStatic).b().InputsAutoType(22U, 23U, 10U, 11U, 12U, 13U, 24U, 19U);
138             INST(21U, Opcode::Return).b().Inputs(20U);
139         }
140     }
141     EXPECT_TRUE(GraphComparator().Compare(init, expected));
142 }
143 
TEST_F(LoweringTest,MulDivMod)144 TEST_F(LoweringTest, MulDivMod)
145 {
146     auto init = CreateEmptyGraph();
147     GRAPH(init)
148     {
149         PARAMETER(0U, 0U).u32();
150         PARAMETER(1U, 1U).u64();
151         PARAMETER(2U, 2U).f32();
152         CONSTANT(3U, 12U).s32();
153         CONSTANT(4U, 150U).s32();
154         CONSTANT(5U, 0U).s64();
155         CONSTANT(6U, 1.2F).f32();
156         CONSTANT(7U, -1L).s32();
157 
158         BASIC_BLOCK(2U, -1L)
159         {
160             INST(8U, Opcode::Div).s32().Inputs(0U, 3U);
161             INST(9U, Opcode::Div).u32().Inputs(0U, 4U);
162             INST(10U, Opcode::Div).u64().Inputs(1U, 5U);
163             INST(11U, Opcode::Div).f32().Inputs(2U, 6U);
164             INST(12U, Opcode::Div).s32().Inputs(0U, 7U);
165 
166             INST(13U, Opcode::Mod).s32().Inputs(0U, 3U);
167             INST(14U, Opcode::Mod).u32().Inputs(0U, 4U);
168             INST(15U, Opcode::Mod).u64().Inputs(1U, 5U);
169             INST(16U, Opcode::Mod).f32().Inputs(2U, 6U);
170             INST(17U, Opcode::Mod).s32().Inputs(0U, 7U);
171 
172             INST(18U, Opcode::Mul).s32().Inputs(0U, 3U);
173             INST(19U, Opcode::Mul).u32().Inputs(0U, 4U);
174             INST(20U, Opcode::Mul).u64().Inputs(1U, 5U);
175             INST(21U, Opcode::Mul).f32().Inputs(2U, 6U);
176             INST(22U, Opcode::Mul).s32().Inputs(0U, 7U);
177             INST(31U, Opcode::SaveState).NoVregs();
178             INST(23U, Opcode::CallStatic)
179                 .b()
180                 .InputsAutoType(8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U, 16U, 17U, 18U, 19U, 20U, 21U, 22U, 31U);
181             INST(24U, Opcode::Return).b().Inputs(23U);
182         }
183     }
184 
185 #ifndef NDEBUG
186     init->SetLowLevelInstructionsEnabled();
187 #endif
188     init->RunPass<compiler::Lowering>();
189     init->RunPass<compiler::Cleanup>();
190 
191     auto expected = CreateEmptyGraph();
192     GRAPH(expected)
193     {
194         PARAMETER(0U, 0U).u32();
195         PARAMETER(1U, 1U).u64();
196         PARAMETER(2U, 2U).f32();
197         CONSTANT(4U, 150U).s32();
198         CONSTANT(5U, 0U).s64();
199         CONSTANT(6U, 1.2F).f32();
200 
201         BASIC_BLOCK(2U, -1L)
202         {
203             INST(25U, Opcode::DivI).s32().Inputs(0U).Imm(0xcU);
204             INST(9U, Opcode::Div).u32().Inputs(0U, 4U);
205             INST(10U, Opcode::Div).u64().Inputs(1U, 5U);
206             INST(11U, Opcode::Div).f32().Inputs(2U, 6U);
207             INST(26U, Opcode::DivI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
208             INST(27U, Opcode::ModI).s32().Inputs(0U).Imm(0xcU);
209             INST(14U, Opcode::Mod).u32().Inputs(0U, 4U);
210             INST(15U, Opcode::Mod).u64().Inputs(1U, 5U);
211             INST(16U, Opcode::Mod).f32().Inputs(2U, 6U);
212             INST(28U, Opcode::ModI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
213             INST(29U, Opcode::MulI).s32().Inputs(0U).Imm(0xcU);
214             INST(19U, Opcode::Mul).u32().Inputs(0U, 4U);
215             INST(20U, Opcode::Mul).u64().Inputs(1U, 5U);
216             INST(21U, Opcode::Mul).f32().Inputs(2U, 6U);
217             INST(30U, Opcode::MulI).s32().Inputs(0U).Imm(static_cast<uint64_t>(-1L));
218             INST(31U, Opcode::SaveState).NoVregs();
219             INST(23U, Opcode::CallStatic)
220                 .b()
221                 .InputsAutoType(25U, 9U, 10U, 11U, 26U, 27U, 14U, 15U, 16U, 28U, 29U, 19U, 20U, 21U, 30U, 31U);
222             INST(24U, Opcode::Return).b().Inputs(23U);
223         }
224     }
225     EXPECT_TRUE(GraphComparator().Compare(init, expected));
226 }
227 
TEST_F(LoweringTest,Logic)228 TEST_F(LoweringTest, Logic)
229 {
230     auto init = CreateEmptyGraph();
231     GRAPH(init)
232     {
233         PARAMETER(0U, 0U).u32();
234         PARAMETER(24U, 1U).s64();
235         CONSTANT(1U, 12U).s32();
236         CONSTANT(2U, 50U).s32();
237         CONSTANT(25U, 0U).s64();
238         CONSTANT(27U, 300U).s32();
239 
240         BASIC_BLOCK(2U, -1L)
241         {
242             INST(3U, Opcode::Or).u32().Inputs(0U, 1U);
243             INST(5U, Opcode::Or).u32().Inputs(0U, 2U);
244             INST(6U, Opcode::And).u32().Inputs(0U, 1U);
245             INST(8U, Opcode::And).u32().Inputs(0U, 2U);
246             INST(9U, Opcode::Xor).u32().Inputs(0U, 1U);
247             INST(11U, Opcode::Xor).u32().Inputs(0U, 2U);
248             INST(12U, Opcode::Or).u8().Inputs(0U, 1U);
249             INST(13U, Opcode::And).u32().Inputs(0U, 0U);
250             INST(26U, Opcode::And).s64().Inputs(24U, 25U);
251             INST(28U, Opcode::Xor).u32().Inputs(0U, 27U);
252             INST(29U, Opcode::Or).s64().Inputs(24U, 25U);
253             INST(30U, Opcode::Xor).s64().Inputs(24U, 25U);
254             INST(31U, Opcode::And).u32().Inputs(0U, 27U);
255             INST(32U, Opcode::Or).u32().Inputs(0U, 27U);
256             INST(15U, Opcode::SaveState).NoVregs();
257             INST(14U, Opcode::CallStatic)
258                 .b()
259                 .InputsAutoType(3U, 5U, 6U, 8U, 9U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
260             INST(23U, Opcode::Return).b().Inputs(14U);
261         }
262     }
263 
264 #ifndef NDEBUG
265     init->SetLowLevelInstructionsEnabled();
266 #endif
267     init->RunPass<compiler::Lowering>();
268     init->RunPass<compiler::Cleanup>();
269 
270     auto expected = CreateEmptyGraph();
271     GRAPH(expected)
272     {
273         PARAMETER(0U, 0U).u32();
274         PARAMETER(24U, 1U).s64();
275         CONSTANT(1U, 12U).s32();
276         CONSTANT(25U, 0U).s64();
277 
278         BASIC_BLOCK(2U, -1L)
279         {
280             INST(33U, Opcode::OrI).u32().Inputs(0U).Imm(0xcU);
281             INST(34U, Opcode::OrI).u32().Inputs(0U).Imm(0x32U);
282             INST(35U, Opcode::AndI).u32().Inputs(0U).Imm(0xcU);
283             INST(36U, Opcode::AndI).u32().Inputs(0U).Imm(0x32U);
284             INST(37U, Opcode::XorI).u32().Inputs(0U).Imm(0xcU);
285             INST(38U, Opcode::XorI).u32().Inputs(0U).Imm(0x32U);
286             INST(12U, Opcode::Or).u8().Inputs(0U, 1U);
287             INST(13U, Opcode::And).u32().Inputs(0U, 0U);
288             INST(26U, Opcode::And).s64().Inputs(24U, 25U);
289             INST(39U, Opcode::XorI).u32().Inputs(0U).Imm(0x12cU);
290             INST(29U, Opcode::Or).s64().Inputs(24U, 25U);
291             INST(30U, Opcode::Xor).s64().Inputs(24U, 25U);
292             INST(40U, Opcode::AndI).u32().Inputs(0U).Imm(0x12cU);
293             INST(41U, Opcode::OrI).u32().Inputs(0U).Imm(0x12cU);
294             INST(15U, Opcode::SaveState).NoVregs();
295             INST(14U, Opcode::CallStatic)
296                 .b()
297                 .InputsAutoType(33U, 34U, 35U, 36U, 37U, 38U, 12U, 13U, 26U, 39U, 29U, 30U, 40U, 41U, 15U);
298             INST(23U, Opcode::Return).b().Inputs(14U);
299         }
300     }
301     EXPECT_TRUE(GraphComparator().Compare(init, expected));
302 }
303 
TEST_F(LoweringTest,Shift)304 TEST_F(LoweringTest, Shift)
305 {
306     auto init = CreateEmptyGraph();
307     GRAPH(init)
308     {
309         PARAMETER(0U, 0U).u32();
310         PARAMETER(24U, 1U).s64();
311         CONSTANT(1U, 12U).s32();
312         CONSTANT(2U, 64U).s32();
313         CONSTANT(25U, 0U).s64();
314         CONSTANT(27U, 200U).s32();
315 
316         BASIC_BLOCK(2U, -1L)
317         {
318             INST(3U, Opcode::Shr).u32().Inputs(0U, 1U);
319             INST(5U, Opcode::Shr).u32().Inputs(0U, 2U);
320             INST(6U, Opcode::AShr).u32().Inputs(0U, 1U);
321             INST(8U, Opcode::AShr).u32().Inputs(0U, 2U);
322             INST(9U, Opcode::Shl).u32().Inputs(0U, 1U);
323             INST(11U, Opcode::Shl).u32().Inputs(0U, 2U);
324             INST(12U, Opcode::Shl).u8().Inputs(0U, 1U);
325             INST(13U, Opcode::Shr).u32().Inputs(0U, 0U);
326             INST(26U, Opcode::Shr).s64().Inputs(24U, 25U);
327             INST(28U, Opcode::AShr).s32().Inputs(0U, 27U);
328             INST(29U, Opcode::AShr).s64().Inputs(24U, 25U);
329             INST(30U, Opcode::Shl).s64().Inputs(24U, 25U);
330             INST(31U, Opcode::Shr).s32().Inputs(0U, 27U);
331             INST(32U, Opcode::Shl).s32().Inputs(0U, 27U);
332             INST(15U, Opcode::SaveState).NoVregs();
333             INST(14U, Opcode::CallStatic)
334                 .b()
335                 .InputsAutoType(3U, 5U, 6U, 8U, 9U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
336             INST(23U, Opcode::Return).b().Inputs(14U);
337         }
338     }
339 #ifndef NDEBUG
340     init->SetLowLevelInstructionsEnabled();
341 #endif
342     init->RunPass<compiler::Lowering>();
343     init->RunPass<compiler::Cleanup>();
344 
345     auto expected = CreateEmptyGraph();
346     GRAPH(expected)
347     {
348         PARAMETER(0U, 0U).u32();
349         PARAMETER(24U, 1U).s64();
350         CONSTANT(1U, 12U).s32();
351         CONSTANT(2U, 64U).s32();
352         CONSTANT(25U, 0U).s64();
353         CONSTANT(27U, 200U).s32();
354 
355         BASIC_BLOCK(2U, -1L)
356         {
357             INST(33U, Opcode::ShrI).u32().Inputs(0U).Imm(0xcU);
358             INST(5U, Opcode::Shr).u32().Inputs(0U, 2U);
359             INST(34U, Opcode::AShrI).u32().Inputs(0U).Imm(0xcU);
360             INST(8U, Opcode::AShr).u32().Inputs(0U, 2U);
361             INST(35U, Opcode::ShlI).u32().Inputs(0U).Imm(0xcU);
362             INST(11U, Opcode::Shl).u32().Inputs(0U, 2U);
363             INST(12U, Opcode::Shl).u8().Inputs(0U, 1U);
364             INST(13U, Opcode::Shr).u32().Inputs(0U, 0U);
365             INST(26U, Opcode::Shr).s64().Inputs(24U, 25U);
366             INST(28U, Opcode::AShr).s32().Inputs(0U, 27U);
367             INST(29U, Opcode::AShr).s64().Inputs(24U, 25U);
368             INST(30U, Opcode::Shl).s64().Inputs(24U, 25U);
369             INST(31U, Opcode::Shr).s32().Inputs(0U, 27U);
370             INST(32U, Opcode::Shl).s32().Inputs(0U, 27U);
371             INST(15U, Opcode::SaveState).NoVregs();
372             INST(14U, Opcode::CallStatic)
373                 .b()
374                 .InputsAutoType(33U, 5U, 34U, 8U, 35U, 11U, 12U, 13U, 26U, 28U, 29U, 30U, 31U, 32U, 15U);
375             INST(23U, Opcode::Return).b().Inputs(14U);
376         }
377     }
378     EXPECT_TRUE(GraphComparator().Compare(init, expected));
379 }
380 
381 // NOLINTEND(readability-magic-numbers)
382 
383 }  // namespace ark::bytecodeopt::test
384