diff options
| -rw-r--r-- | build/Android.common_test.mk | 6 | ||||
| -rw-r--r-- | build/Android.executable.mk | 3 | ||||
| -rw-r--r-- | build/Android.gtest.mk | 3 | ||||
| -rw-r--r-- | compiler/optimizing/builder.cc | 12 | ||||
| -rw-r--r-- | compiler/optimizing/builder.h | 3 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 108 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 84 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 82 | ||||
| -rw-r--r-- | compiler/optimizing/constant_folding.cc | 14 | ||||
| -rw-r--r-- | compiler/optimizing/constant_folding_test.cc | 55 | ||||
| -rw-r--r-- | compiler/optimizing/live_ranges_test.cc | 14 | ||||
| -rw-r--r-- | compiler/optimizing/locations.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/locations.h | 25 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 17 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 48 | ||||
| -rw-r--r-- | compiler/optimizing/register_allocator.cc | 26 | ||||
| -rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.h | 8 | ||||
| -rw-r--r-- | dalvikvm/Android.mk | 6 | ||||
| -rw-r--r-- | runtime/runtime.cc | 11 | ||||
| -rw-r--r-- | sigchainlib/Android.mk | 26 | ||||
| -rw-r--r-- | test/411-optimizing-arith/src/Main.java | 32 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 188 |
22 files changed, 570 insertions, 205 deletions
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk index ee72706b91..3e76d91aed 100644 --- a/build/Android.common_test.mk +++ b/build/Android.common_test.mk @@ -90,6 +90,12 @@ ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT ?= $(ART_TEST_FULL) # Do you want run-tests without a dex2oat? ART_TEST_RUN_TEST_NO_DEX2OAT ?= $(ART_TEST_FULL) +# Do you want run-tests with libartd.so? +ART_TEST_RUN_TEST_DEBUG ?= true + +# Do you want run-tests with libart.so? +ART_TEST_RUN_TEST_NDEBUG ?= $(ART_TEST_FULL) + # Do you want failed tests to have their artifacts cleaned up? ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true diff --git a/build/Android.executable.mk b/build/Android.executable.mk index 81f329751f..86f445faa2 100644 --- a/build/Android.executable.mk +++ b/build/Android.executable.mk @@ -54,9 +54,10 @@ define build-art-executable include $(CLEAR_VARS) LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) LOCAL_MODULE_TAGS := optional - LOCAL_SRC_FILES := $$(art_source) ../sigchainlib/sigchain.cc + LOCAL_SRC_FILES := $$(art_source) LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime $$(art_c_includes) LOCAL_SHARED_LIBRARIES += $$(art_shared_libraries) + LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain ifeq ($$(art_ndebug_or_debug),ndebug) LOCAL_MODULE := $$(art_executable) diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index f782d5c6a2..db7257a94d 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -332,9 +332,10 @@ define define-art-gtest LOCAL_MODULE_TAGS := tests endif LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION) - LOCAL_SRC_FILES := $$(art_gtest_filename) sigchainlib/sigchain.cc + LOCAL_SRC_FILES := $$(art_gtest_filename) LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime $$(art_gtest_extra_c_includes) LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries) libart-gtest + LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 2648d4d670..2f1a092ea8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -267,6 +267,13 @@ HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { } template<typename T> +void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) { + HInstruction* first = LoadLocal(instruction.VRegB(), type); + current_block_->AddInstruction(new (arena_) T(type, first)); + UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); +} + +template<typename T> void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) { HInstruction* first = LoadLocal(instruction.VRegB(), type); HInstruction* second = LoadLocal(instruction.VRegC(), type); @@ -678,6 +685,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::NEG_INT: { + Unop_12x<HNeg>(instruction, Primitive::kPrimInt); + break; + } + case Instruction::ADD_INT: { Binop_23x<HAdd>(instruction, Primitive::kPrimInt); break; diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index e68cdb0b1d..90e50ad951 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -95,6 +95,9 @@ class HGraphBuilder : public ValueObject { bool InitializeParameters(uint16_t number_of_parameters); template<typename T> + void Unop_12x(const Instruction& instruction, Primitive::Type type); + + template<typename T> void Binop_23x(const Instruction& instruction, Primitive::Type type); template<typename T> diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index a2cf670b0f..ebb1d6ae4b 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -656,7 +656,7 @@ void LocationsBuilderARM::VisitIf(HIf* if_instr) { new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); HInstruction* cond = if_instr->InputAt(0); if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); } } @@ -715,10 +715,10 @@ void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { void LocationsBuilderARM::VisitCondition(HCondition* comp) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1))); if (comp->NeedsMaterialization()) { - locations->SetOut(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } } @@ -1016,16 +1016,57 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderARM::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ rsbs(out.As<Register>(), in.As<Register>(), ShifterOperand(0)); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderARM::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); switch (add->GetResultType()) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong; - locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); - locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry); - locations->SetOut(Location::RequiresRegister()); + bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), output_overlaps); break; } @@ -1088,10 +1129,10 @@ void LocationsBuilderARM::VisitSub(HSub* sub) { switch (sub->GetResultType()) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong; - locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); - locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry); - locations->SetOut(Location::RequiresRegister()); + bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), output_overlaps); break; } @@ -1150,9 +1191,9 @@ void LocationsBuilderARM::VisitMul(HMul* mul) { switch (mul->GetResultType()) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; } @@ -1261,8 +1302,8 @@ void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instructi void LocationsBuilderARM::VisitNot(HNot* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { @@ -1274,9 +1315,9 @@ void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { void LocationsBuilderARM::VisitCompare(HCompare* compare) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { @@ -1332,9 +1373,8 @@ void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; - bool dies_at_entry = !is_object_type; - locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); - locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); // Temporary registers for the write barrier. if (is_object_type) { locations->AddTemp(Location::RequiresRegister()); @@ -1394,8 +1434,8 @@ void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instr void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { @@ -1481,10 +1521,9 @@ void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { @@ -1594,10 +1633,9 @@ void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); } else { - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); - locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetInAt(2, Location::RequiresRegister()); } } @@ -1684,8 +1722,8 @@ void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 041acdf91e..cc2be82b94 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -588,7 +588,7 @@ void LocationsBuilderX86::VisitIf(HIf* if_instr) { new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); HInstruction* cond = if_instr->InputAt(0); if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { - locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::Any()); } } @@ -699,8 +699,8 @@ void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) { void LocationsBuilderX86::VisitCondition(HCondition* comp) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); if (comp->NeedsMaterialization()) { locations->SetOut(Location::RequiresRegister()); } @@ -957,6 +957,47 @@ void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ negl(out.As<Register>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderX86::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); @@ -1279,9 +1320,9 @@ void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) { void LocationsBuilderX86::VisitCompare(HCompare* compare) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) { @@ -1350,12 +1391,11 @@ void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) || (field_type == Primitive::kPrimByte); // The register allocator does not support multiple // inputs that die at entry with one in a specific register. - bool dies_at_entry = !is_object_type && !is_byte_type; if (is_byte_type) { // Ensure the value is in a byte register. - locations->SetInAt(1, Location::RegisterLocation(EAX), dies_at_entry); + locations->SetInAt(1, Location::RegisterLocation(EAX)); } else { - locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry); + locations->SetInAt(1, Location::RequiresRegister()); } // Temporary registers for the write barrier. if (is_object_type) { @@ -1431,8 +1471,8 @@ void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { @@ -1521,10 +1561,9 @@ void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) { @@ -1637,16 +1676,13 @@ void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) { // We need the inputs to be different than the output in case of long operation. // In case of a byte operation, the register allocator does not support multiple // inputs that die at entry with one in a specific register. - bool dies_at_entry = value_type != Primitive::kPrimLong && !is_byte_type; - locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); - locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), dies_at_entry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); if (is_byte_type) { // Ensure the value is in a byte register. - locations->SetInAt(2, Location::ByteRegisterOrConstant( - EAX, instruction->InputAt(2)), dies_at_entry); + locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2))); } else { - locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), dies_at_entry); + locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2))); } } } @@ -1776,8 +1812,8 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); instruction->SetLocations(locations); } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5fa930512b..9df9d417d4 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -489,7 +489,7 @@ void LocationsBuilderX86_64::VisitIf(HIf* if_instr) { new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); HInstruction* cond = if_instr->InputAt(0); if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { - locations->SetInAt(0, Location::Any(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::Any()); } } @@ -598,8 +598,8 @@ void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) { void LocationsBuilderX86_64::VisitCondition(HCondition* comp) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::Any(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::Any()); if (comp->NeedsMaterialization()) { locations->SetOut(Location::RequiresRegister()); } @@ -676,9 +676,9 @@ void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual void LocationsBuilderX86_64::VisitCompare(HCompare* compare) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) { @@ -933,6 +933,47 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +void LocationsBuilderX86_64::VisitNeg(HNeg* neg) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) { + LocationSummary* locations = neg->GetLocations(); + Location out = locations->Out(); + Location in = locations->InAt(0); + switch (neg->GetResultType()) { + case Primitive::kPrimInt: + DCHECK(in.IsRegister()); + __ negl(out.As<CpuRegister>()); + break; + + case Primitive::kPrimLong: + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType(); + break; + + default: + LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); + } +} + void LocationsBuilderX86_64::VisitAdd(HAdd* add) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); @@ -1213,9 +1254,8 @@ void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instructio new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); Primitive::Type field_type = instruction->GetFieldType(); bool is_object_type = field_type == Primitive::kPrimNot; - bool dies_at_entry = !is_object_type; - locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); - locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); if (is_object_type) { // Temporary registers for the write barrier. locations->AddTemp(Location::RequiresRegister()); @@ -1272,8 +1312,8 @@ void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* in void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { @@ -1356,10 +1396,10 @@ void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) { void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + 1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) { @@ -1463,14 +1503,14 @@ void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) { locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); } else { - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetInAt( - 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); - locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); + 1, Location::RegisterOrConstant(instruction->InputAt(1))); + locations->SetInAt(2, Location::RequiresRegister()); if (value_type == Primitive::kPrimLong) { - locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); + locations->SetInAt(2, Location::RequiresRegister()); } else { - locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)), Location::kDiesAtEntry); + locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2))); } } } @@ -1582,8 +1622,8 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) { void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); - locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); - locations->SetOut(Location::RequiresRegister()); + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) { diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc index 0b3ad9809f..10a7e46299 100644 --- a/compiler/optimizing/constant_folding.cc +++ b/compiler/optimizing/constant_folding.cc @@ -31,11 +31,19 @@ void HConstantFolding::Run() { for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* inst = it.Current(); - // Constant folding: replace `c <- a op b' with a compile-time - // evaluation of `a op b' if `a' and `b' are constant. if (inst->IsBinaryOperation()) { + // Constant folding: replace `op(a, b)' with a constant at + // compile time if `a' and `b' are both constants. HConstant* constant = - inst->AsBinaryOperation()->TryStaticEvaluation(graph_->GetArena()); + inst->AsBinaryOperation()->TryStaticEvaluation(); + if (constant != nullptr) { + inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant); + } + } else if (inst->IsUnaryOperation()) { + // Constant folding: replace `op(a)' with a constant at compile + // time if `a' is a constant. + HConstant* constant = + inst->AsUnaryOperation()->TryStaticEvaluation(); if (constant != nullptr) { inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant); } diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc index ec2ff33590..09bf2c8d7d 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -72,6 +72,61 @@ static void TestCode(const uint16_t* data, /** + * Tiny three-register program exercising int constant folding on negation. + * + * 16-bit + * offset + * ------ + * v0 <- 1 0. const/4 v0, #+1 + * v1 <- -v0 1. neg-int v0, v1 + * return v1 2. return v1 + */ +TEST(ConstantFolding, IntConstantFoldingNegation) { + const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( + Instruction::CONST_4 | 0 << 8 | 1 << 12, + Instruction::NEG_INT | 1 << 8 | 0 << 12, + Instruction::RETURN | 1 << 8); + + std::string expected_before = + "BasicBlock 0, succ: 1\n" + " 2: IntConstant [5]\n" + " 10: SuspendCheck\n" + " 11: Goto 1\n" + "BasicBlock 1, pred: 0, succ: 2\n" + " 5: Neg(2) [8]\n" + " 8: Return(5)\n" + "BasicBlock 2, pred: 1\n" + " 9: Exit\n"; + + // Expected difference after constant folding. + diff_t expected_cf_diff = { + { " 2: IntConstant [5]\n", " 2: IntConstant\n" }, + { " 5: Neg(2) [8]\n", " 12: IntConstant [8]\n" }, + { " 8: Return(5)\n", " 8: Return(12)\n" } + }; + std::string expected_after_cf = Patch(expected_before, expected_cf_diff); + + // Check the value of the computed constant. + auto check_after_cf = [](HGraph* graph) { + HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction(); + ASSERT_TRUE(inst->IsIntConstant()); + ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1); + }; + + // Expected difference after dead code elimination. + diff_t expected_dce_diff = { + { " 2: IntConstant\n", removed }, + }; + std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff); + + TestCode(data, + expected_before, + expected_after_cf, + expected_after_dce, + check_after_cf); +} + +/** * Tiny three-register program exercising int constant folding on addition. * * 16-bit diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index d5f4f902c8..89c949563b 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -73,7 +73,7 @@ TEST(LiveRangesTest, CFG1) { LiveRange* range = interval->GetFirstRange(); ASSERT_EQ(2u, range->GetStart()); // Last use is the return instruction. - ASSERT_EQ(9u, range->GetEnd()); + ASSERT_EQ(8u, range->GetEnd()); HBasicBlock* block = graph->GetBlocks().Get(1); ASSERT_TRUE(block->GetLastInstruction()->IsReturn()); ASSERT_EQ(8u, block->GetLastInstruction()->GetLifetimePosition()); @@ -119,7 +119,7 @@ TEST(LiveRangesTest, CFG2) { LiveRange* range = interval->GetFirstRange(); ASSERT_EQ(2u, range->GetStart()); // Last use is the return instruction. - ASSERT_EQ(23u, range->GetEnd()); + ASSERT_EQ(22u, range->GetEnd()); HBasicBlock* block = graph->GetBlocks().Get(3); ASSERT_TRUE(block->GetLastInstruction()->IsReturn()); ASSERT_EQ(22u, block->GetLastInstruction()->GetLifetimePosition()); @@ -193,7 +193,7 @@ TEST(LiveRangesTest, CFG3) { range = interval->GetFirstRange(); ASSERT_EQ(22u, liveness.GetInstructionFromSsaIndex(2)->GetLifetimePosition()); ASSERT_EQ(22u, range->GetStart()); - ASSERT_EQ(25u, range->GetEnd()); + ASSERT_EQ(24u, range->GetEnd()); ASSERT_TRUE(range->GetNext() == nullptr); } @@ -263,7 +263,7 @@ TEST(LiveRangesTest, Loop1) { range = interval->GetFirstRange(); // The instruction is live until the return instruction after the loop. ASSERT_EQ(6u, range->GetStart()); - ASSERT_EQ(27u, range->GetEnd()); + ASSERT_EQ(26u, range->GetEnd()); ASSERT_TRUE(range->GetNext() == nullptr); // Test for the phi. @@ -271,7 +271,7 @@ TEST(LiveRangesTest, Loop1) { range = interval->GetFirstRange(); // Instruction is consumed by the if. ASSERT_EQ(14u, range->GetStart()); - ASSERT_EQ(16u, range->GetEnd()); + ASSERT_EQ(17u, range->GetEnd()); ASSERT_TRUE(range->GetNext() == nullptr); } @@ -338,7 +338,7 @@ TEST(LiveRangesTest, Loop2) { range = range->GetNext(); ASSERT_TRUE(range != nullptr); ASSERT_EQ(24u, range->GetStart()); - ASSERT_EQ(27u, range->GetEnd()); + ASSERT_EQ(26u, range->GetEnd()); // Test for the add instruction. HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd(); @@ -410,7 +410,7 @@ TEST(LiveRangesTest, CFG4) { interval = liveness.GetInstructionFromSsaIndex(1)->GetLiveInterval(); range = interval->GetFirstRange(); ASSERT_EQ(4u, range->GetStart()); - ASSERT_EQ(29u, range->GetEnd()); + ASSERT_EQ(28u, range->GetEnd()); ASSERT_TRUE(range->GetNext() == nullptr); // Test for the first add. diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc index 1637484799..ed5e260a5b 100644 --- a/compiler/optimizing/locations.cc +++ b/compiler/optimizing/locations.cc @@ -25,16 +25,14 @@ LocationSummary::LocationSummary(HInstruction* instruction, CallKind call_kind) temps_(instruction->GetBlock()->GetGraph()->GetArena(), 0), environment_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->EnvironmentSize()), - dies_at_entry_(instruction->GetBlock()->GetGraph()->GetArena(), instruction->InputCount()), + output_overlaps_(true), call_kind_(call_kind), stack_mask_(nullptr), register_mask_(0), live_registers_() { inputs_.SetSize(instruction->InputCount()); - dies_at_entry_.SetSize(instruction->InputCount()); for (size_t i = 0; i < instruction->InputCount(); ++i) { inputs_.Put(i, Location()); - dies_at_entry_.Put(i, false); } environment_.SetSize(instruction->EnvironmentSize()); for (size_t i = 0; i < instruction->EnvironmentSize(); ++i) { diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h index dcf70f27b0..11bcd78521 100644 --- a/compiler/optimizing/locations.h +++ b/compiler/optimizing/locations.h @@ -34,7 +34,7 @@ class HInstruction; */ class Location : public ValueObject { public: - static constexpr bool kDiesAtEntry = true; + static constexpr bool kNoOutputOverlap = false; enum Kind { kInvalid = 0, @@ -373,8 +373,7 @@ class LocationSummary : public ArenaObject { LocationSummary(HInstruction* instruction, CallKind call_kind = kNoCall); - void SetInAt(uint32_t at, Location location, bool dies_at_entry = false) { - dies_at_entry_.Put(at, dies_at_entry); + void SetInAt(uint32_t at, Location location) { inputs_.Put(at, location); } @@ -386,7 +385,8 @@ class LocationSummary : public ArenaObject { return inputs_.Size(); } - void SetOut(Location location) { + void SetOut(Location location, bool overlaps = true) { + output_overlaps_ = overlaps; output_ = Location(location); } @@ -449,23 +449,30 @@ class LocationSummary : public ArenaObject { return &live_registers_; } - bool InputOverlapsWithOutputOrTemp(uint32_t input, bool is_environment) const { + bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const { if (is_environment) return true; - Location location = Out(); - if (input == 0 && location.IsUnallocated() && location.GetPolicy() == Location::kSameAsFirstInput) { + if ((input_index == 0) + && output_.IsUnallocated() + && (output_.GetPolicy() == Location::kSameAsFirstInput)) { return false; } - if (dies_at_entry_.Get(input)) { + if (inputs_.Get(input_index).IsRegister() || inputs_.Get(input_index).IsFpuRegister()) { return false; } return true; } + bool OutputOverlapsWithInputs() const { + return output_overlaps_; + } + private: GrowableArray<Location> inputs_; GrowableArray<Location> temps_; GrowableArray<Location> environment_; - GrowableArray<bool> dies_at_entry_; + // Whether the output overlaps with any of the inputs. If it overlaps, then it cannot + // share the same register as the inputs. + bool output_overlaps_; Location output_; const CallKind call_kind_; diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 10c60140ec..a219b97cc8 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -572,15 +572,26 @@ void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) { } } -HConstant* HBinaryOperation::TryStaticEvaluation(ArenaAllocator* allocator) const { +HConstant* HUnaryOperation::TryStaticEvaluation() const { + if (GetInput()->IsIntConstant()) { + int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue()); + return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value); + } else if (GetInput()->IsLongConstant()) { + LOG(FATAL) << "Static evaluation of long unary operations is not yet implemented."; + return nullptr; + } + return nullptr; +} + +HConstant* HBinaryOperation::TryStaticEvaluation() const { if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) { int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(), GetRight()->AsIntConstant()->GetValue()); - return new(allocator) HIntConstant(value); + return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value); } else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) { int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(), GetRight()->AsLongConstant()->GetValue()); - return new(allocator) HLongConstant(value); + return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value); } return nullptr; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 7bb71b6012..3f29e53d65 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -503,10 +503,12 @@ class HBasicBlock : public ArenaObject { M(Temporary, Instruction) \ M(SuspendCheck, Instruction) \ M(Mul, BinaryOperation) \ + M(Neg, UnaryOperation) #define FOR_EACH_INSTRUCTION(M) \ FOR_EACH_CONCRETE_INSTRUCTION(M) \ M(Constant, Instruction) \ + M(UnaryOperation, Instruction) \ M(BinaryOperation, Instruction) \ M(Invoke, Instruction) @@ -1086,6 +1088,34 @@ class HIf : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HIf); }; +class HUnaryOperation : public HExpression<1> { + public: + HUnaryOperation(Primitive::Type result_type, HInstruction* input) + : HExpression(result_type, SideEffects::None()) { + SetRawInputAt(0, input); + } + + HInstruction* GetInput() const { return InputAt(0); } + Primitive::Type GetResultType() const { return GetType(); } + + virtual bool CanBeMoved() const { return true; } + virtual bool InstructionDataEquals(HInstruction* other) const { return true; } + + // Try to statically evaluate `operation` and return a HConstant + // containing the result of this evaluation. If `operation` cannot + // be evaluated as a constant, return nullptr. + HConstant* TryStaticEvaluation() const; + + // Apply this operation to `x`. + virtual int32_t Evaluate(int32_t x) const = 0; + virtual int64_t Evaluate(int64_t x) const = 0; + + DECLARE_INSTRUCTION(UnaryOperation); + + private: + DISALLOW_COPY_AND_ASSIGN(HUnaryOperation); +}; + class HBinaryOperation : public HExpression<2> { public: HBinaryOperation(Primitive::Type result_type, @@ -1104,10 +1134,10 @@ class HBinaryOperation : public HExpression<2> { virtual bool CanBeMoved() const { return true; } virtual bool InstructionDataEquals(HInstruction* other) const { return true; } - // Try to statically evaluate `operation` and return an HConstant + // Try to statically evaluate `operation` and return a HConstant // containing the result of this evaluation. If `operation` cannot // be evaluated as a constant, return nullptr. - HConstant* TryStaticEvaluation(ArenaAllocator* allocator) const; + HConstant* TryStaticEvaluation() const; // Apply this operation to `x` and `y`. virtual int32_t Evaluate(int32_t x, int32_t y) const = 0; @@ -1518,6 +1548,20 @@ class HNewInstance : public HExpression<0> { DISALLOW_COPY_AND_ASSIGN(HNewInstance); }; +class HNeg : public HUnaryOperation { + public: + explicit HNeg(Primitive::Type result_type, HInstruction* input) + : HUnaryOperation(result_type, input) {} + + virtual int32_t Evaluate(int32_t x) const OVERRIDE { return -x; } + virtual int64_t Evaluate(int64_t x) const OVERRIDE { return -x; } + + DECLARE_INSTRUCTION(Neg); + + private: + DISALLOW_COPY_AND_ASSIGN(HNeg); +}; + class HAdd : public HBinaryOperation { public: HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right) diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 5055a76107..719c069729 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -218,6 +218,9 @@ void RegisterAllocator::ProcessInstruction(HInstruction* instruction) { current->SetFrom(position + 1); current->SetRegister(output.reg()); BlockRegister(output, position, position + 1, instruction->GetType()); + } else if (!locations->OutputOverlapsWithInputs()) { + // Shift the interval's start by one to not interfere with the inputs. + current->SetFrom(position + 1); } else if (output.IsStackSlot() || output.IsDoubleStackSlot()) { current->SetSpillSlot(output.GetStackIndex()); } @@ -723,15 +726,6 @@ void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { parent->SetSpillSlot((slot + reserved_out_slots_) * kVRegSize); } -// We create a special marker for inputs moves to differentiate them from -// moves created during resolution. They must be different instructions -// because the input moves work on the assumption that the interval moves -// have been executed. -static constexpr size_t kInputMoveLifetimePosition = 0; -static bool IsInputMove(HInstruction* instruction) { - return instruction->GetLifetimePosition() == kInputMoveLifetimePosition; -} - static bool IsValidDestination(Location destination) { return destination.IsRegister() || destination.IsStackSlot() || destination.IsDoubleStackSlot(); } @@ -748,14 +742,14 @@ void RegisterAllocator::AddInputMoveFor(HInstruction* user, HParallelMove* move = nullptr; if (previous == nullptr || !previous->IsParallelMove() - || !IsInputMove(previous)) { + || previous->GetLifetimePosition() < user->GetLifetimePosition()) { move = new (allocator_) HParallelMove(allocator_); - move->SetLifetimePosition(kInputMoveLifetimePosition); + move->SetLifetimePosition(user->GetLifetimePosition()); user->GetBlock()->InsertInstructionBefore(move, user); } else { move = previous->AsParallelMove(); } - DCHECK(IsInputMove(move)); + DCHECK_EQ(move->GetLifetimePosition(), user->GetLifetimePosition()); move->AddMove(new (allocator_) MoveOperands(source, destination, nullptr)); } @@ -778,7 +772,7 @@ void RegisterAllocator::InsertParallelMoveAt(size_t position, move = at->GetNext()->AsParallelMove(); // This is a parallel move for connecting siblings in a same block. We need to // differentiate it with moves for connecting blocks, and input moves. - if (move == nullptr || IsInputMove(move) || move->GetLifetimePosition() > position) { + if (move == nullptr || move->GetLifetimePosition() > position) { move = new (allocator_) HParallelMove(allocator_); move->SetLifetimePosition(position); at->GetBlock()->InsertInstructionBefore(move, at->GetNext()); @@ -786,12 +780,6 @@ void RegisterAllocator::InsertParallelMoveAt(size_t position, } else { // Move must happen before the instruction. HInstruction* previous = at->GetPrevious(); - if (previous != nullptr && previous->IsParallelMove() && IsInputMove(previous)) { - // This is a parallel move for connecting siblings in a same block. We need to - // differentiate it with input moves. - at = previous; - previous = previous->GetPrevious(); - } if (previous == nullptr || !previous->IsParallelMove() || previous->GetLifetimePosition() != position) { diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h index e9bd30338d..d3e1c0e81f 100644 --- a/compiler/optimizing/ssa_liveness_analysis.h +++ b/compiler/optimizing/ssa_liveness_analysis.h @@ -188,10 +188,14 @@ class LiveInterval : public ArenaObject { && (first_use_->GetPosition() < position)) { // The user uses the instruction multiple times, and one use dies before the other. // We update the use list so that the latter is first. + UsePosition* cursor = first_use_; + while ((cursor->GetNext() != nullptr) && (cursor->GetNext()->GetPosition() < position)) { + cursor = cursor->GetNext(); + } DCHECK(first_use_->GetPosition() + 1 == position); UsePosition* new_use = new (allocator_) UsePosition( - instruction, input_index, is_environment, position, first_use_->GetNext()); - first_use_->SetNext(new_use); + instruction, input_index, is_environment, position, cursor->GetNext()); + cursor->SetNext(new_use); if (first_range_->GetEnd() == first_use_->GetPosition()) { first_range_->end_ = position; } diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk index 0bab429e83..0ef20d60de 100644 --- a/dalvikvm/Android.mk +++ b/dalvikvm/Android.mk @@ -24,10 +24,11 @@ include $(CLEAR_VARS) LOCAL_MODULE := dalvikvm LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := cc -LOCAL_SRC_FILES := dalvikvm.cc ../sigchainlib/sigchain.cc +LOCAL_SRC_FILES := dalvikvm.cc LOCAL_CFLAGS := $(dalvikvm_cflags) LOCAL_C_INCLUDES := art/runtime LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper +LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk @@ -51,10 +52,11 @@ LOCAL_MODULE := dalvikvm LOCAL_MODULE_TAGS := optional LOCAL_CLANG := true LOCAL_CPP_EXTENSION := cc -LOCAL_SRC_FILES := dalvikvm.cc ../sigchainlib/sigchain.cc +LOCAL_SRC_FILES := dalvikvm.cc LOCAL_CFLAGS := $(dalvikvm_cflags) LOCAL_C_INCLUDES := art/runtime LOCAL_SHARED_LIBRARIES := libnativehelper +LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain LOCAL_LDFLAGS := -ldl -lpthread # Mac OS linker doesn't understand --export-dynamic. ifneq ($(HOST_OS),darwin) diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 62b065605c..c16e9edde9 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -172,9 +172,6 @@ Runtime::~Runtime() { BackgroundMethodSamplingProfiler::Shutdown(); } - // Shutdown the fault manager if it was initialized. - fault_manager.Shutdown(); - Trace::Shutdown(); // Make sure to let the GC complete if it is running. @@ -187,6 +184,10 @@ Runtime::~Runtime() { // Make sure all other non-daemon threads have terminated, and all daemon threads are suspended. delete thread_list_; + + // Shutdown the fault manager if it was initialized. + fault_manager.Shutdown(); + delete monitor_list_; delete monitor_pool_; delete class_linker_; @@ -850,14 +851,14 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) // Pre-allocate an OutOfMemoryError for the double-OOME case. self->ThrowNewException(ThrowLocation(), "Ljava/lang/OutOfMemoryError;", "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " - "no stack available"); + "no stack trace available"); pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL)); self->ClearException(); // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class // ahead of checking the application's class loader. self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;", - "Class not found using the boot class loader; no stack available"); + "Class not found using the boot class loader; no stack trace available"); pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL)); self->ClearException(); diff --git a/sigchainlib/Android.mk b/sigchainlib/Android.mk index e52adfc651..b7ff3606fd 100644 --- a/sigchainlib/Android.mk +++ b/sigchainlib/Android.mk @@ -30,6 +30,18 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS += $(ART_TARGET_CFLAGS) +LOCAL_SRC_FILES := sigchain.cc +LOCAL_CLANG = $(ART_TARGET_CLANG) +LOCAL_MODULE:= libsigchain +LOCAL_SHARED_LIBRARIES := liblog +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common_build.mk +include $(BUILD_STATIC_LIBRARY) + # Build host library. include $(CLEAR_VARS) LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) @@ -43,3 +55,17 @@ LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk LOCAL_LDLIBS = -ldl LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION) +LOCAL_MODULE_TAGS := optional +LOCAL_IS_HOST_MODULE := true +LOCAL_CFLAGS += $(ART_HOST_CFLAGS) +LOCAL_CLANG = $(ART_HOST_CLANG) +LOCAL_SRC_FILES := sigchain.cc +LOCAL_MODULE:= libsigchain +LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk +LOCAL_LDLIBS = -ldl +LOCAL_MULTILIB := both +include external/libcxx/libcxx.mk +include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java index 74c47a606c..2b3ba33a6a 100644 --- a/test/411-optimizing-arith/src/Main.java +++ b/test/411-optimizing-arith/src/Main.java @@ -33,6 +33,7 @@ public class Main { public static void main(String[] args) { mul(); + neg(); } public static void mul() { @@ -51,6 +52,34 @@ public class Main { expectEquals(36L, $opt$Mul(-12L, -3L)); expectEquals(33L, $opt$Mul(1L, 3L) * 11); expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7 + + $opt$InplaceNegOne(1); + } + + public static void neg() { + expectEquals(-1, $opt$Neg(1)); + expectEquals(1, $opt$Neg(-1)); + expectEquals(0, $opt$Neg(0)); + expectEquals(51, $opt$Neg(-51)); + expectEquals(-51, $opt$Neg(51)); + expectEquals(2147483647, $opt$Neg(-2147483647)); // (2^31 - 1) + expectEquals(-2147483647, $opt$Neg(2147483647)); // -(2^31 - 1) + // From the Java 7 SE Edition specification: + // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4 + // + // For integer values, negation is the same as subtraction from + // zero. The Java programming language uses two's-complement + // representation for integers, and the range of two's-complement + // values is not symmetric, so negation of the maximum negative + // int or long results in that same maximum negative number. + // Overflow occurs in this case, but no exception is thrown. + // For all integer values x, -x equals (~x)+1.'' + expectEquals(-2147483648, $opt$Neg(-2147483648)); // -(2^31) + } + + public static void $opt$InplaceNegOne(int a) { + a = -a; + expectEquals(-1, a); } static int $opt$Mul(int a, int b) { @@ -61,4 +90,7 @@ public class Main { return a * b; } + static int $opt$Neg(int a){ + return -a; + } } diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index e066a387fa..bc954e4755 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -115,6 +115,13 @@ IMAGE_TYPES := image ifeq ($(ART_TEST_RUN_TEST_NO_IMAGE),true) IMAGE_TYPES += no-image endif +RUN_TYPES := +ifeq ($(ART_TEST_RUN_TEST_DEBUG),true) + RUN_TYPES += debug +endif +ifeq ($(ART_TEST_RUN_TEST_NDEBUG),true) + RUN_TYPES += ndebug +endif ADDRESS_SIZES_TARGET := $(ART_PHONY_TEST_TARGET_SUFFIX) $(2ND_ART_PHONY_TEST_TARGET_SUFFIX) ADDRESS_SIZES_HOST := $(ART_PHONY_TEST_HOST_SUFFIX) $(2ND_ART_PHONY_TEST_HOST_SUFFIX) ALL_ADDRESS_SIZES := 64 32 @@ -122,21 +129,22 @@ ALL_ADDRESS_SIZES := 64 32 # List all run test names with number arguments agreeing with the comment above. define all-run-test-names $(foreach target, $(1), \ - $(foreach prebuild, $(2), \ - $(foreach compiler, $(3), \ - $(foreach relocate, $(4), \ - $(foreach trace, $(5), \ - $(foreach gc, $(6), \ - $(foreach jni, $(7), \ - $(foreach image, $(8), \ - $(foreach test, $(9), \ - $(foreach address_size, $(10), \ - test-art-$(target)-run-test-$(prebuild)-$(compiler)-$(relocate)-$(trace)-$(gc)-$(jni)-$(image)-$(test)$(address_size) \ - )))))))))) + $(foreach run-type, $(2), \ + $(foreach prebuild, $(3), \ + $(foreach compiler, $(4), \ + $(foreach relocate, $(5), \ + $(foreach trace, $(6), \ + $(foreach gc, $(7), \ + $(foreach jni, $(8), \ + $(foreach image, $(9), \ + $(foreach test, $(10), \ + $(foreach address_size, $(11), \ + test-art-$(target)-run-test-$(run-type)-$(prebuild)-$(compiler)-$(relocate)-$(trace)-$(gc)-$(jni)-$(image)-$(test)$(address_size) \ + ))))))))))) endef # all-run-test-names # To generate a full list or tests: -# $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \ +# $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \ # $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \ # $(TEST_ART_RUN_TESTS), $(ALL_ADDRESS_SIZES)) @@ -152,7 +160,7 @@ TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \ # disable timing sensitive tests on "dist" builds. ifdef dist_goal - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES)) endif @@ -162,7 +170,7 @@ TEST_ART_TIMING_SENSITIVE_RUN_TESTS := TEST_ART_BROKEN_RUN_TESTS := \ 004-ThreadStress -ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_BROKEN_RUN_TESTS), $(ALL_ADDRESS_SIZES)) @@ -173,7 +181,7 @@ TEST_ART_BROKEN_PREBUILD_RUN_TESTS := \ 116-nodex2oat ifneq (,$(filter prebuild,$(PREBUILD_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),prebuild, \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),prebuild, \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_BROKEN_PREBUILD_RUN_TESTS), $(ALL_ADDRESS_SIZES)) endif @@ -184,7 +192,7 @@ TEST_ART_BROKEN_NO_PREBUILD_TESTS := \ 117-nopatchoat ifneq (,$(filter no-prebuild,$(PREBUILD_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),no-prebuild, \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),no-prebuild, \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_BROKEN_NO_PREBUILD_TESTS), $(ALL_ADDRESS_SIZES)) endif @@ -197,7 +205,7 @@ TEST_ART_BROKEN_NO_RELOCATE_TESTS := \ 117-nopatchoat ifneq (,$(filter no-relocate,$(RELOCATE_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES), no-relocate,$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_BROKEN_NO_RELOCATE_TESTS), $(ALL_ADDRESS_SIZES)) endif @@ -210,7 +218,7 @@ TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \ 114-ParallelGC ifneq (,$(filter gcstress,$(GC_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),gcstress,$(JNI_TYPES), \ $(IMAGE_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES)) endif @@ -218,7 +226,7 @@ endif TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := # 115-native-bridge setup is complicated. Need to implement it correctly for the target. -ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(PREBUILD_TYPES),$(COMPILER_TYPES), \ +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \ $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES),115-native-bridge, \ $(ALL_ADDRESS_SIZES)) @@ -232,26 +240,49 @@ TEST_ART_BROKEN_FALLBACK_RUN_TESTS := \ 119-noimage-patchoat ifneq (,$(filter no-dex2oat,$(PREBUILD_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),no-dex2oat, \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),no-dex2oat, \ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \ $(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES)) endif ifneq (,$(filter no-image,$(IMAGE_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),no-image, \ $(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES)) endif ifneq (,$(filter relocate-no-patchoat,$(RELOCATE_TYPES))) - ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(PREBUILD_TYPES), \ + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ $(COMPILER_TYPES), relocate-no-patchoat,$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES),$(TEST_ART_BROKEN_FALLBACK_RUN_TESTS),$(ALL_ADDRESS_SIZES)) endif TEST_ART_BROKEN_FALLBACK_RUN_TESTS := +# The following tests use libarttest.so, which is linked against libartd.so, so will +# not work when libart.so is the one loaded. +# TODO: Find a way to run these tests in ndebug mode. +TEST_ART_BROKEN_NDEBUG_TESTS := \ + 004-JniTest \ + 004-ReferenceMap \ + 004-SignalTest \ + 004-StackWalk \ + 004-UnsafeTest \ + 115-native-bridge \ + 116-nodex2oat \ + 117-nopatchoat \ + 118-noimage-dex2oat \ + 119-noimage-patchoat \ + +ifneq (,$(filter ndebug,$(RUN_TYPES))) + ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(PREBUILD_TYPES), \ + $(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \ + $(TEST_ART_BROKEN_NDEBUG_TESTS),$(ALL_ADDRESS_SIZES)) +endif + +TEST_ART_BROKEN_NDEBUG_TESTS := + # Clear variables ahead of appending to them when defining tests. $(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=)) $(foreach target, $(TARGET_TYPES), \ @@ -281,6 +312,9 @@ $(foreach target, $(TARGET_TYPES), \ $(foreach target, $(TARGET_TYPES), \ $(foreach address_size, $(ALL_ADDRESS_SIZES), \ $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(address_size))_RULES :=))) +$(foreach target, $(TARGET_TYPES), \ + $(foreach run_type, $(RUN_TYPES), \ + $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run_type))_RULES :=))) # We need dex2oat and dalvikvm on the target as well as the core image. TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUT) $(2ND_TARGET_CORE_IMG_OUT) @@ -314,10 +348,10 @@ ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \ endif # Create a rule to build and run a tests following the form: -# test-art-{1: host or target}-run-test-{2: prebuild no-prebuild no-dex2oat}- -# {3: interpreter default optimizing}-{4: relocate no-relocate relocate-no-patchoat}- -# {5: trace or no-trace}-{6: gcstress gcverify cms}-{7: forcecopy checkjni jni}- -# {8: no-image image}-{9: test name}{10: 32 or 64} +# test-art-{1: host or target}-run-test-{2:debug ndebug}-{3: prebuild no-prebuild no-dex2oat}- +# {4: interpreter default optimizing}-{5: relocate no-relocate relocate-no-patchoat}- +# {6: trace or no-trace}-{7: gcstress gcverify cms}-{8: forcecopy checkjni jni}- +# {9: no-image image}-{10: test name}{11: 32 or 64} define define-test-art-run-test run_test_options := prereq_rule := @@ -340,119 +374,129 @@ define define-test-art-run-test $$(error found $(1) expected $(TARGET_TYPES)) endif endif - ifeq ($(2),prebuild) + ifeq ($(2),debug) + test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEBUG_RULES + else + ifeq ($(2),ndebug) + test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELEASE_RULES + run_test_options += -O + else + $$(error found $(2) expected $(RUN_TYPES)) + endif + endif + ifeq ($(3),prebuild) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_PREBUILD_RULES run_test_options += --prebuild else - ifeq ($(2),no-prebuild) + ifeq ($(3),no-prebuild) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_PREBUILD_RULES run_test_options += --no-prebuild else - ifeq ($(2),no-dex2oat) + ifeq ($(3),no-dex2oat) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_DEX2OAT_RULES run_test_options += --no-prebuild --no-dex2oat else - $$(error found $(2) expected $(PREBUILD_TYPES)) + $$(error found $(3) expected $(PREBUILD_TYPES)) endif endif endif - ifeq ($(3),optimizing) + ifeq ($(4),optimizing) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_OPTIMIZING_RULES run_test_options += -Xcompiler-option --compiler-backend=Optimizing else - ifeq ($(3),interpreter) + ifeq ($(4),interpreter) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_INTERPRETER_RULES run_test_options += --interpreter else - ifeq ($(3),default) + ifeq ($(4),default) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_DEFAULT_RULES else - $$(error found $(3) expected $(COMPILER_TYPES)) + $$(error found $(4) expected $(COMPILER_TYPES)) endif endif endif - ifeq ($(4),relocate) + ifeq ($(5),relocate) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELOCATE_RULES run_test_options += --relocate else - ifeq ($(4),no-relocate) + ifeq ($(5),no-relocate) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_RELOCATE_RULES run_test_options += --no-relocate else - ifeq ($(4),relocate-no-patchoat) + ifeq ($(5),relocate-no-patchoat) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_RELOCATE_NO_PATCHOAT_RULES run_test_options += --relocate --no-patchoat else - $$(error found $(4) expected $(RELOCATE_TYPES)) + $$(error found $(5) expected $(RELOCATE_TYPES)) endif endif endif - ifeq ($(5),trace) + ifeq ($(6),trace) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_TRACE_RULES run_test_options += --trace else - ifeq ($(5),no-trace) + ifeq ($(6),no-trace) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_TRACE_RULES else - $$(error found $(5) expected $(TRACE_TYPES)) + $$(error found $(6) expected $(TRACE_TYPES)) endif endif - ifeq ($(6),gcverify) + ifeq ($(7),gcverify) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_GCVERIFY_RULES run_test_options += --gcverify else - ifeq ($(6),gcstress) + ifeq ($(7),gcstress) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_GCSTRESS_RULES run_test_options += --gcstress else - ifeq ($(6),cms) + ifeq ($(7),cms) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_CMS_RULES else - $$(error found $(6) expected $(GC_TYPES)) + $$(error found $(7) expected $(GC_TYPES)) endif endif endif - ifeq ($(7),forcecopy) + ifeq ($(8),forcecopy) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_FORCECOPY_RULES run_test_options += --runtime-option -Xjniopts:forcecopy ifneq ($$(ART_TEST_JNI_FORCECOPY),true) skip_test := true endif else - ifeq ($(7),checkjni) + ifeq ($(8),checkjni) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_CHECKJNI_RULES run_test_options += --runtime-option -Xcheck:jni else - ifeq ($(7),jni) + ifeq ($(8),jni) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_JNI_RULES else - $$(error found $(7) expected $(JNI_TYPES)) + $$(error found $(8) expected $(JNI_TYPES)) endif endif endif - ifeq ($(8),no-image) + ifeq ($(9),no-image) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_IMAGE_RULES run_test_options += --no-image else - ifeq ($(8),image) + ifeq ($(9),image) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES else - $$(error found $(8) expected $(IMAGE_TYPES)) + $$(error found $(9) expected $(IMAGE_TYPES)) endif endif - # $(9) is the test name + # $(10) is the test name test_groups += ART_RUN_TEST_$$(uc_host_or_target)_$(call name-to-var,$(9))_RULES - ifeq ($(10),64) + ifeq ($(11),64) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_64_RULES run_test_options += --64 else - ifeq ($(10),32) + ifeq ($(11),32) test_groups += ART_RUN_TEST_$$(uc_host_or_target)_32_RULES else - $$(error found $(10) expected $(ALL_ADDRESS_SIZES)) + $$(error found $(11) expected $(ALL_ADDRESS_SIZES)) endif endif - run_test_rule_name := test-art-$(1)-run-test-$(2)-$(3)-$(4)-$(5)-$(6)-$(7)-$(8)-$(9)$(10) + run_test_rule_name := test-art-$(1)-run-test-$(2)-$(3)-$(4)-$(5)-$(6)-$(7)-$(8)-$(9)-$(10)$(11) run_test_options := --output-path $(ART_HOST_TEST_DIR)/run-test-output/$$(run_test_rule_name) \ $$(run_test_options) $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options) @@ -462,7 +506,7 @@ $$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTAB DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \ SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \ DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \ - art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(9) \ + art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(10) \ && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@) $$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \ echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \ @@ -480,16 +524,17 @@ endef # define-test-art-run-test $(foreach target, $(TARGET_TYPES), \ $(foreach test, $(TEST_ART_RUN_TESTS), \ - $(foreach address_size, $(ADDRESS_SIZES_$(call name-to-var,$(target))), \ - $(foreach prebuild, $(PREBUILD_TYPES), \ - $(foreach compiler, $(COMPILER_TYPES), \ - $(foreach relocate, $(RELOCATE_TYPES), \ - $(foreach trace, $(TRACE_TYPES), \ - $(foreach gc, $(GC_TYPES), \ - $(foreach jni, $(JNI_TYPES), \ - $(foreach image, $(IMAGE_TYPES), \ - $(eval $(call define-test-art-run-test,$(target),$(prebuild),$(compiler),$(relocate),$(trace),$(gc),$(jni),$(image),$(test),$(address_size))) \ - )))))))))) + $(foreach run_type, $(RUN_TYPES), \ + $(foreach address_size, $(ADDRESS_SIZES_$(call name-to-var,$(target))), \ + $(foreach prebuild, $(PREBUILD_TYPES), \ + $(foreach compiler, $(COMPILER_TYPES), \ + $(foreach relocate, $(RELOCATE_TYPES), \ + $(foreach trace, $(TRACE_TYPES), \ + $(foreach gc, $(GC_TYPES), \ + $(foreach jni, $(JNI_TYPES), \ + $(foreach image, $(IMAGE_TYPES), \ + $(eval $(call define-test-art-run-test,$(target),$(run_type),$(prebuild),$(compiler),$(relocate),$(trace),$(gc),$(jni),$(image),$(test),$(address_size))) \ + ))))))))))) define-test-art-run-test := # Define a phony rule whose purpose is to test its prerequisites. @@ -509,6 +554,9 @@ $(foreach target, $(TARGET_TYPES), \ $(foreach prebuild, $(PREBUILD_TYPES), $(eval \ $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(prebuild),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(prebuild))_RULES))))) $(foreach target, $(TARGET_TYPES), \ + $(foreach run-type, $(RUN_TYPES), $(eval \ + $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(run-type),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run-type))_RULES))))) +$(foreach target, $(TARGET_TYPES), \ $(foreach compiler, $(COMPILER_TYPES), $(eval \ $(call define-test-art-run-test-group,test-art-$(target)-run-test-$(compiler),$(ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(compiler))_RULES))))) $(foreach target, $(TARGET_TYPES), \ @@ -562,6 +610,9 @@ $(foreach target, $(TARGET_TYPES), \ $(foreach target, $(TARGET_TYPES), \ $(foreach address_size, $(ALL_ADDRESS_SIZES), \ $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(address_size))_RULES :=))) +$(foreach target, $(TARGET_TYPES), \ + $(foreach run_type, $(RUN_TYPES), \ + $(eval ART_RUN_TEST_$(call name-to-var,$(target))_$(call name-to-var,$(run_type))_RULES :=))) define-test-art-run-test-group := TARGET_TYPES := PREBUILD_TYPES := @@ -574,6 +625,7 @@ IMAGE_TYPES := ADDRESS_SIZES_TARGET := ADDRESS_SIZES_HOST := ALL_ADDRESS_SIZES := +RUN_TYPES := include $(LOCAL_PATH)/Android.libarttest.mk include art/test/Android.libnativebridgetest.mk |