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