1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "base/arena_allocator.h"
18 #include "base/macros.h"
19 #include "nodes.h"
20 #include "optimizing_unit_test.h"
21
22 namespace art HIDDEN {
23
24 /**
25 * Fixture class for testing vector nodes.
26 */
27 class NodesVectorTest : public OptimizingUnitTest {
28 public:
NodesVectorTest()29 NodesVectorTest()
30 : graph_(CreateGraph()) {
31 BuildGraph();
32 }
33
~NodesVectorTest()34 ~NodesVectorTest() { }
35
BuildGraph()36 void BuildGraph() {
37 graph_->SetNumberOfVRegs(1);
38 entry_block_ = new (GetAllocator()) HBasicBlock(graph_);
39 exit_block_ = new (GetAllocator()) HBasicBlock(graph_);
40 graph_->AddBlock(entry_block_);
41 graph_->AddBlock(exit_block_);
42 graph_->SetEntryBlock(entry_block_);
43 graph_->SetExitBlock(exit_block_);
44 int8_parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
45 dex::TypeIndex(1),
46 0,
47 DataType::Type::kInt8);
48 entry_block_->AddInstruction(int8_parameter_);
49 int16_parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
50 dex::TypeIndex(2),
51 0,
52 DataType::Type::kInt16);
53 entry_block_->AddInstruction(int16_parameter_);
54 int32_parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
55 dex::TypeIndex(0),
56 0,
57 DataType::Type::kInt32);
58 entry_block_->AddInstruction(int32_parameter_);
59 }
60
61 // General building fields.
62 HGraph* graph_;
63
64 HBasicBlock* entry_block_;
65 HBasicBlock* exit_block_;
66
67 HInstruction* int8_parameter_;
68 HInstruction* int16_parameter_;
69 HInstruction* int32_parameter_;
70 };
71
72 //
73 // The actual vector nodes tests.
74 //
75
TEST(NodesVector,Alignment)76 TEST(NodesVector, Alignment) {
77 EXPECT_TRUE(Alignment(1, 0).IsAlignedAt(1));
78 EXPECT_FALSE(Alignment(1, 0).IsAlignedAt(2));
79
80 EXPECT_TRUE(Alignment(2, 0).IsAlignedAt(1));
81 EXPECT_TRUE(Alignment(2, 1).IsAlignedAt(1));
82 EXPECT_TRUE(Alignment(2, 0).IsAlignedAt(2));
83 EXPECT_FALSE(Alignment(2, 1).IsAlignedAt(2));
84 EXPECT_FALSE(Alignment(2, 0).IsAlignedAt(4));
85 EXPECT_FALSE(Alignment(2, 1).IsAlignedAt(4));
86
87 EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(1));
88 EXPECT_TRUE(Alignment(4, 2).IsAlignedAt(1));
89 EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(2));
90 EXPECT_TRUE(Alignment(4, 2).IsAlignedAt(2));
91 EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(4));
92 EXPECT_FALSE(Alignment(4, 2).IsAlignedAt(4));
93 EXPECT_FALSE(Alignment(4, 0).IsAlignedAt(8));
94 EXPECT_FALSE(Alignment(4, 2).IsAlignedAt(8));
95
96 EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(1));
97 EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(2));
98 EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(4));
99 EXPECT_TRUE(Alignment(16, 8).IsAlignedAt(8));
100 EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(16));
101 EXPECT_FALSE(Alignment(16, 1).IsAlignedAt(16));
102 EXPECT_FALSE(Alignment(16, 7).IsAlignedAt(16));
103 EXPECT_FALSE(Alignment(16, 0).IsAlignedAt(32));
104
105 EXPECT_EQ(16u, Alignment(16, 0).Base());
106 EXPECT_EQ(0u, Alignment(16, 0).Offset());
107 EXPECT_EQ(4u, Alignment(16, 4).Offset());
108 }
109
TEST(NodesVector,AlignmentEQ)110 TEST(NodesVector, AlignmentEQ) {
111 EXPECT_TRUE(Alignment(2, 0) == Alignment(2, 0));
112 EXPECT_TRUE(Alignment(2, 1) == Alignment(2, 1));
113 EXPECT_TRUE(Alignment(4, 0) == Alignment(4, 0));
114 EXPECT_TRUE(Alignment(4, 2) == Alignment(4, 2));
115
116 EXPECT_FALSE(Alignment(4, 0) == Alignment(2, 0));
117 EXPECT_FALSE(Alignment(4, 0) == Alignment(4, 1));
118 EXPECT_FALSE(Alignment(4, 0) == Alignment(8, 0));
119 }
120
TEST(NodesVector,AlignmentString)121 TEST(NodesVector, AlignmentString) {
122 EXPECT_STREQ("ALIGN(1,0)", Alignment(1, 0).ToString().c_str());
123
124 EXPECT_STREQ("ALIGN(2,0)", Alignment(2, 0).ToString().c_str());
125 EXPECT_STREQ("ALIGN(2,1)", Alignment(2, 1).ToString().c_str());
126
127 EXPECT_STREQ("ALIGN(16,0)", Alignment(16, 0).ToString().c_str());
128 EXPECT_STREQ("ALIGN(16,1)", Alignment(16, 1).ToString().c_str());
129 EXPECT_STREQ("ALIGN(16,8)", Alignment(16, 8).ToString().c_str());
130 EXPECT_STREQ("ALIGN(16,9)", Alignment(16, 9).ToString().c_str());
131 }
132
TEST_F(NodesVectorTest,VectorOperationProperties)133 TEST_F(NodesVectorTest, VectorOperationProperties) {
134 HVecOperation* v0 = new (GetAllocator())
135 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
136 HVecOperation* v1 = new (GetAllocator())
137 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
138 HVecOperation* v2 = new (GetAllocator())
139 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 2, kNoDexPc);
140 HVecOperation* v3 = new (GetAllocator())
141 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt16, 4, kNoDexPc);
142 HVecOperation* v4 = new (GetAllocator()) HVecStore(
143 GetAllocator(),
144 int32_parameter_,
145 int32_parameter_,
146 v0,
147 DataType::Type::kInt32,
148 SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
149 4,
150 kNoDexPc);
151
152 EXPECT_TRUE(v0->Equals(v0));
153 EXPECT_TRUE(v1->Equals(v1));
154 EXPECT_TRUE(v2->Equals(v2));
155 EXPECT_TRUE(v3->Equals(v3));
156 EXPECT_TRUE(v4->Equals(v4));
157
158 EXPECT_TRUE(v0->Equals(v1));
159 EXPECT_FALSE(v0->Equals(v2)); // different vector lengths
160 EXPECT_FALSE(v0->Equals(v3)); // different packed types
161 EXPECT_FALSE(v0->Equals(v4)); // different kinds
162
163 EXPECT_TRUE(v1->Equals(v0)); // switch operands
164 EXPECT_FALSE(v4->Equals(v0));
165
166 EXPECT_EQ(4u, v0->GetVectorLength());
167 EXPECT_EQ(4u, v1->GetVectorLength());
168 EXPECT_EQ(2u, v2->GetVectorLength());
169 EXPECT_EQ(4u, v3->GetVectorLength());
170 EXPECT_EQ(4u, v4->GetVectorLength());
171
172 EXPECT_EQ(DataType::Type::kFloat64, v0->GetType());
173 EXPECT_EQ(DataType::Type::kFloat64, v1->GetType());
174 EXPECT_EQ(DataType::Type::kFloat64, v2->GetType());
175 EXPECT_EQ(DataType::Type::kFloat64, v3->GetType());
176 EXPECT_EQ(DataType::Type::kFloat64, v4->GetType());
177
178 EXPECT_EQ(DataType::Type::kInt32, v0->GetPackedType());
179 EXPECT_EQ(DataType::Type::kInt32, v1->GetPackedType());
180 EXPECT_EQ(DataType::Type::kInt32, v2->GetPackedType());
181 EXPECT_EQ(DataType::Type::kInt16, v3->GetPackedType());
182 EXPECT_EQ(DataType::Type::kInt32, v4->GetPackedType());
183
184 EXPECT_EQ(16u, v0->GetVectorNumberOfBytes());
185 EXPECT_EQ(16u, v1->GetVectorNumberOfBytes());
186 EXPECT_EQ(8u, v2->GetVectorNumberOfBytes());
187 EXPECT_EQ(8u, v3->GetVectorNumberOfBytes());
188 EXPECT_EQ(16u, v4->GetVectorNumberOfBytes());
189
190 EXPECT_FALSE(v0->CanBeMoved());
191 EXPECT_FALSE(v1->CanBeMoved());
192 EXPECT_FALSE(v2->CanBeMoved());
193 EXPECT_FALSE(v3->CanBeMoved());
194 EXPECT_FALSE(v4->CanBeMoved());
195 }
196
TEST_F(NodesVectorTest,VectorAlignmentAndStringCharAtMatterOnLoad)197 TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) {
198 HVecLoad* v0 = new (GetAllocator()) HVecLoad(GetAllocator(),
199 int32_parameter_,
200 int32_parameter_,
201 DataType::Type::kInt32,
202 SideEffects::ArrayReadOfType(DataType::Type::kInt32),
203 4,
204 /*is_string_char_at*/ false,
205 kNoDexPc);
206 HVecLoad* v1 = new (GetAllocator()) HVecLoad(GetAllocator(),
207 int32_parameter_,
208 int32_parameter_,
209 DataType::Type::kInt32,
210 SideEffects::ArrayReadOfType(DataType::Type::kInt32),
211 4,
212 /*is_string_char_at*/ false,
213 kNoDexPc);
214 HVecLoad* v2 = new (GetAllocator()) HVecLoad(GetAllocator(),
215 int32_parameter_,
216 int32_parameter_,
217 DataType::Type::kInt32,
218 SideEffects::ArrayReadOfType(DataType::Type::kInt32),
219 4,
220 /*is_string_char_at*/ true,
221 kNoDexPc);
222
223 EXPECT_TRUE(v0->CanBeMoved());
224 EXPECT_TRUE(v1->CanBeMoved());
225 EXPECT_TRUE(v2->CanBeMoved());
226
227 EXPECT_FALSE(v0->IsStringCharAt());
228 EXPECT_FALSE(v1->IsStringCharAt());
229 EXPECT_TRUE(v2->IsStringCharAt());
230
231 EXPECT_TRUE(v0->Equals(v0));
232 EXPECT_TRUE(v1->Equals(v1));
233 EXPECT_TRUE(v2->Equals(v2));
234
235 EXPECT_TRUE(v0->Equals(v1));
236 EXPECT_FALSE(v0->Equals(v2)); // different is_string_char_at
237
238 EXPECT_TRUE(v0->GetAlignment() == Alignment(4, 0));
239 EXPECT_TRUE(v1->GetAlignment() == Alignment(4, 0));
240 EXPECT_TRUE(v2->GetAlignment() == Alignment(4, 0));
241
242 v1->SetAlignment(Alignment(8, 0));
243
244 EXPECT_TRUE(v1->GetAlignment() == Alignment(8, 0));
245
246 EXPECT_FALSE(v0->Equals(v1)); // no longer equal
247 }
248
TEST_F(NodesVectorTest,VectorAlignmentMattersOnStore)249 TEST_F(NodesVectorTest, VectorAlignmentMattersOnStore) {
250 HVecOperation* p0 = new (GetAllocator())
251 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
252 HVecStore* v0 = new (GetAllocator()) HVecStore(
253 GetAllocator(),
254 int32_parameter_,
255 int32_parameter_,
256 p0,
257 DataType::Type::kInt32,
258 SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
259 4,
260 kNoDexPc);
261 HVecStore* v1 = new (GetAllocator()) HVecStore(
262 GetAllocator(),
263 int32_parameter_,
264 int32_parameter_,
265 p0,
266 DataType::Type::kInt32,
267 SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
268 4,
269 kNoDexPc);
270
271 EXPECT_FALSE(v0->CanBeMoved());
272 EXPECT_FALSE(v1->CanBeMoved());
273
274 EXPECT_TRUE(v0->Equals(v1));
275
276 EXPECT_TRUE(v0->GetAlignment() == Alignment(4, 0));
277 EXPECT_TRUE(v1->GetAlignment() == Alignment(4, 0));
278
279 v1->SetAlignment(Alignment(8, 0));
280
281 EXPECT_TRUE(v1->GetAlignment() == Alignment(8, 0));
282
283 EXPECT_FALSE(v0->Equals(v1)); // no longer equal
284 }
285
TEST_F(NodesVectorTest,VectorAttributesMatterOnHalvingAdd)286 TEST_F(NodesVectorTest, VectorAttributesMatterOnHalvingAdd) {
287 HVecOperation* u0 = new (GetAllocator())
288 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kUint32, 4, kNoDexPc);
289 HVecOperation* u1 = new (GetAllocator())
290 HVecReplicateScalar(GetAllocator(), int16_parameter_, DataType::Type::kUint16, 8, kNoDexPc);
291 HVecOperation* u2 = new (GetAllocator())
292 HVecReplicateScalar(GetAllocator(), int8_parameter_, DataType::Type::kUint8, 16, kNoDexPc);
293
294 HVecOperation* p0 = new (GetAllocator())
295 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
296 HVecOperation* p1 = new (GetAllocator())
297 HVecReplicateScalar(GetAllocator(), int16_parameter_, DataType::Type::kInt16, 8, kNoDexPc);
298 HVecOperation* p2 = new (GetAllocator())
299 HVecReplicateScalar(GetAllocator(), int8_parameter_, DataType::Type::kInt8, 16, kNoDexPc);
300
301 HVecHalvingAdd* v0 = new (GetAllocator()) HVecHalvingAdd(
302 GetAllocator(), u0, u0, DataType::Type::kUint32, 4, /*is_rounded*/ true, kNoDexPc);
303 HVecHalvingAdd* v1 = new (GetAllocator()) HVecHalvingAdd(
304 GetAllocator(), u0, u0, DataType::Type::kUint32, 4, /*is_rounded*/ false, kNoDexPc);
305 HVecHalvingAdd* v2 = new (GetAllocator()) HVecHalvingAdd(
306 GetAllocator(), p0, p0, DataType::Type::kInt32, 4, /*is_rounded*/ true, kNoDexPc);
307 HVecHalvingAdd* v3 = new (GetAllocator()) HVecHalvingAdd(
308 GetAllocator(), p0, p0, DataType::Type::kInt32, 4, /*is_rounded*/ false, kNoDexPc);
309
310 HVecHalvingAdd* v4 = new (GetAllocator()) HVecHalvingAdd(
311 GetAllocator(), u1, u1, DataType::Type::kUint16, 8, /*is_rounded*/ true, kNoDexPc);
312 HVecHalvingAdd* v5 = new (GetAllocator()) HVecHalvingAdd(
313 GetAllocator(), u1, u1, DataType::Type::kUint16, 8, /*is_rounded*/ false, kNoDexPc);
314 HVecHalvingAdd* v6 = new (GetAllocator()) HVecHalvingAdd(
315 GetAllocator(), p1, p1, DataType::Type::kInt16, 8, /*is_rounded*/ true, kNoDexPc);
316 HVecHalvingAdd* v7 = new (GetAllocator()) HVecHalvingAdd(
317 GetAllocator(), p1, p1, DataType::Type::kInt16, 8, /*is_rounded*/ false, kNoDexPc);
318
319 HVecHalvingAdd* v8 = new (GetAllocator()) HVecHalvingAdd(
320 GetAllocator(), u2, u2, DataType::Type::kUint8, 16, /*is_rounded*/ true, kNoDexPc);
321 HVecHalvingAdd* v9 = new (GetAllocator()) HVecHalvingAdd(
322 GetAllocator(), u2, u2, DataType::Type::kUint8, 16, /*is_rounded*/ false, kNoDexPc);
323 HVecHalvingAdd* v10 = new (GetAllocator()) HVecHalvingAdd(
324 GetAllocator(), p2, p2, DataType::Type::kInt8, 16, /*is_rounded*/ true, kNoDexPc);
325 HVecHalvingAdd* v11 = new (GetAllocator()) HVecHalvingAdd(
326 GetAllocator(), p2, p2, DataType::Type::kInt8, 16, /*is_rounded*/ false, kNoDexPc);
327
328 HVecHalvingAdd* hadd_insns[] = { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 };
329
330 EXPECT_FALSE(u0->CanBeMoved());
331 EXPECT_FALSE(u1->CanBeMoved());
332 EXPECT_FALSE(u2->CanBeMoved());
333 EXPECT_FALSE(p0->CanBeMoved());
334 EXPECT_FALSE(p1->CanBeMoved());
335 EXPECT_FALSE(p2->CanBeMoved());
336
337 for (HVecHalvingAdd* hadd_insn : hadd_insns) {
338 EXPECT_TRUE(hadd_insn->CanBeMoved());
339 }
340
341 EXPECT_TRUE(v0->IsRounded());
342 EXPECT_TRUE(!v1->IsRounded());
343 EXPECT_TRUE(v2->IsRounded());
344 EXPECT_TRUE(!v3->IsRounded());
345 EXPECT_TRUE(v4->IsRounded());
346 EXPECT_TRUE(!v5->IsRounded());
347 EXPECT_TRUE(v6->IsRounded());
348 EXPECT_TRUE(!v7->IsRounded());
349 EXPECT_TRUE(v8->IsRounded());
350 EXPECT_TRUE(!v9->IsRounded());
351 EXPECT_TRUE(v10->IsRounded());
352 EXPECT_TRUE(!v11->IsRounded());
353
354 for (HVecHalvingAdd* hadd_insn1 : hadd_insns) {
355 for (HVecHalvingAdd* hadd_insn2 : hadd_insns) {
356 EXPECT_EQ(hadd_insn1 == hadd_insn2, hadd_insn1->Equals(hadd_insn2));
357 }
358 }
359 }
360
TEST_F(NodesVectorTest,VectorOperationMattersOnMultiplyAccumulate)361 TEST_F(NodesVectorTest, VectorOperationMattersOnMultiplyAccumulate) {
362 HVecOperation* v0 = new (GetAllocator())
363 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
364
365 HVecMultiplyAccumulate* v1 = new (GetAllocator()) HVecMultiplyAccumulate(
366 GetAllocator(), HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 4, kNoDexPc);
367 HVecMultiplyAccumulate* v2 = new (GetAllocator()) HVecMultiplyAccumulate(
368 GetAllocator(), HInstruction::kSub, v0, v0, v0, DataType::Type::kInt32, 4, kNoDexPc);
369 HVecMultiplyAccumulate* v3 = new (GetAllocator()) HVecMultiplyAccumulate(
370 GetAllocator(), HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 2, kNoDexPc);
371
372 EXPECT_FALSE(v0->CanBeMoved());
373 EXPECT_TRUE(v1->CanBeMoved());
374 EXPECT_TRUE(v2->CanBeMoved());
375 EXPECT_TRUE(v3->CanBeMoved());
376
377 EXPECT_EQ(HInstruction::kAdd, v1->GetOpKind());
378 EXPECT_EQ(HInstruction::kSub, v2->GetOpKind());
379 EXPECT_EQ(HInstruction::kAdd, v3->GetOpKind());
380
381 EXPECT_TRUE(v1->Equals(v1));
382 EXPECT_TRUE(v2->Equals(v2));
383 EXPECT_TRUE(v3->Equals(v3));
384
385 EXPECT_FALSE(v1->Equals(v2)); // different operators
386 EXPECT_FALSE(v1->Equals(v3)); // different vector lengths
387 }
388
TEST_F(NodesVectorTest,VectorKindMattersOnReduce)389 TEST_F(NodesVectorTest, VectorKindMattersOnReduce) {
390 HVecOperation* v0 = new (GetAllocator())
391 HVecReplicateScalar(GetAllocator(), int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
392
393 HVecReduce* v1 = new (GetAllocator()) HVecReduce(
394 GetAllocator(), v0, DataType::Type::kInt32, 4, HVecReduce::kSum, kNoDexPc);
395 HVecReduce* v2 = new (GetAllocator()) HVecReduce(
396 GetAllocator(), v0, DataType::Type::kInt32, 4, HVecReduce::kMin, kNoDexPc);
397 HVecReduce* v3 = new (GetAllocator()) HVecReduce(
398 GetAllocator(), v0, DataType::Type::kInt32, 4, HVecReduce::kMax, kNoDexPc);
399
400 EXPECT_FALSE(v0->CanBeMoved());
401 EXPECT_TRUE(v1->CanBeMoved());
402 EXPECT_TRUE(v2->CanBeMoved());
403 EXPECT_TRUE(v3->CanBeMoved());
404
405 EXPECT_EQ(HVecReduce::kSum, v1->GetReductionKind());
406 EXPECT_EQ(HVecReduce::kMin, v2->GetReductionKind());
407 EXPECT_EQ(HVecReduce::kMax, v3->GetReductionKind());
408
409 EXPECT_TRUE(v1->Equals(v1));
410 EXPECT_TRUE(v2->Equals(v2));
411 EXPECT_TRUE(v3->Equals(v3));
412
413 EXPECT_FALSE(v1->Equals(v2)); // different kinds
414 EXPECT_FALSE(v1->Equals(v3));
415 }
416
417 } // namespace art
418