Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2014 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 "builder.h"
     18 #include "code_generator.h"
     19 #include "dex_file.h"
     20 #include "dex_instruction.h"
     21 #include "nodes.h"
     22 #include "optimizing_unit_test.h"
     23 #include "ssa_liveness_analysis.h"
     24 #include "utils/arena_allocator.h"
     25 
     26 #include "gtest/gtest.h"
     27 
     28 namespace art {
     29 
     30 static void DumpBitVector(BitVector* vector,
     31                           std::ostream& buffer,
     32                           size_t count,
     33                           const char* prefix) {
     34   buffer << prefix;
     35   buffer << '(';
     36   for (size_t i = 0; i < count; ++i) {
     37     buffer << vector->IsBitSet(i);
     38   }
     39   buffer << ")\n";
     40 }
     41 
     42 static void TestCode(const uint16_t* data, const char* expected) {
     43   ArenaPool pool;
     44   ArenaAllocator allocator(&pool);
     45   HGraphBuilder builder(&allocator);
     46   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
     47   HGraph* graph = builder.BuildGraph(*item);
     48   ASSERT_NE(graph, nullptr);
     49   graph->BuildDominatorTree();
     50   graph->TransformToSSA();
     51   graph->FindNaturalLoops();
     52   CodeGenerator* codegen = CodeGenerator::Create(&allocator, graph, InstructionSet::kX86);
     53   SsaLivenessAnalysis liveness(*graph, codegen);
     54   liveness.Analyze();
     55 
     56   std::ostringstream buffer;
     57   for (HInsertionOrderIterator it(*graph); !it.Done(); it.Advance()) {
     58     HBasicBlock* block = it.Current();
     59     buffer << "Block " << block->GetBlockId() << std::endl;
     60     size_t ssa_values = liveness.GetNumberOfSsaValues();
     61     BitVector* live_in = liveness.GetLiveInSet(*block);
     62     DumpBitVector(live_in, buffer, ssa_values, "  live in: ");
     63     BitVector* live_out = liveness.GetLiveOutSet(*block);
     64     DumpBitVector(live_out, buffer, ssa_values, "  live out: ");
     65     BitVector* kill = liveness.GetKillSet(*block);
     66     DumpBitVector(kill, buffer, ssa_values, "  kill: ");
     67   }
     68   ASSERT_STREQ(expected, buffer.str().c_str());
     69 }
     70 
     71 TEST(LivenessTest, CFG1) {
     72   const char* expected =
     73     "Block 0\n"
     74     "  live in: (0)\n"
     75     "  live out: (0)\n"
     76     "  kill: (1)\n"
     77     "Block 1\n"
     78     "  live in: (0)\n"
     79     "  live out: (0)\n"
     80     "  kill: (0)\n"
     81     "Block 2\n"
     82     "  live in: (0)\n"
     83     "  live out: (0)\n"
     84     "  kill: (0)\n";
     85 
     86   // Constant is not used.
     87   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     88     Instruction::CONST_4 | 0 | 0,
     89     Instruction::RETURN_VOID);
     90 
     91   TestCode(data, expected);
     92 }
     93 
     94 TEST(LivenessTest, CFG2) {
     95   const char* expected =
     96     "Block 0\n"
     97     "  live in: (0)\n"
     98     "  live out: (1)\n"
     99     "  kill: (1)\n"
    100     "Block 1\n"
    101     "  live in: (1)\n"
    102     "  live out: (0)\n"
    103     "  kill: (0)\n"
    104     "Block 2\n"
    105     "  live in: (0)\n"
    106     "  live out: (0)\n"
    107     "  kill: (0)\n";
    108 
    109   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    110     Instruction::CONST_4 | 0 | 0,
    111     Instruction::RETURN);
    112 
    113   TestCode(data, expected);
    114 }
    115 
    116 TEST(LivenessTest, CFG3) {
    117   const char* expected =
    118     "Block 0\n"  // entry block
    119     "  live in: (000)\n"
    120     "  live out: (110)\n"
    121     "  kill: (110)\n"
    122     "Block 1\n"  // block with add
    123     "  live in: (110)\n"
    124     "  live out: (001)\n"
    125     "  kill: (001)\n"
    126     "Block 2\n"  // block with return
    127     "  live in: (001)\n"
    128     "  live out: (000)\n"
    129     "  kill: (000)\n"
    130     "Block 3\n"  // exit block
    131     "  live in: (000)\n"
    132     "  live out: (000)\n"
    133     "  kill: (000)\n";
    134 
    135   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
    136     Instruction::CONST_4 | 3 << 12 | 0,
    137     Instruction::CONST_4 | 4 << 12 | 1 << 8,
    138     Instruction::ADD_INT_2ADDR | 1 << 12,
    139     Instruction::GOTO | 0x100,
    140     Instruction::RETURN);
    141 
    142   TestCode(data, expected);
    143 }
    144 
    145 TEST(LivenessTest, CFG4) {
    146   // var a;
    147   // if (0 == 0) {
    148   //   a = 5;
    149   // } else {
    150   //   a = 4;
    151   // }
    152   // return a;
    153   //
    154   // Bitsets are made of:
    155   // (constant0, constant4, constant5, phi)
    156   const char* expected =
    157     "Block 0\n"  // entry block
    158     "  live in: (0000)\n"
    159     "  live out: (1110)\n"
    160     "  kill: (1110)\n"
    161     "Block 1\n"  // block with if
    162     "  live in: (1110)\n"
    163     "  live out: (0110)\n"
    164     "  kill: (0000)\n"
    165     "Block 2\n"  // else block
    166     "  live in: (0100)\n"
    167     "  live out: (0000)\n"
    168     "  kill: (0000)\n"
    169     "Block 3\n"  // then block
    170     "  live in: (0010)\n"
    171     "  live out: (0000)\n"
    172     "  kill: (0000)\n"
    173     "Block 4\n"  // return block
    174     "  live in: (0000)\n"
    175     "  live out: (0000)\n"
    176     "  kill: (0001)\n"
    177     "Block 5\n"  // exit block
    178     "  live in: (0000)\n"
    179     "  live out: (0000)\n"
    180     "  kill: (0000)\n";
    181 
    182   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    183     Instruction::CONST_4 | 0 | 0,
    184     Instruction::IF_EQ, 4,
    185     Instruction::CONST_4 | 4 << 12 | 0,
    186     Instruction::GOTO | 0x200,
    187     Instruction::CONST_4 | 5 << 12 | 0,
    188     Instruction::RETURN | 0 << 8);
    189 
    190   TestCode(data, expected);
    191 }
    192 
    193 TEST(LivenessTest, CFG5) {
    194   // var a = 0;
    195   // if (0 == 0) {
    196   // } else {
    197   //   a = 4;
    198   // }
    199   // return a;
    200   //
    201   // Bitsets are made of:
    202   // (constant0, constant4, phi)
    203   const char* expected =
    204     "Block 0\n"  // entry block
    205     "  live in: (000)\n"
    206     "  live out: (110)\n"
    207     "  kill: (110)\n"
    208     "Block 1\n"  // block with if
    209     "  live in: (110)\n"
    210     "  live out: (110)\n"
    211     "  kill: (000)\n"
    212     "Block 2\n"  // else block
    213     "  live in: (010)\n"
    214     "  live out: (000)\n"
    215     "  kill: (000)\n"
    216     "Block 3\n"  // return block
    217     "  live in: (000)\n"
    218     "  live out: (000)\n"
    219     "  kill: (001)\n"
    220     "Block 4\n"  // exit block
    221     "  live in: (000)\n"
    222     "  live out: (000)\n"
    223     "  kill: (000)\n"
    224     "Block 5\n"  // block to avoid critical edge. Predecessor is 1, successor is 3.
    225     "  live in: (100)\n"
    226     "  live out: (000)\n"
    227     "  kill: (000)\n";
    228 
    229   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    230     Instruction::CONST_4 | 0 | 0,
    231     Instruction::IF_EQ, 3,
    232     Instruction::CONST_4 | 4 << 12 | 0,
    233     Instruction::RETURN | 0 << 8);
    234 
    235   TestCode(data, expected);
    236 }
    237 
    238 TEST(LivenessTest, Loop1) {
    239   // Simple loop with one preheader and one back edge.
    240   // var a = 0;
    241   // while (a == a) {
    242   //   a = 4;
    243   // }
    244   // return;
    245   // Bitsets are made of:
    246   // (constant0, constant4, phi)
    247   const char* expected =
    248     "Block 0\n"  // entry block
    249     "  live in: (000)\n"
    250     "  live out: (110)\n"
    251     "  kill: (110)\n"
    252     "Block 1\n"  // pre header
    253     "  live in: (110)\n"
    254     "  live out: (010)\n"
    255     "  kill: (000)\n"
    256     "Block 2\n"  // loop header
    257     "  live in: (010)\n"
    258     "  live out: (010)\n"
    259     "  kill: (001)\n"
    260     "Block 3\n"  // back edge
    261     "  live in: (010)\n"
    262     "  live out: (010)\n"
    263     "  kill: (000)\n"
    264     "Block 4\n"  // return block
    265     "  live in: (000)\n"
    266     "  live out: (000)\n"
    267     "  kill: (000)\n"
    268     "Block 5\n"  // exit block
    269     "  live in: (000)\n"
    270     "  live out: (000)\n"
    271     "  kill: (000)\n";
    272 
    273 
    274   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    275     Instruction::CONST_4 | 0 | 0,
    276     Instruction::IF_EQ, 4,
    277     Instruction::CONST_4 | 4 << 12 | 0,
    278     Instruction::GOTO | 0xFD00,
    279     Instruction::RETURN_VOID);
    280 
    281   TestCode(data, expected);
    282 }
    283 
    284 TEST(LivenessTest, Loop3) {
    285   // Test that the returned value stays live in a preceding loop.
    286   // var a = 0;
    287   // while (a == a) {
    288   //   a = 4;
    289   // }
    290   // return 5;
    291   // Bitsets are made of:
    292   // (constant0, constant4, constant5, phi)
    293   const char* expected =
    294     "Block 0\n"
    295     "  live in: (0000)\n"
    296     "  live out: (1110)\n"
    297     "  kill: (1110)\n"
    298     "Block 1\n"
    299     "  live in: (1110)\n"
    300     "  live out: (0110)\n"
    301     "  kill: (0000)\n"
    302     "Block 2\n"  // loop header
    303     "  live in: (0110)\n"
    304     "  live out: (0110)\n"
    305     "  kill: (0001)\n"
    306     "Block 3\n"  // back edge
    307     "  live in: (0110)\n"
    308     "  live out: (0110)\n"
    309     "  kill: (0000)\n"
    310     "Block 4\n"  // return block
    311     "  live in: (0010)\n"
    312     "  live out: (0000)\n"
    313     "  kill: (0000)\n"
    314     "Block 5\n"  // exit block
    315     "  live in: (0000)\n"
    316     "  live out: (0000)\n"
    317     "  kill: (0000)\n";
    318 
    319   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
    320     Instruction::CONST_4 | 0 | 0,
    321     Instruction::IF_EQ, 4,
    322     Instruction::CONST_4 | 4 << 12 | 0,
    323     Instruction::GOTO | 0xFD00,
    324     Instruction::CONST_4 | 5 << 12 | 1 << 8,
    325     Instruction::RETURN | 1 << 8);
    326 
    327   TestCode(data, expected);
    328 }
    329 
    330 
    331 TEST(LivenessTest, Loop4) {
    332   // Make sure we support a preheader of a loop not being the first predecessor
    333   // in the predecessor list of the header.
    334   // var a = 0;
    335   // while (a == a) {
    336   //   a = 4;
    337   // }
    338   // return a;
    339   // Bitsets are made of:
    340   // (constant0, constant4, phi)
    341   const char* expected =
    342     "Block 0\n"
    343     "  live in: (000)\n"
    344     "  live out: (110)\n"
    345     "  kill: (110)\n"
    346     "Block 1\n"
    347     "  live in: (110)\n"
    348     "  live out: (110)\n"
    349     "  kill: (000)\n"
    350     "Block 2\n"  // loop header
    351     "  live in: (010)\n"
    352     "  live out: (011)\n"
    353     "  kill: (001)\n"
    354     "Block 3\n"  // back edge
    355     "  live in: (010)\n"
    356     "  live out: (010)\n"
    357     "  kill: (000)\n"
    358     "Block 4\n"  // pre loop header
    359     "  live in: (110)\n"
    360     "  live out: (010)\n"
    361     "  kill: (000)\n"
    362     "Block 5\n"  // return block
    363     "  live in: (001)\n"
    364     "  live out: (000)\n"
    365     "  kill: (000)\n"
    366     "Block 6\n"  // exit block
    367     "  live in: (000)\n"
    368     "  live out: (000)\n"
    369     "  kill: (000)\n";
    370 
    371   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    372     Instruction::CONST_4 | 0 | 0,
    373     Instruction::GOTO | 0x500,
    374     Instruction::IF_EQ, 5,
    375     Instruction::CONST_4 | 4 << 12 | 0,
    376     Instruction::GOTO | 0xFD00,
    377     Instruction::GOTO | 0xFC00,
    378     Instruction::RETURN | 0 << 8);
    379 
    380   TestCode(data, expected);
    381 }
    382 
    383 TEST(LivenessTest, Loop5) {
    384   // Make sure we create a preheader of a loop when a header originally has two
    385   // incoming blocks and one back edge.
    386   // Bitsets are made of:
    387   // (constant0, constant4, constant5, phi in block 8, phi in block 4)
    388   const char* expected =
    389     "Block 0\n"
    390     "  live in: (00000)\n"
    391     "  live out: (11100)\n"
    392     "  kill: (11100)\n"
    393     "Block 1\n"
    394     "  live in: (11100)\n"
    395     "  live out: (01100)\n"
    396     "  kill: (00000)\n"
    397     "Block 2\n"
    398     "  live in: (01000)\n"
    399     "  live out: (00000)\n"
    400     "  kill: (00000)\n"
    401     "Block 3\n"
    402     "  live in: (00100)\n"
    403     "  live out: (00000)\n"
    404     "  kill: (00000)\n"
    405     "Block 4\n"  // loop header
    406     "  live in: (00000)\n"
    407     "  live out: (00001)\n"
    408     "  kill: (00001)\n"
    409     "Block 5\n"  // back edge
    410     "  live in: (00001)\n"
    411     "  live out: (00000)\n"
    412     "  kill: (00000)\n"
    413     "Block 6\n"  // return block
    414     "  live in: (00001)\n"
    415     "  live out: (00000)\n"
    416     "  kill: (00000)\n"
    417     "Block 7\n"  // exit block
    418     "  live in: (00000)\n"
    419     "  live out: (00000)\n"
    420     "  kill: (00000)\n"
    421     "Block 8\n"  // synthesized pre header
    422     "  live in: (00000)\n"
    423     "  live out: (00000)\n"
    424     "  kill: (00010)\n";
    425 
    426   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    427     Instruction::CONST_4 | 0 | 0,
    428     Instruction::IF_EQ, 4,
    429     Instruction::CONST_4 | 4 << 12 | 0,
    430     Instruction::GOTO | 0x200,
    431     Instruction::CONST_4 | 5 << 12 | 0,
    432     Instruction::IF_EQ, 3,
    433     Instruction::GOTO | 0xFE00,
    434     Instruction::RETURN | 0 << 8);
    435 
    436   TestCode(data, expected);
    437 }
    438 
    439 TEST(LivenessTest, Loop6) {
    440   // Bitsets are made of:
    441   // (constant0, constant4, constant5, phi in block 2, phi in block 8)
    442   const char* expected =
    443     "Block 0\n"
    444     "  live in: (00000)\n"
    445     "  live out: (11100)\n"
    446     "  kill: (11100)\n"
    447     "Block 1\n"
    448     "  live in: (11100)\n"
    449     "  live out: (01100)\n"
    450     "  kill: (00000)\n"
    451     "Block 2\n"  // loop header
    452     "  live in: (01100)\n"
    453     "  live out: (01110)\n"
    454     "  kill: (00010)\n"
    455     "Block 3\n"
    456     "  live in: (01100)\n"
    457     "  live out: (01100)\n"
    458     "  kill: (00000)\n"
    459     "Block 4\n"  // original back edge
    460     "  live in: (01100)\n"
    461     "  live out: (01100)\n"
    462     "  kill: (00000)\n"
    463     "Block 5\n"  // original back edge
    464     "  live in: (01100)\n"
    465     "  live out: (01100)\n"
    466     "  kill: (00000)\n"
    467     "Block 6\n"  // return block
    468     "  live in: (00010)\n"
    469     "  live out: (00000)\n"
    470     "  kill: (00000)\n"
    471     "Block 7\n"  // exit block
    472     "  live in: (00000)\n"
    473     "  live out: (00000)\n"
    474     "  kill: (00000)\n"
    475     "Block 8\n"  // synthesized back edge
    476     "  live in: (01100)\n"
    477     "  live out: (01100)\n"
    478     "  kill: (00001)\n";
    479 
    480   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    481     Instruction::CONST_4 | 0 | 0,
    482     Instruction::IF_EQ, 8,
    483     Instruction::CONST_4 | 4 << 12 | 0,
    484     Instruction::IF_EQ, 4,
    485     Instruction::CONST_4 | 5 << 12 | 0,
    486     Instruction::GOTO | 0xFA00,
    487     Instruction::GOTO | 0xF900,
    488     Instruction::RETURN | 0 << 8);
    489 
    490   TestCode(data, expected);
    491 }
    492 
    493 
    494 TEST(LivenessTest, Loop7) {
    495   // Bitsets are made of:
    496   // (constant0, constant4, constant5, phi in block 2, phi in block 6)
    497   const char* expected =
    498     "Block 0\n"
    499     "  live in: (00000)\n"
    500     "  live out: (11100)\n"
    501     "  kill: (11100)\n"
    502     "Block 1\n"
    503     "  live in: (11100)\n"
    504     "  live out: (01100)\n"
    505     "  kill: (00000)\n"
    506     "Block 2\n"  // loop header
    507     "  live in: (01100)\n"
    508     "  live out: (01110)\n"
    509     "  kill: (00010)\n"
    510     "Block 3\n"
    511     "  live in: (01100)\n"
    512     "  live out: (01100)\n"
    513     "  kill: (00000)\n"
    514     "Block 4\n"  // loop exit
    515     "  live in: (00100)\n"
    516     "  live out: (00000)\n"
    517     "  kill: (00000)\n"
    518     "Block 5\n"  // back edge
    519     "  live in: (01100)\n"
    520     "  live out: (01100)\n"
    521     "  kill: (00000)\n"
    522     "Block 6\n"  // return block
    523     "  live in: (00000)\n"
    524     "  live out: (00000)\n"
    525     "  kill: (00001)\n"
    526     "Block 7\n"  // exit block
    527     "  live in: (00000)\n"
    528     "  live out: (00000)\n"
    529     "  kill: (00000)\n"
    530     "Block 8\n"  // synthesized block to avoid critical edge.
    531     "  live in: (00010)\n"
    532     "  live out: (00000)\n"
    533     "  kill: (00000)\n";
    534 
    535   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
    536     Instruction::CONST_4 | 0 | 0,
    537     Instruction::IF_EQ, 8,
    538     Instruction::CONST_4 | 4 << 12 | 0,
    539     Instruction::IF_EQ, 4,
    540     Instruction::CONST_4 | 5 << 12 | 0,
    541     Instruction::GOTO | 0x0200,
    542     Instruction::GOTO | 0xF900,
    543     Instruction::RETURN | 0 << 8);
    544 
    545   TestCode(data, expected);
    546 }
    547 
    548 }  // namespace art
    549