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 "bytecodeopt_peepholes.h"
17 #include "common.h"
18 #include "compiler/optimizer/optimizations/cleanup.h"
19
20 namespace ark::bytecodeopt::test {
21
22 // NOLINTBEGIN(readability-magic-numbers)
23
TEST_F(IrBuilderTest,PeepholesTryBlockInstBetween)24 TEST_F(IrBuilderTest, PeepholesTryBlockInstBetween)
25 {
26 auto source = R"(
27 .record E {}
28 .record R {
29 u1 field
30 }
31
32 .function void R.ctor(R a0) <ctor> {
33 newobj v0, E
34 throw v0
35 }
36
37 .function u8 main() {
38 try_begin:
39 movi v1, 0x1
40 newobj v0, R
41 movi v1, 0x2
42 call.short R.ctor, v0
43 try_end:
44 ldai 0x0
45 return
46 catch_all:
47 lda v1
48 return
49 .catchall try_begin, try_end, catch_all
50 }
51 )";
52 ASSERT_TRUE(ParseToGraph(source, "main"));
53
54 EXPECT_FALSE(GetGraph()->RunPass<BytecodeOptPeepholes>());
55 }
56
TEST_F(IrBuilderTest,PeepholesTryBlockNoInstBetween)57 TEST_F(IrBuilderTest, PeepholesTryBlockNoInstBetween)
58 {
59 auto source = R"(
60 .record E {}
61 .record R {
62 u1 field
63 }
64
65 .function void R.ctor(R a0) <ctor> {
66 newobj v0, E
67 throw v0
68 }
69
70 .function u8 main() {
71 try_begin:
72 movi v1, 0x1
73 newobj v0, R
74 call.short R.ctor, v0
75 try_end:
76 ldai 0x0
77 return
78 catch_all:
79 lda v1
80 return
81 .catchall try_begin, try_end, catch_all
82 }
83 )";
84 ASSERT_TRUE(ParseToGraph(source, "main"));
85
86 EXPECT_TRUE(GetGraph()->RunPass<BytecodeOptPeepholes>());
87 }
88
89 // NOTE(aromanov): enable
TEST_F(CommonTest,DISABLED_NoNullCheck)90 TEST_F(CommonTest, DISABLED_NoNullCheck)
91 {
92 RuntimeInterfaceMock runtime(0U);
93 auto graph = CreateEmptyGraph();
94 graph->SetRuntime(&runtime);
95 GRAPH(graph)
96 {
97 // NOLINTNEXTLINE(google-build-using-namespace)
98 using namespace compiler::DataType;
99 CONSTANT(6U, 0U);
100 BASIC_BLOCK(2U, -1L)
101 {
102 INST(0U, Opcode::SaveState).NoVregs();
103 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(68U);
104 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U).TypeId(68U);
105 INST(3U, Opcode::SaveState).NoVregs();
106 INST(5U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2U}, {NO_TYPE, 3U}});
107 INST(7U, Opcode::Return).s32().Inputs(6U);
108 }
109 }
110
111 EXPECT_TRUE(graph->RunPass<BytecodeOptPeepholes>());
112 EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
113
114 auto after = CreateEmptyGraph();
115 GRAPH(after)
116 {
117 // NOLINTNEXTLINE(google-build-using-namespace)
118 using namespace compiler::DataType;
119 CONSTANT(6U, 0U);
120 BASIC_BLOCK(2U, -1L)
121 {
122 INST(0U, Opcode::SaveState).NoVregs();
123 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(68U);
124 INST(3U, Opcode::SaveState).NoVregs();
125 INST(8U, Opcode::InitObject).ref().Inputs({{REFERENCE, 1U}, {NO_TYPE, 3U}});
126 INST(7U, Opcode::Return).s32().Inputs(6U);
127 }
128 }
129
130 EXPECT_TRUE(GraphComparator().Compare(graph, after));
131 }
132
133 // NOTE(aromanov): enable
TEST_F(CommonTest,DISABLED_NotRelatedNullCheck)134 TEST_F(CommonTest, DISABLED_NotRelatedNullCheck)
135 {
136 RuntimeInterfaceMock runtime(1U);
137 auto graph = CreateEmptyGraph();
138 graph->SetRuntime(&runtime);
139 GRAPH(graph)
140 {
141 // NOLINTNEXTLINE(google-build-using-namespace)
142 using namespace compiler::DataType;
143 PARAMETER(10U, 0U).ref();
144 CONSTANT(6U, 0U);
145 BASIC_BLOCK(2U, -1L)
146 {
147 INST(0U, Opcode::SaveState).NoVregs();
148 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U);
149 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U);
150 INST(3U, Opcode::SaveState).NoVregs();
151 INST(4U, Opcode::NullCheck).ref().Inputs(10U, 3U);
152 INST(5U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2U}, {NO_TYPE, 3U}});
153 INST(7U, Opcode::Return).s32().Inputs(6U);
154 }
155 }
156
157 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
158 }
159
TEST_F(CommonTest,CallStaticOtherBasicBlock)160 TEST_F(CommonTest, CallStaticOtherBasicBlock)
161 {
162 RuntimeInterfaceMock runtime(1U);
163 auto graph = CreateEmptyGraph();
164 graph->SetRuntime(&runtime);
165 GRAPH(graph)
166 {
167 // NOLINTNEXTLINE(google-build-using-namespace)
168 using namespace compiler::DataType;
169 PARAMETER(10U, 0U).ref();
170 CONSTANT(6U, 0U);
171 BASIC_BLOCK(2U, 3U)
172 {
173 INST(0U, Opcode::SaveState).NoVregs();
174 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U);
175 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U);
176 INST(3U, Opcode::SaveState).NoVregs();
177 }
178 BASIC_BLOCK(3U, -1L)
179 {
180 INST(5U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2U}, {NO_TYPE, 3U}});
181 INST(7U, Opcode::Return).s32().Inputs(6U);
182 }
183 }
184
185 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
186 }
187
188 // NOTE(aromanov): enable
TEST_F(CommonTest,DISABLED_NoSaveStateNullCheckAfterNewObject)189 TEST_F(CommonTest, DISABLED_NoSaveStateNullCheckAfterNewObject)
190 {
191 RuntimeInterfaceMock runtime(0U);
192 auto graph = CreateEmptyGraph();
193 graph->SetRuntime(&runtime);
194 GRAPH(graph)
195 {
196 // NOLINTNEXTLINE(google-build-using-namespace)
197 using namespace compiler::DataType;
198 BASIC_BLOCK(2U, -1L)
199 {
200 INST(0U, Opcode::SaveState).NoVregs();
201 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U);
202 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U);
203 CONSTANT(3U, 0U).s32();
204 INST(4U, Opcode::SaveState).NoVregs();
205 INST(5U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2U}, {NO_TYPE, 4U}});
206 INST(6U, Opcode::ReturnVoid).v0id();
207 }
208 }
209
210 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
211 }
212
TEST_F(CommonTest,CallConstructorOtherClass)213 TEST_F(CommonTest, CallConstructorOtherClass)
214 {
215 RuntimeInterfaceMock runtime(1U, false);
216 auto graph = CreateEmptyGraph();
217 graph->SetRuntime(&runtime);
218 GRAPH(graph)
219 {
220 // NOLINTNEXTLINE(google-build-using-namespace)
221 using namespace compiler::DataType;
222 PARAMETER(10U, 0U).ref();
223 CONSTANT(6U, 0U);
224 BASIC_BLOCK(2U, -1L)
225 {
226 INST(0U, Opcode::SaveState).NoVregs();
227 INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U);
228 INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U);
229 INST(3U, Opcode::SaveState).NoVregs();
230 INST(5U, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2U}, {NO_TYPE, 3U}});
231 INST(7U, Opcode::Return).s32().Inputs(6U);
232 }
233 }
234
235 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
236 }
237
238 // NOLINTEND(readability-magic-numbers)
239
240 } // namespace ark::bytecodeopt::test
241