licm_test.cc revision 8030c4100d2586fac39ed4007c61ee91d4ea4f25
1/* 2 * Copyright (C) 2015 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 "builder.h" 19#include "gtest/gtest.h" 20#include "licm.h" 21#include "nodes.h" 22#include "optimizing_unit_test.h" 23#include "side_effects_analysis.h" 24 25namespace art { 26 27/** 28 * Fixture class for the LICM tests. 29 */ 30class LICMTest : public testing::Test { 31 public: 32 LICMTest() : pool_(), allocator_(&pool_) { 33 graph_ = CreateGraph(&allocator_); 34 } 35 36 ~LICMTest() { } 37 38 // Builds a singly-nested loop structure in CFG. Tests can further populate 39 // the basic blocks with instructions to set up interesting scenarios. 40 void BuildLoop() { 41 entry_ = new (&allocator_) HBasicBlock(graph_); 42 loop_preheader_ = new (&allocator_) HBasicBlock(graph_); 43 loop_header_ = new (&allocator_) HBasicBlock(graph_); 44 loop_body_ = new (&allocator_) HBasicBlock(graph_); 45 exit_ = new (&allocator_) HBasicBlock(graph_); 46 47 graph_->AddBlock(entry_); 48 graph_->AddBlock(loop_preheader_); 49 graph_->AddBlock(loop_header_); 50 graph_->AddBlock(loop_body_); 51 graph_->AddBlock(exit_); 52 53 graph_->SetEntryBlock(entry_); 54 graph_->SetExitBlock(exit_); 55 56 // Set up loop flow in CFG. 57 entry_->AddSuccessor(loop_preheader_); 58 loop_preheader_->AddSuccessor(loop_header_); 59 loop_header_->AddSuccessor(loop_body_); 60 loop_header_->AddSuccessor(exit_); 61 loop_body_->AddSuccessor(loop_header_); 62 63 // Provide boiler-plate instructions. 64 parameter_ = new (&allocator_) HParameterValue(0, Primitive::kPrimNot); 65 entry_->AddInstruction(parameter_); 66 constant_ = graph_->GetIntConstant(42); 67 loop_preheader_->AddInstruction(new (&allocator_) HGoto()); 68 loop_header_->AddInstruction(new (&allocator_) HIf(parameter_)); 69 loop_body_->AddInstruction(new (&allocator_) HGoto()); 70 exit_->AddInstruction(new (&allocator_) HExit()); 71 } 72 73 // Performs LICM optimizations (after proper set up). 74 void PerformLICM() { 75 ASSERT_TRUE(graph_->TryBuildingSsa()); 76 SideEffectsAnalysis side_effects(graph_); 77 side_effects.Run(); 78 LICM licm(graph_, side_effects); 79 licm.Run(); 80 } 81 82 // General building fields. 83 ArenaPool pool_; 84 ArenaAllocator allocator_; 85 HGraph* graph_; 86 87 // Specific basic blocks. 88 HBasicBlock* entry_; 89 HBasicBlock* loop_preheader_; 90 HBasicBlock* loop_header_; 91 HBasicBlock* loop_body_; 92 HBasicBlock* exit_; 93 94 HInstruction* parameter_; // "this" 95 HInstruction* constant_; 96}; 97 98// 99// The actual LICM tests. 100// 101 102TEST_F(LICMTest, FieldHoisting) { 103 BuildLoop(); 104 105 // Populate the loop with instructions: set/get field with different types. 106 NullHandle<mirror::DexCache> dex_cache; 107 HInstruction* get_field = new (&allocator_) HInstanceFieldGet( 108 parameter_, Primitive::kPrimLong, MemberOffset(10), 109 false, kUnknownFieldIndex, graph_->GetDexFile(), dex_cache, 0); 110 loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction()); 111 HInstruction* set_field = new (&allocator_) HInstanceFieldSet( 112 parameter_, constant_, Primitive::kPrimInt, MemberOffset(20), 113 false, kUnknownFieldIndex, graph_->GetDexFile(), dex_cache, 0); 114 loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction()); 115 116 EXPECT_EQ(get_field->GetBlock(), loop_body_); 117 EXPECT_EQ(set_field->GetBlock(), loop_body_); 118 PerformLICM(); 119 EXPECT_EQ(get_field->GetBlock(), loop_preheader_); 120 EXPECT_EQ(set_field->GetBlock(), loop_body_); 121} 122 123TEST_F(LICMTest, NoFieldHoisting) { 124 BuildLoop(); 125 126 // Populate the loop with instructions: set/get field with same types. 127 NullHandle<mirror::DexCache> dex_cache; 128 HInstruction* get_field = new (&allocator_) HInstanceFieldGet( 129 parameter_, Primitive::kPrimLong, MemberOffset(10), 130 false, kUnknownFieldIndex, graph_->GetDexFile(), dex_cache, 0); 131 loop_body_->InsertInstructionBefore(get_field, loop_body_->GetLastInstruction()); 132 HInstruction* set_field = new (&allocator_) HInstanceFieldSet( 133 parameter_, get_field, Primitive::kPrimLong, MemberOffset(10), 134 false, kUnknownFieldIndex, graph_->GetDexFile(), dex_cache, 0); 135 loop_body_->InsertInstructionBefore(set_field, loop_body_->GetLastInstruction()); 136 137 EXPECT_EQ(get_field->GetBlock(), loop_body_); 138 EXPECT_EQ(set_field->GetBlock(), loop_body_); 139 PerformLICM(); 140 EXPECT_EQ(get_field->GetBlock(), loop_body_); 141 EXPECT_EQ(set_field->GetBlock(), loop_body_); 142} 143 144TEST_F(LICMTest, ArrayHoisting) { 145 BuildLoop(); 146 147 // Populate the loop with instructions: set/get array with different types. 148 HInstruction* get_array = new (&allocator_) HArrayGet( 149 parameter_, constant_, Primitive::kPrimLong, 0); 150 loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction()); 151 HInstruction* set_array = new (&allocator_) HArraySet( 152 parameter_, constant_, constant_, Primitive::kPrimInt, 0); 153 loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction()); 154 155 EXPECT_EQ(get_array->GetBlock(), loop_body_); 156 EXPECT_EQ(set_array->GetBlock(), loop_body_); 157 PerformLICM(); 158 EXPECT_EQ(get_array->GetBlock(), loop_preheader_); 159 EXPECT_EQ(set_array->GetBlock(), loop_body_); 160} 161 162TEST_F(LICMTest, NoArrayHoisting) { 163 BuildLoop(); 164 165 // Populate the loop with instructions: set/get array with same types. 166 HInstruction* get_array = new (&allocator_) HArrayGet( 167 parameter_, constant_, Primitive::kPrimLong, 0); 168 loop_body_->InsertInstructionBefore(get_array, loop_body_->GetLastInstruction()); 169 HInstruction* set_array = new (&allocator_) HArraySet( 170 parameter_, get_array, constant_, Primitive::kPrimLong, 0); 171 loop_body_->InsertInstructionBefore(set_array, loop_body_->GetLastInstruction()); 172 173 EXPECT_EQ(get_array->GetBlock(), loop_body_); 174 EXPECT_EQ(set_array->GetBlock(), loop_body_); 175 PerformLICM(); 176 EXPECT_EQ(get_array->GetBlock(), loop_body_); 177 EXPECT_EQ(set_array->GetBlock(), loop_body_); 178} 179 180} // namespace art 181