Home | History | Annotate | Download | only in optimizing
      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