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: 28 NodesVectorTest() 29 : graph_(CreateGraph()) { 30 BuildGraph(); 31 } 32 33 ~NodesVectorTest() { } 34 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 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 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 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 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 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 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 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 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 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->GetKind()); 405 EXPECT_EQ(HVecReduce::kMin, v2->GetKind()); 406 EXPECT_EQ(HVecReduce::kMax, v3->GetKind()); 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