upload android base code part3
This commit is contained in:
parent
71b83c22f1
commit
b9e30e05b1
15122 changed files with 2089659 additions and 0 deletions
445
android/art/compiler/optimizing/gvn_test.cc
Normal file
445
android/art/compiler/optimizing/gvn_test.cc
Normal file
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "base/arena_allocator.h"
|
||||
#include "builder.h"
|
||||
#include "gvn.h"
|
||||
#include "nodes.h"
|
||||
#include "optimizing_unit_test.h"
|
||||
#include "side_effects_analysis.h"
|
||||
|
||||
namespace art {
|
||||
|
||||
class GVNTest : public CommonCompilerTest {};
|
||||
|
||||
TEST_F(GVNTest, LocalFieldElimination) {
|
||||
ArenaPool pool;
|
||||
ArenaAllocator allocator(&pool);
|
||||
|
||||
HGraph* graph = CreateGraph(&allocator);
|
||||
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(entry);
|
||||
graph->SetEntryBlock(entry);
|
||||
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
|
||||
dex::TypeIndex(0),
|
||||
0,
|
||||
Primitive::kPrimNot);
|
||||
entry->AddInstruction(parameter);
|
||||
|
||||
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(block);
|
||||
entry->AddSuccessor(block);
|
||||
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* to_remove = block->GetLastInstruction();
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(43),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* different_offset = block->GetLastInstruction();
|
||||
// Kill the value.
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
|
||||
parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* use_after_kill = block->GetLastInstruction();
|
||||
block->AddInstruction(new (&allocator) HExit());
|
||||
|
||||
ASSERT_EQ(to_remove->GetBlock(), block);
|
||||
ASSERT_EQ(different_offset->GetBlock(), block);
|
||||
ASSERT_EQ(use_after_kill->GetBlock(), block);
|
||||
|
||||
graph->BuildDominatorTree();
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
GVNOptimization(graph, side_effects).Run();
|
||||
|
||||
ASSERT_TRUE(to_remove->GetBlock() == nullptr);
|
||||
ASSERT_EQ(different_offset->GetBlock(), block);
|
||||
ASSERT_EQ(use_after_kill->GetBlock(), block);
|
||||
}
|
||||
|
||||
TEST_F(GVNTest, GlobalFieldElimination) {
|
||||
ArenaPool pool;
|
||||
ArenaAllocator allocator(&pool);
|
||||
|
||||
HGraph* graph = CreateGraph(&allocator);
|
||||
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(entry);
|
||||
graph->SetEntryBlock(entry);
|
||||
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
|
||||
dex::TypeIndex(0),
|
||||
0,
|
||||
Primitive::kPrimNot);
|
||||
entry->AddInstruction(parameter);
|
||||
|
||||
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(block);
|
||||
entry->AddSuccessor(block);
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
|
||||
block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
|
||||
HBasicBlock* then = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* else_ = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* join = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(then);
|
||||
graph->AddBlock(else_);
|
||||
graph->AddBlock(join);
|
||||
|
||||
block->AddSuccessor(then);
|
||||
block->AddSuccessor(else_);
|
||||
then->AddSuccessor(join);
|
||||
else_->AddSuccessor(join);
|
||||
|
||||
then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
then->AddInstruction(new (&allocator) HGoto());
|
||||
else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
else_->AddInstruction(new (&allocator) HGoto());
|
||||
join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
join->AddInstruction(new (&allocator) HExit());
|
||||
|
||||
graph->BuildDominatorTree();
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
GVNOptimization(graph, side_effects).Run();
|
||||
|
||||
// Check that all field get instructions have been GVN'ed.
|
||||
ASSERT_TRUE(then->GetFirstInstruction()->IsGoto());
|
||||
ASSERT_TRUE(else_->GetFirstInstruction()->IsGoto());
|
||||
ASSERT_TRUE(join->GetFirstInstruction()->IsExit());
|
||||
}
|
||||
|
||||
TEST_F(GVNTest, LoopFieldElimination) {
|
||||
ArenaPool pool;
|
||||
ArenaAllocator allocator(&pool);
|
||||
|
||||
HGraph* graph = CreateGraph(&allocator);
|
||||
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(entry);
|
||||
graph->SetEntryBlock(entry);
|
||||
|
||||
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
|
||||
dex::TypeIndex(0),
|
||||
0,
|
||||
Primitive::kPrimNot);
|
||||
entry->AddInstruction(parameter);
|
||||
|
||||
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(block);
|
||||
entry->AddSuccessor(block);
|
||||
block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
block->AddInstruction(new (&allocator) HGoto());
|
||||
|
||||
HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* loop_body = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
|
||||
|
||||
graph->AddBlock(loop_header);
|
||||
graph->AddBlock(loop_body);
|
||||
graph->AddBlock(exit);
|
||||
block->AddSuccessor(loop_header);
|
||||
loop_header->AddSuccessor(loop_body);
|
||||
loop_header->AddSuccessor(exit);
|
||||
loop_body->AddSuccessor(loop_header);
|
||||
|
||||
loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction();
|
||||
loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction()));
|
||||
|
||||
// Kill inside the loop body to prevent field gets inside the loop header
|
||||
// and the body to be GVN'ed.
|
||||
loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
|
||||
parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* field_set = loop_body->GetLastInstruction();
|
||||
loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction();
|
||||
loop_body->AddInstruction(new (&allocator) HGoto());
|
||||
|
||||
exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimBoolean,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
HInstruction* field_get_in_exit = exit->GetLastInstruction();
|
||||
exit->AddInstruction(new (&allocator) HExit());
|
||||
|
||||
ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
|
||||
ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
|
||||
ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
|
||||
|
||||
graph->BuildDominatorTree();
|
||||
{
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
GVNOptimization(graph, side_effects).Run();
|
||||
}
|
||||
|
||||
// Check that all field get instructions are still there.
|
||||
ASSERT_EQ(field_get_in_loop_header->GetBlock(), loop_header);
|
||||
ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
|
||||
// The exit block is dominated by the loop header, whose field get
|
||||
// does not get killed by the loop flags.
|
||||
ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
|
||||
|
||||
// Now remove the field set, and check that all field get instructions have been GVN'ed.
|
||||
loop_body->RemoveInstruction(field_set);
|
||||
{
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
GVNOptimization(graph, side_effects).Run();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(field_get_in_loop_header->GetBlock() == nullptr);
|
||||
ASSERT_TRUE(field_get_in_loop_body->GetBlock() == nullptr);
|
||||
ASSERT_TRUE(field_get_in_exit->GetBlock() == nullptr);
|
||||
}
|
||||
|
||||
// Test that inner loops affect the side effects of the outer loop.
|
||||
TEST_F(GVNTest, LoopSideEffects) {
|
||||
ArenaPool pool;
|
||||
ArenaAllocator allocator(&pool);
|
||||
|
||||
static const SideEffects kCanTriggerGC = SideEffects::CanTriggerGC();
|
||||
|
||||
HGraph* graph = CreateGraph(&allocator);
|
||||
HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
|
||||
graph->AddBlock(entry);
|
||||
graph->SetEntryBlock(entry);
|
||||
|
||||
HBasicBlock* outer_loop_header = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* outer_loop_body = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* outer_loop_exit = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* inner_loop_header = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* inner_loop_body = new (&allocator) HBasicBlock(graph);
|
||||
HBasicBlock* inner_loop_exit = new (&allocator) HBasicBlock(graph);
|
||||
|
||||
graph->AddBlock(outer_loop_header);
|
||||
graph->AddBlock(outer_loop_body);
|
||||
graph->AddBlock(outer_loop_exit);
|
||||
graph->AddBlock(inner_loop_header);
|
||||
graph->AddBlock(inner_loop_body);
|
||||
graph->AddBlock(inner_loop_exit);
|
||||
|
||||
entry->AddSuccessor(outer_loop_header);
|
||||
outer_loop_header->AddSuccessor(outer_loop_body);
|
||||
outer_loop_header->AddSuccessor(outer_loop_exit);
|
||||
outer_loop_body->AddSuccessor(inner_loop_header);
|
||||
inner_loop_header->AddSuccessor(inner_loop_body);
|
||||
inner_loop_header->AddSuccessor(inner_loop_exit);
|
||||
inner_loop_body->AddSuccessor(inner_loop_header);
|
||||
inner_loop_exit->AddSuccessor(outer_loop_header);
|
||||
|
||||
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
|
||||
dex::TypeIndex(0),
|
||||
0,
|
||||
Primitive::kPrimBoolean);
|
||||
entry->AddInstruction(parameter);
|
||||
entry->AddInstruction(new (&allocator) HGoto());
|
||||
outer_loop_header->AddInstruction(new (&allocator) HSuspendCheck());
|
||||
outer_loop_header->AddInstruction(new (&allocator) HIf(parameter));
|
||||
outer_loop_body->AddInstruction(new (&allocator) HGoto());
|
||||
inner_loop_header->AddInstruction(new (&allocator) HSuspendCheck());
|
||||
inner_loop_header->AddInstruction(new (&allocator) HIf(parameter));
|
||||
inner_loop_body->AddInstruction(new (&allocator) HGoto());
|
||||
inner_loop_exit->AddInstruction(new (&allocator) HGoto());
|
||||
outer_loop_exit->AddInstruction(new (&allocator) HExit());
|
||||
|
||||
graph->BuildDominatorTree();
|
||||
|
||||
ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
|
||||
*outer_loop_header->GetLoopInformation()));
|
||||
|
||||
// Check that the only side effect of loops is to potentially trigger GC.
|
||||
{
|
||||
// Make one block with a side effect.
|
||||
entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter,
|
||||
parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0));
|
||||
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
|
||||
ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
|
||||
ASSERT_FALSE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
|
||||
ASSERT_FALSE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
|
||||
ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).Equals(kCanTriggerGC));
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(inner_loop_header).Equals(kCanTriggerGC));
|
||||
}
|
||||
|
||||
// Check that the side effects of the outer loop does not affect the inner loop.
|
||||
{
|
||||
outer_loop_body->InsertInstructionBefore(
|
||||
new (&allocator) HInstanceFieldSet(parameter,
|
||||
parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0),
|
||||
outer_loop_body->GetLastInstruction());
|
||||
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
|
||||
ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
|
||||
ASSERT_FALSE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(inner_loop_header).Equals(kCanTriggerGC));
|
||||
}
|
||||
|
||||
// Check that the side effects of the inner loop affects the outer loop.
|
||||
{
|
||||
outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction());
|
||||
inner_loop_body->InsertInstructionBefore(
|
||||
new (&allocator) HInstanceFieldSet(parameter,
|
||||
parameter,
|
||||
nullptr,
|
||||
Primitive::kPrimNot,
|
||||
MemberOffset(42),
|
||||
false,
|
||||
kUnknownFieldIndex,
|
||||
kUnknownClassDefIndex,
|
||||
graph->GetDexFile(),
|
||||
0),
|
||||
inner_loop_body->GetLastInstruction());
|
||||
|
||||
SideEffectsAnalysis side_effects(graph);
|
||||
side_effects.Run();
|
||||
|
||||
ASSERT_TRUE(side_effects.GetBlockEffects(entry).DoesAnyWrite());
|
||||
ASSERT_FALSE(side_effects.GetBlockEffects(outer_loop_body).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(outer_loop_header).DoesAnyWrite());
|
||||
ASSERT_TRUE(side_effects.GetLoopEffects(inner_loop_header).DoesAnyWrite());
|
||||
}
|
||||
}
|
||||
} // namespace art
|
Loading…
Add table
Add a link
Reference in a new issue