summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/common_compiler_test.cc9
-rw-r--r--compiler/common_compiler_test.h2
-rw-r--r--compiler/dex/quick/arm64/int_arm64.cc1
-rw-r--r--compiler/image_writer.cc6
-rw-r--r--compiler/oat_test.cc4
-rw-r--r--compiler/oat_writer.cc32
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc2
-rw-r--r--compiler/optimizing/graph_checker.cc68
-rw-r--r--compiler/optimizing/graph_checker.h18
-rw-r--r--compiler/optimizing/graph_visualizer.h1
-rw-r--r--compiler/optimizing/gvn.h21
-rw-r--r--compiler/optimizing/live_ranges_test.cc10
-rw-r--r--compiler/optimizing/optimization.cc6
-rw-r--r--compiler/optimizing/optimization.h1
-rw-r--r--compiler/optimizing/optimizing_compiler.cc24
-rw-r--r--compiler/optimizing/ssa_builder.cc14
-rw-r--r--compiler/optimizing/ssa_builder.h15
-rw-r--r--compiler/optimizing/ssa_phi_elimination.cc8
-rw-r--r--compiler/optimizing/ssa_test.cc36
-rw-r--r--compiler/utils/arm/assembler_arm.cc3
20 files changed, 204 insertions, 77 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 97387a1c9c..a3d9a0bd6d 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -60,14 +60,18 @@ void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) {
const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
uint32_t mapping_table_offset = mapping_table.empty() ? 0u
: sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size();
- OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset,
+ const std::vector<uint8_t>& gc_map = *compiled_method->GetGcMap();
+ uint32_t gc_map_offset = gc_map.empty() ? 0u
+ : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table.size() + gc_map.size();
+ OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset,
compiled_method->GetFrameSizeInBytes(),
compiled_method->GetCoreSpillMask(),
compiled_method->GetFpSpillMask(), code_size);
header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
- size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
+ size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size() +
+ gc_map.size();
size_t code_offset = compiled_method->AlignCode(size - code_size);
size_t padding = code_offset - (size - code_size);
chunk->reserve(padding + size);
@@ -75,6 +79,7 @@ void CommonCompilerTest::MakeExecutable(mirror::ArtMethod* method) {
memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
+ chunk->insert(chunk->begin(), gc_map.begin(), gc_map.end());
chunk->insert(chunk->begin(), padding, 0);
chunk->insert(chunk->end(), code->begin(), code->end());
CHECK_EQ(padding + size, chunk->size());
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 20b750c55b..9cffbc86f3 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -42,7 +42,7 @@ class CommonCompilerTest : public CommonRuntimeTest {
~CommonCompilerTest();
// Create an OatMethod based on pointers (for unit tests).
- OatFile::OatMethod CreateOatMethod(const void* code, const uint8_t* gc_map);
+ OatFile::OatMethod CreateOatMethod(const void* code);
void MakeExecutable(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index b12fc0a313..57e67d534b 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -483,6 +483,7 @@ bool Arm64Mir2Lir::SmallLiteralDivRem64(Instruction::Code dalvik_opcode, bool is
} else {
reconstructed_imm = base + 1;
}
+ DCHECK_EQ(reconstructed_imm, magic_table[lit].magic64) << " for literal " << lit;
}
// Load the magic constant in two instructions.
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 4f5026dee3..03899cc755 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1125,7 +1125,6 @@ void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) {
copy->SetEntryPointFromJniPtrSize<kVerifyNone>(orig->GetEntryPointFromJni(), target_ptr_size_);
copy->SetEntryPointFromQuickCompiledCodePtrSize<kVerifyNone>(
orig->GetEntryPointFromQuickCompiledCode(), target_ptr_size_);
- copy->SetNativeGcMapPtrSize<kVerifyNone>(orig->GetNativeGcMap(), target_ptr_size_);
// The resolution method has a special trampoline to call.
Runtime* runtime = Runtime::Current();
@@ -1186,11 +1185,6 @@ void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) {
// Note this is not the code_ pointer, that is handled above.
copy->SetEntryPointFromJniPtrSize<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_),
target_ptr_size_);
- } else {
- // Normal (non-abstract non-native) methods have various tables to relocate.
- uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
- const uint8_t* native_gc_map = GetOatAddress(native_gc_map_offset);
- copy->SetNativeGcMapPtrSize<kVerifyNone>(native_gc_map, target_ptr_size_);
}
// Interpreter entrypoint:
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index ce4ed6d22b..9fe98e3663 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -190,8 +190,8 @@ TEST_F(OatTest, OatHeaderSizeCheck) {
// If this test is failing and you have to update these constants,
// it is time to update OatHeader::kOatVersion
EXPECT_EQ(84U, sizeof(OatHeader));
- EXPECT_EQ(8U, sizeof(OatMethodOffsets));
- EXPECT_EQ(24U, sizeof(OatQuickMethodHeader));
+ EXPECT_EQ(4U, sizeof(OatMethodOffsets));
+ EXPECT_EQ(28U, sizeof(OatQuickMethodHeader));
EXPECT_EQ(91 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints));
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c6beb36178..a57f892c58 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -510,15 +510,18 @@ struct OatWriter::GcMapDataAccess {
}
static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
- return oat_class->method_offsets_[method_offsets_index].gc_map_offset_;
+ uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_;
+ return offset == 0u ? 0u :
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
ALWAYS_INLINE {
- oat_class->method_offsets_[method_offsets_index].gc_map_offset_ = offset;
+ oat_class->method_headers_[method_offsets_index].gc_map_offset_ =
+ (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
- static const char* Name() ALWAYS_INLINE {
+ static const char* Name() {
return "GC map";
}
};
@@ -540,7 +543,7 @@ struct OatWriter::MappingTableDataAccess {
(oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
- static const char* Name() ALWAYS_INLINE {
+ static const char* Name() {
return "mapping table";
}
};
@@ -562,7 +565,7 @@ struct OatWriter::VmapTableDataAccess {
(oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
}
- static const char* Name() ALWAYS_INLINE {
+ static const char* Name() {
return "vmap table";
}
};
@@ -764,6 +767,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
uint32_t mapping_table_offset = method_header->mapping_table_offset_;
uint32_t vmap_table_offset = method_header->vmap_table_offset_;
+ uint32_t gc_map_offset = method_header->gc_map_offset_;
// The code offset was 0 when the mapping/vmap table offset was set, so it's set
// to 0-offset and we need to adjust it by code_offset.
uint32_t code_offset = quick_code_offset - thumb_offset;
@@ -775,12 +779,16 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
vmap_table_offset += code_offset;
DCHECK_LT(vmap_table_offset, code_offset);
}
+ if (gc_map_offset != 0u) {
+ gc_map_offset += code_offset;
+ DCHECK_LT(gc_map_offset, code_offset);
+ }
uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
*method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
- frame_size_in_bytes, core_spill_mask, fp_spill_mask,
- code_size);
+ gc_map_offset, frame_size_in_bytes, core_spill_mask,
+ fp_spill_mask, code_size);
if (!deduped) {
// Update offsets. (Checksum is updated when writing.)
@@ -909,7 +917,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
- OatMethodOffsets offsets(0u, 0u);
+ OatMethodOffsets offsets(0u);
if (compiled_method != nullptr) {
DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -920,7 +928,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
// Unchecked as we hold mutator_lock_ on entry.
ScopedObjectAccessUnchecked soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
NullHandle<mirror::ClassLoader>(),
@@ -936,7 +944,6 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
}
// Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
method->SetQuickOatCodeOffset(offsets.code_offset_);
- method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
return true;
}
@@ -1157,7 +1164,7 @@ template <typename DataAccess>
class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
public:
WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
- size_t relative_offset)
+ size_t relative_offset)
: OatDexMethodVisitor(writer, relative_offset),
out_(out),
file_offset_(file_offset) {
@@ -1179,7 +1186,8 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
DCHECK((map_size == 0u && map_offset == 0u) ||
(map_size != 0u && map_offset != 0u && map_offset <= offset_))
- << PrettyMethod(it.GetMemberIndex(), *dex_file_);
+ << map_size << " " << map_offset << " " << offset_ << " "
+ << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
if (map_size != 0u && map_offset == offset_) {
if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
ReportWriteFailure(it);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 69f031aab1..83d04b1a58 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2896,7 +2896,7 @@ void ParallelMoveResolverX86_64::EmitMove(size_t index) {
__ movss(Address(CpuRegister(RSP), destination.GetStackIndex()),
source.As<XmmRegister>());
} else {
- DCHECK(destination.IsDoubleStackSlot());
+ DCHECK(destination.IsDoubleStackSlot()) << destination;
__ movsd(Address(CpuRegister(RSP), destination.GetStackIndex()),
source.As<XmmRegister>());
}
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 1953241a2a..5d712feb2b 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -342,4 +342,72 @@ void SSAChecker::VisitPhi(HPhi* phi) {
}
}
+static Primitive::Type PrimitiveKind(Primitive::Type type) {
+ switch (type) {
+ case Primitive::kPrimBoolean:
+ case Primitive::kPrimByte:
+ case Primitive::kPrimShort:
+ case Primitive::kPrimChar:
+ case Primitive::kPrimInt:
+ return Primitive::kPrimInt;
+ default:
+ return type;
+ }
+}
+
+void SSAChecker::VisitCondition(HCondition* op) {
+ VisitInstruction(op);
+ // TODO: check inputs types, and special case the `null` check.
+ if (op->GetType() != Primitive::kPrimBoolean) {
+ std::stringstream error;
+ error << "Condition " << op->DebugName() << " " << op->GetId()
+ << " has a non-boolean result type: "
+ << op->GetType() << ".";
+ errors_.push_back(error.str());
+ }
+}
+
+void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
+ VisitInstruction(op);
+ if (op->IsUShr() || op->IsShr() || op->IsShl()) {
+ if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
+ std::stringstream error;
+ error << "Shift operation " << op->DebugName() << " " << op->GetId()
+ << " has a non-int kind second input: "
+ << op->InputAt(1)->DebugName() << " of type " << op->InputAt(1)->GetType()
+ << ".";
+ errors_.push_back(error.str());
+ }
+ } else {
+ if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
+ std::stringstream error;
+ error << "Binary operation " << op->DebugName() << " " << op->GetId()
+ << " has inputs of different type: "
+ << op->InputAt(0)->GetType() << ", and " << op->InputAt(1)->GetType()
+ << ".";
+ errors_.push_back(error.str());
+ }
+ }
+
+ if (op->IsCompare()) {
+ if (op->GetType() != Primitive::kPrimInt) {
+ std::stringstream error;
+ error << "Compare operation " << op->GetId()
+ << " has a non-int result type: "
+ << op->GetType() << ".";
+ errors_.push_back(error.str());
+ }
+ } else {
+ // Use the first input, so that we can also make this check for shift operations.
+ if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
+ std::stringstream error;
+ error << "Binary operation " << op->DebugName() << " " << op->GetId()
+ << " has a result type different than its input type: "
+ << op->GetType() << ", and " << op->InputAt(1)->GetType()
+ << ".";
+ errors_.push_back(error.str());
+ }
+ }
+}
+
} // namespace art
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 8ba8cb16b1..b6c9f1720c 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -24,11 +24,11 @@
namespace art {
// A control-flow graph visitor performing various checks.
-class GraphChecker : public HGraphVisitor {
+class GraphChecker : public HGraphDelegateVisitor {
public:
GraphChecker(ArenaAllocator* allocator, HGraph* graph,
const char* dump_prefix = "art::GraphChecker: ")
- : HGraphVisitor(graph),
+ : HGraphDelegateVisitor(graph),
allocator_(allocator),
dump_prefix_(dump_prefix) {}
@@ -36,10 +36,10 @@ class GraphChecker : public HGraphVisitor {
virtual void Run() { VisitInsertionOrder(); }
// Check `block`.
- virtual void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
+ void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
// Check `instruction`.
- virtual void VisitInstruction(HInstruction* instruction) OVERRIDE;
+ void VisitInstruction(HInstruction* instruction) OVERRIDE;
// Was the last visit of the graph valid?
bool IsValid() const {
@@ -82,7 +82,7 @@ class SSAChecker : public GraphChecker {
: GraphChecker(allocator, graph, "art::SSAChecker: ") {}
// Check the whole graph (in reverse post-order).
- virtual void Run() {
+ void Run() OVERRIDE {
// VisitReversePostOrder is used instead of VisitInsertionOrder,
// as the latter might visit dead blocks removed by the dominator
// computation.
@@ -90,13 +90,15 @@ class SSAChecker : public GraphChecker {
}
// Perform SSA form checks on `block`.
- virtual void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
+ void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
// Loop-related checks from block `loop_header`.
void CheckLoop(HBasicBlock* loop_header);
// Perform SSA form checks on instructions.
- virtual void VisitInstruction(HInstruction* instruction) OVERRIDE;
- virtual void VisitPhi(HPhi* phi) OVERRIDE;
+ void VisitInstruction(HInstruction* instruction) OVERRIDE;
+ void VisitPhi(HPhi* phi) OVERRIDE;
+ void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
+ void VisitCondition(HCondition* op) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(SSAChecker);
diff --git a/compiler/optimizing/graph_visualizer.h b/compiler/optimizing/graph_visualizer.h
index 4d8bec2422..60d996ba88 100644
--- a/compiler/optimizing/graph_visualizer.h
+++ b/compiler/optimizing/graph_visualizer.h
@@ -30,7 +30,6 @@ class HGraph;
// TODO: Create an analysis/optimization abstraction.
static const char* kLivenessPassName = "liveness";
static const char* kRegisterAllocatorPassName = "register";
-static const char* kGVNPassName = "gvn";
/**
* If enabled, emits compilation information suitable for the c1visualizer tool
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index a841d5f65a..8e739cb6d3 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -166,10 +166,10 @@ class ValueSet : public ArenaObject<kArenaAllocMisc> {
/**
* Optimization phase that removes redundant instruction.
*/
-class GlobalValueNumberer : public HOptimization {
+class GlobalValueNumberer : public ValueObject {
public:
GlobalValueNumberer(ArenaAllocator* allocator, HGraph* graph)
- : HOptimization(graph, true, "GVN"),
+ : graph_(graph),
allocator_(allocator),
block_effects_(allocator, graph->GetBlocks().Size()),
loop_effects_(allocator, graph->GetBlocks().Size()),
@@ -187,7 +187,7 @@ class GlobalValueNumberer : public HOptimization {
}
}
- void Run() OVERRIDE;
+ void Run();
private:
// Per-block GVN. Will also update the ValueSet of the dominated and
@@ -202,6 +202,8 @@ class GlobalValueNumberer : public HOptimization {
SideEffects GetLoopEffects(HBasicBlock* block) const;
SideEffects GetBlockEffects(HBasicBlock* block) const;
+ HGraph* graph_;
+
ArenaAllocator* const allocator_;
// Side effects of individual blocks, that is the union of the side effects
@@ -224,6 +226,19 @@ class GlobalValueNumberer : public HOptimization {
DISALLOW_COPY_AND_ASSIGN(GlobalValueNumberer);
};
+class GVNOptimization : public HOptimization {
+ public:
+ explicit GVNOptimization(HGraph* graph) : HOptimization(graph, true, "GVN") {}
+
+ void Run() OVERRIDE {
+ GlobalValueNumberer gvn(graph_->GetArena(), graph_);
+ gvn.Run();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GVNOptimization);
+};
+
} // namespace art
#endif // ART_COMPILER_OPTIMIZING_GVN_H_
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 89c949563b..e3c6fec23b 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -386,7 +386,7 @@ TEST(LiveRangesTest, CFG4) {
Instruction::ADD_INT, 1 << 8,
Instruction::GOTO | 0x300,
Instruction::ADD_INT, 1 << 8,
- Instruction::RETURN | 1 << 8);
+ Instruction::RETURN);
ArenaPool pool;
ArenaAllocator allocator(&pool);
@@ -410,7 +410,10 @@ TEST(LiveRangesTest, CFG4) {
interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval();
range = interval->GetFirstRange();
ASSERT_EQ(4u, range->GetStart());
- ASSERT_EQ(28u, range->GetEnd());
+ ASSERT_EQ(17u, range->GetEnd());
+ range = range->GetNext();
+ ASSERT_EQ(20u, range->GetStart());
+ ASSERT_EQ(23u, range->GetEnd());
ASSERT_TRUE(range->GetNext() == nullptr);
// Test for the first add.
@@ -429,9 +432,8 @@ TEST(LiveRangesTest, CFG4) {
ASSERT_EQ(26u, range->GetEnd());
ASSERT_TRUE(range->GetNext() == nullptr);
- // Test for the phi, which is unused.
HPhi* phi = liveness.GetInstructionFromSsaIndex(4)->AsPhi();
- ASSERT_EQ(phi->NumberOfUses(), 0u);
+ ASSERT_EQ(phi->NumberOfUses(), 1u);
interval = phi->GetLiveInterval();
range = interval->GetFirstRange();
ASSERT_EQ(26u, range->GetStart());
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index d1178d5798..b99f6784f7 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -27,13 +27,15 @@ void HOptimization::Check() {
SSAChecker checker(graph_->GetArena(), graph_);
checker.Run();
if (!checker.IsValid()) {
- LOG(FATAL) << Dumpable<SSAChecker>(checker);
+ LOG(FATAL) << "Error after " << GetPassName() << ": "
+ << Dumpable<SSAChecker>(checker);
}
} else {
GraphChecker checker(graph_->GetArena(), graph_);
checker.Run();
if (!checker.IsValid()) {
- LOG(FATAL) << Dumpable<GraphChecker>(checker);
+ LOG(FATAL) << "Error after " << GetPassName() << ": "
+ << Dumpable<GraphChecker>(checker);
}
}
}
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index d281248f4a..e36ef198b6 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -17,7 +17,6 @@
#ifndef ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
#define ART_COMPILER_OPTIMIZING_OPTIMIZATION_H_
-#include "graph_visualizer.h"
#include "nodes.h"
namespace art {
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 42ac77d1d8..d8533eb8bf 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -35,6 +35,7 @@
#include "nodes.h"
#include "prepare_for_register_allocation.h"
#include "register_allocator.h"
+#include "ssa_builder.h"
#include "ssa_phi_elimination.h"
#include "ssa_liveness_analysis.h"
#include "utils/arena_allocator.h"
@@ -191,21 +192,31 @@ static bool CanOptimize(const DexFile::CodeItem& code_item) {
}
static void RunOptimizations(HGraph* graph, const HGraphVisualizer& visualizer) {
+ TransformToSsa ssa(graph);
HDeadCodeElimination opt1(graph);
HConstantFolding opt2(graph);
SsaRedundantPhiElimination opt3(graph);
SsaDeadPhiElimination opt4(graph);
InstructionSimplifier opt5(graph);
- GlobalValueNumberer opt6(graph->GetArena(), graph);
+ GVNOptimization opt6(graph);
InstructionSimplifier opt7(graph);
- HOptimization* optimizations[] = { &opt1, &opt2, &opt3, &opt4, &opt5, &opt6, &opt7 };
+ HOptimization* optimizations[] = {
+ &ssa,
+ &opt1,
+ &opt2,
+ &opt3,
+ &opt4,
+ &opt5,
+ &opt6,
+ &opt7
+ };
for (size_t i = 0; i < arraysize(optimizations); ++i) {
HOptimization* optimization = optimizations[i];
optimization->Run();
- optimization->Check();
visualizer.DumpGraph(optimization->GetPassName());
+ optimization->Check();
}
}
@@ -271,11 +282,6 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
&& CanOptimize(*code_item)
&& RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set)) {
optimized_compiled_methods_++;
- graph->BuildDominatorTree();
- graph->TransformToSSA();
- visualizer.DumpGraph("ssa");
- graph->FindNaturalLoops();
-
RunOptimizations(graph, visualizer);
PrepareForRegisterAllocation(graph).Run();
@@ -321,7 +327,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
graph->FindNaturalLoops();
SsaRedundantPhiElimination(graph).Run();
SsaDeadPhiElimination(graph).Run();
- GlobalValueNumberer(graph->GetArena(), graph).Run();
+ GVNOptimization(graph).Run();
SsaLivenessAnalysis liveness(*graph, codegen);
liveness.Analyze();
visualizer.DumpGraph(kLivenessPassName);
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index b2cc11996e..edfafcdd83 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -18,6 +18,7 @@
#include "nodes.h"
#include "ssa_type_propagation.h"
+#include "ssa_phi_elimination.h"
namespace art {
@@ -41,11 +42,20 @@ void SsaBuilder::BuildSsa() {
}
}
- // 3) Propagate types of phis.
+ // 3) Remove dead phis. This will remove phis that are only used by environments:
+ // at the DEX level, the type of these phis does not need to be consistent, but
+ // our code generator will complain if the inputs of a phi do not have the same
+ // type (modulo the special case of `null`).
+ SsaDeadPhiElimination dead_phis(GetGraph());
+ dead_phis.Run();
+
+ // 4) Propagate types of phis. At this point, phis are typed void in the general
+ // case, or float or double when we created a floating-point equivalent. So we
+ // need to propagate the types across phis to give them a correct type.
SsaTypePropagation type_propagation(GetGraph());
type_propagation.Run();
- // 4) Clear locals.
+ // 5) Clear locals.
// TODO: Move this to a dead code eliminator phase.
for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
!it.Done();
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index 2207cd6bfa..5ab328fe23 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -18,9 +18,24 @@
#define ART_COMPILER_OPTIMIZING_SSA_BUILDER_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
+class TransformToSsa : public HOptimization {
+ public:
+ explicit TransformToSsa(HGraph* graph) : HOptimization(graph, true, "ssa transform") {}
+
+ void Run() OVERRIDE {
+ graph_->BuildDominatorTree();
+ graph_->TransformToSSA();
+ graph_->FindNaturalLoops();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransformToSsa);
+};
+
static constexpr int kDefaultNumberOfLoops = 2;
class SsaBuilder : public HGraphVisitor {
diff --git a/compiler/optimizing/ssa_phi_elimination.cc b/compiler/optimizing/ssa_phi_elimination.cc
index 56979e1c6a..58cea771b9 100644
--- a/compiler/optimizing/ssa_phi_elimination.cc
+++ b/compiler/optimizing/ssa_phi_elimination.cc
@@ -24,6 +24,8 @@ void SsaDeadPhiElimination::Run() {
HBasicBlock* block = it.Current();
for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
HPhi* phi = inst_it.Current()->AsPhi();
+ // Set dead ahead of running through uses. The phi may have no use.
+ phi->SetDead();
for (HUseIterator<HInstruction> use_it(phi->GetUses()); !use_it.Done(); use_it.Advance()) {
HUseListNode<HInstruction>* current = use_it.Current();
HInstruction* user = current->GetUser();
@@ -31,8 +33,6 @@ void SsaDeadPhiElimination::Run() {
worklist_.Add(phi);
phi->SetLive();
break;
- } else {
- phi->SetDead();
}
}
}
@@ -65,8 +65,8 @@ void SsaDeadPhiElimination::Run() {
use_it.Advance()) {
HUseListNode<HInstruction>* user_node = use_it.Current();
HInstruction* user = user_node->GetUser();
- DCHECK(user->IsLoopHeaderPhi());
- DCHECK(user->AsPhi()->IsDead());
+ DCHECK(user->IsLoopHeaderPhi()) << user->GetId();
+ DCHECK(user->AsPhi()->IsDead()) << user->GetId();
// Just put itself as an input. The phi will be removed in this loop anyway.
user->SetRawInputAt(user_node->GetIndex(), user);
current->RemoveUser(user, user_node->GetIndex());
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index fffe5c2b44..6174dd49a1 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -199,29 +199,31 @@ TEST(SsaTest, Loop1) {
// Test that we create a phi for an initialized local at entry of a loop.
const char* expected =
"BasicBlock 0, succ: 1\n"
- " 0: IntConstant 0 [6, 4, 2, 2]\n"
- " 1: Goto\n"
- "BasicBlock 1, pred: 0, succ: 5, 6\n"
- " 2: Equal(0, 0) [3]\n"
- " 3: If(2)\n"
- "BasicBlock 2, pred: 3, 6, succ: 3\n"
- " 4: Phi(6, 0) [6]\n"
+ " 0: IntConstant 0 [6, 3, 3]\n"
+ " 1: IntConstant 4 [6]\n"
+ " 2: Goto\n"
+ "BasicBlock 1, pred: 0, succ: 4, 2\n"
+ " 3: Equal(0, 0) [4]\n"
+ " 4: If(3)\n"
+ "BasicBlock 2, pred: 1, succ: 3\n"
" 5: Goto\n"
- "BasicBlock 3, pred: 5, 2, succ: 2\n"
- " 6: Phi(0, 4) [4]\n"
+ "BasicBlock 3, pred: 2, 4, succ: 5\n"
+ " 6: Phi(1, 0) [9]\n"
" 7: Goto\n"
- "BasicBlock 4\n"
- // Synthesized blocks to avoid critical edge.
- "BasicBlock 5, pred: 1, succ: 3\n"
+ "BasicBlock 4, pred: 1, succ: 3\n"
" 8: Goto\n"
- "BasicBlock 6, pred: 1, succ: 2\n"
- " 9: Goto\n";
+ "BasicBlock 5, pred: 3, succ: 6\n"
+ " 9: Return(6)\n"
+ "BasicBlock 6, pred: 5\n"
+ " 10: Exit\n";
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
- Instruction::IF_EQ, 3,
- Instruction::GOTO | 0x100,
- Instruction::GOTO | 0xFF00);
+ Instruction::IF_EQ, 4,
+ Instruction::CONST_4 | 4 << 12 | 0,
+ Instruction::GOTO | 0x200,
+ Instruction::GOTO | 0xFF00,
+ Instruction::RETURN | 0 << 8);
TestCode(data, expected);
}
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index 9c84bc1e37..0f28591775 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -205,10 +205,9 @@ uint32_t Address::encodingArm() const {
encoding = am_ | offset_;
}
} else {
- uint32_t imm5 = offset_;
uint32_t shift = shift_;
if (shift == RRX) {
- imm5 = 0;
+ CHECK_EQ(offset_, 0);
shift = ROR;
}
encoding = am_ | static_cast<uint32_t>(rm_) | shift << 5 | offset_ << 7 | B25;