diff options
| -rw-r--r-- | build/Android.bp | 2 | ||||
| -rw-r--r-- | build/Android.common_path.mk | 6 | ||||
| -rw-r--r-- | build/Android.common_test.mk | 6 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.cc | 56 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier_arm.h | 57 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.cc | 62 | ||||
| -rw-r--r-- | compiler/optimizing/instruction_simplifier_arm64.h | 63 | ||||
| -rw-r--r-- | compiler/optimizing/loop_optimization.cc | 136 | ||||
| -rw-r--r-- | dalvikvm/Android.bp | 2 | ||||
| -rw-r--r-- | test/623-checker-loop-regressions/src/Main.java | 16 | ||||
| -rw-r--r-- | test/645-checker-abs-simd/src/Main.java | 31 | ||||
| -rw-r--r-- | test/660-checker-simd-sad-short3/expected.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-simd-sad-short3/info.txt | 1 | ||||
| -rw-r--r-- | test/660-checker-simd-sad-short3/src/Main.java | 351 | ||||
| -rw-r--r-- | test/910-methods/check | 4 | ||||
| -rw-r--r-- | test/910-methods/expected_d8.diff | 4 | ||||
| -rw-r--r-- | test/Android.bp | 4 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 15 | ||||
| -rwxr-xr-x | tools/run-prebuilt-libjdwp-tests.sh | 112 |
19 files changed, 720 insertions, 209 deletions
diff --git a/build/Android.bp b/build/Android.bp index 8e8a2f68d8..ff762dd703 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -83,7 +83,7 @@ art_global_defaults { "bionic/libc/private", ], }, - linux: { + linux_glibc: { cflags: [ // Enable missing-noreturn only on non-Mac. As lots of things are not implemented for // Apple, it's a pain. diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk index f4f8d49a7a..3247e54ab2 100644 --- a/build/Android.common_path.mk +++ b/build/Android.common_path.mk @@ -84,12 +84,6 @@ endif HOST_CORE_DEX_FILES := $(foreach jar,$(HOST_CORE_JARS), $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar) TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar) -# Classpath for Jack compilation: we only need core-libart. -HOST_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack -HOST_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack) -TARGET_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack -TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack) - ART_HOST_DEX_DEPENDENCIES := $(foreach jar,$(HOST_CORE_JARS),$(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar) diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk index 1ae79ac8cd..37e6d4230d 100644 --- a/build/Android.common_test.mk +++ b/build/Android.common_test.mk @@ -202,9 +202,9 @@ endef # $(5): a make variable used to collate target dependencies, e.g ART_TEST_TARGET_OAT_HelloWorld_DEX # $(6): a make variable used to collate host dependencies, e.g ART_TEST_HOST_OAT_HelloWorld_DEX # -# If the input test directory contains a file called main.list and main.jpp, +# If the input test directory contains a file called main.list, # then a multi-dex file is created passing main.list as the --main-dex-list -# argument to dx and main.jpp for Jack. +# argument to dx. define build-art-test-dex ifeq ($(ART_BUILD_TARGET),true) include $(CLEAR_VARS) @@ -219,7 +219,6 @@ define build-art-test-dex LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex - LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp endif include $(BUILD_JAVA_LIBRARY) $(5) := $$(LOCAL_INSTALLED_MODULE) @@ -235,7 +234,6 @@ define build-art-test-dex LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex - LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true -D jack.preprocessor.file=$(LOCAL_PATH)/$(2)/main.jpp endif include $(BUILD_HOST_DALVIK_JAVA_LIBRARY) $(6) := $$(LOCAL_INSTALLED_MODULE) diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc index efd7cb47fe..7439893787 100644 --- a/compiler/optimizing/instruction_simplifier_arm.cc +++ b/compiler/optimizing/instruction_simplifier_arm.cc @@ -30,6 +30,57 @@ using helpers::HasShifterOperand; namespace arm { +class InstructionSimplifierArmVisitor : public HGraphVisitor { + public: + InstructionSimplifierArmVisitor(HGraph* graph, OptimizingCompilerStats* stats) + : HGraphVisitor(graph), stats_(stats) {} + + private: + void RecordSimplification() { + if (stats_ != nullptr) { + stats_->RecordStat(kInstructionSimplificationsArch); + } + } + + bool TryMergeIntoUsersShifterOperand(HInstruction* instruction); + bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge); + bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { + return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false); + } + bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { + DCHECK(CanMergeIntoShifterOperand(use, bitfield_op)); + return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true); + } + + /** + * This simplifier uses a special-purpose BB visitor. + * (1) No need to visit Phi nodes. + * (2) Since statements can be removed in a "forward" fashion, + * the visitor should test if each statement is still there. + */ + void VisitBasicBlock(HBasicBlock* block) OVERRIDE { + // TODO: fragile iteration, provide more robust iterators? + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (instruction->IsInBlock()) { + instruction->Accept(this); + } + } + } + + void VisitAnd(HAnd* instruction) OVERRIDE; + void VisitArrayGet(HArrayGet* instruction) OVERRIDE; + void VisitArraySet(HArraySet* instruction) OVERRIDE; + void VisitMul(HMul* instruction) OVERRIDE; + void VisitOr(HOr* instruction) OVERRIDE; + void VisitShl(HShl* instruction) OVERRIDE; + void VisitShr(HShr* instruction) OVERRIDE; + void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; + void VisitUShr(HUShr* instruction) OVERRIDE; + + OptimizingCompilerStats* stats_; +}; + bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge) { @@ -234,5 +285,10 @@ void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) { } } +void InstructionSimplifierArm::Run() { + InstructionSimplifierArmVisitor visitor(graph_, stats_); + visitor.VisitReversePostOrder(); +} + } // namespace arm } // namespace art diff --git a/compiler/optimizing/instruction_simplifier_arm.h b/compiler/optimizing/instruction_simplifier_arm.h index e2ed257777..2f6572931f 100644 --- a/compiler/optimizing/instruction_simplifier_arm.h +++ b/compiler/optimizing/instruction_simplifier_arm.h @@ -23,58 +23,6 @@ namespace art { namespace arm { -class InstructionSimplifierArmVisitor : public HGraphVisitor { - public: - InstructionSimplifierArmVisitor(HGraph* graph, OptimizingCompilerStats* stats) - : HGraphVisitor(graph), stats_(stats) {} - - private: - void RecordSimplification() { - if (stats_ != nullptr) { - stats_->RecordStat(kInstructionSimplificationsArch); - } - } - - bool TryMergeIntoUsersShifterOperand(HInstruction* instruction); - bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge); - bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { - return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false); - } - bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { - DCHECK(CanMergeIntoShifterOperand(use, bitfield_op)); - return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true); - } - - /** - * This simplifier uses a special-purpose BB visitor. - * (1) No need to visit Phi nodes. - * (2) Since statements can be removed in a "forward" fashion, - * the visitor should test if each statement is still there. - */ - void VisitBasicBlock(HBasicBlock* block) OVERRIDE { - // TODO: fragile iteration, provide more robust iterators? - for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { - HInstruction* instruction = it.Current(); - if (instruction->IsInBlock()) { - instruction->Accept(this); - } - } - } - - void VisitAnd(HAnd* instruction) OVERRIDE; - void VisitArrayGet(HArrayGet* instruction) OVERRIDE; - void VisitArraySet(HArraySet* instruction) OVERRIDE; - void VisitMul(HMul* instruction) OVERRIDE; - void VisitOr(HOr* instruction) OVERRIDE; - void VisitShl(HShl* instruction) OVERRIDE; - void VisitShr(HShr* instruction) OVERRIDE; - void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; - void VisitUShr(HUShr* instruction) OVERRIDE; - - OptimizingCompilerStats* stats_; -}; - - class InstructionSimplifierArm : public HOptimization { public: InstructionSimplifierArm(HGraph* graph, OptimizingCompilerStats* stats) @@ -82,10 +30,7 @@ class InstructionSimplifierArm : public HOptimization { static constexpr const char* kInstructionSimplifierArmPassName = "instruction_simplifier_arm"; - void Run() OVERRIDE { - InstructionSimplifierArmVisitor visitor(graph_, stats_); - visitor.VisitReversePostOrder(); - } + void Run() OVERRIDE; }; } // namespace arm diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc index 1c3b79dc03..c639953536 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.cc +++ b/compiler/optimizing/instruction_simplifier_arm64.cc @@ -30,6 +30,63 @@ namespace arm64 { using helpers::ShifterOperandSupportsExtension; +class InstructionSimplifierArm64Visitor : public HGraphVisitor { + public: + InstructionSimplifierArm64Visitor(HGraph* graph, OptimizingCompilerStats* stats) + : HGraphVisitor(graph), stats_(stats) {} + + private: + void RecordSimplification() { + if (stats_ != nullptr) { + stats_->RecordStat(kInstructionSimplificationsArch); + } + } + + bool TryMergeIntoUsersShifterOperand(HInstruction* instruction); + bool TryMergeIntoShifterOperand(HInstruction* use, + HInstruction* bitfield_op, + bool do_merge); + bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { + return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false); + } + bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { + DCHECK(CanMergeIntoShifterOperand(use, bitfield_op)); + return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true); + } + + /** + * This simplifier uses a special-purpose BB visitor. + * (1) No need to visit Phi nodes. + * (2) Since statements can be removed in a "forward" fashion, + * the visitor should test if each statement is still there. + */ + void VisitBasicBlock(HBasicBlock* block) OVERRIDE { + // TODO: fragile iteration, provide more robust iterators? + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (instruction->IsInBlock()) { + instruction->Accept(this); + } + } + } + + // HInstruction visitors, sorted alphabetically. + void VisitAnd(HAnd* instruction) OVERRIDE; + void VisitArrayGet(HArrayGet* instruction) OVERRIDE; + void VisitArraySet(HArraySet* instruction) OVERRIDE; + void VisitMul(HMul* instruction) OVERRIDE; + void VisitOr(HOr* instruction) OVERRIDE; + void VisitShl(HShl* instruction) OVERRIDE; + void VisitShr(HShr* instruction) OVERRIDE; + void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; + void VisitUShr(HUShr* instruction) OVERRIDE; + void VisitXor(HXor* instruction) OVERRIDE; + void VisitVecLoad(HVecLoad* instruction) OVERRIDE; + void VisitVecStore(HVecStore* instruction) OVERRIDE; + + OptimizingCompilerStats* stats_; +}; + bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge) { @@ -223,5 +280,10 @@ void InstructionSimplifierArm64Visitor::VisitVecStore(HVecStore* instruction) { } } +void InstructionSimplifierArm64::Run() { + InstructionSimplifierArm64Visitor visitor(graph_, stats_); + visitor.VisitReversePostOrder(); +} + } // namespace arm64 } // namespace art diff --git a/compiler/optimizing/instruction_simplifier_arm64.h b/compiler/optimizing/instruction_simplifier_arm64.h index 4f16fc383d..d180a8dc46 100644 --- a/compiler/optimizing/instruction_simplifier_arm64.h +++ b/compiler/optimizing/instruction_simplifier_arm64.h @@ -23,64 +23,6 @@ namespace art { namespace arm64 { -class InstructionSimplifierArm64Visitor : public HGraphVisitor { - public: - InstructionSimplifierArm64Visitor(HGraph* graph, OptimizingCompilerStats* stats) - : HGraphVisitor(graph), stats_(stats) {} - - private: - void RecordSimplification() { - if (stats_ != nullptr) { - stats_->RecordStat(kInstructionSimplificationsArch); - } - } - - bool TryMergeIntoUsersShifterOperand(HInstruction* instruction); - bool TryMergeIntoShifterOperand(HInstruction* use, - HInstruction* bitfield_op, - bool do_merge); - bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { - return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false); - } - bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) { - DCHECK(CanMergeIntoShifterOperand(use, bitfield_op)); - return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true); - } - - /** - * This simplifier uses a special-purpose BB visitor. - * (1) No need to visit Phi nodes. - * (2) Since statements can be removed in a "forward" fashion, - * the visitor should test if each statement is still there. - */ - void VisitBasicBlock(HBasicBlock* block) OVERRIDE { - // TODO: fragile iteration, provide more robust iterators? - for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { - HInstruction* instruction = it.Current(); - if (instruction->IsInBlock()) { - instruction->Accept(this); - } - } - } - - // HInstruction visitors, sorted alphabetically. - void VisitAnd(HAnd* instruction) OVERRIDE; - void VisitArrayGet(HArrayGet* instruction) OVERRIDE; - void VisitArraySet(HArraySet* instruction) OVERRIDE; - void VisitMul(HMul* instruction) OVERRIDE; - void VisitOr(HOr* instruction) OVERRIDE; - void VisitShl(HShl* instruction) OVERRIDE; - void VisitShr(HShr* instruction) OVERRIDE; - void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE; - void VisitUShr(HUShr* instruction) OVERRIDE; - void VisitXor(HXor* instruction) OVERRIDE; - void VisitVecLoad(HVecLoad* instruction) OVERRIDE; - void VisitVecStore(HVecStore* instruction) OVERRIDE; - - OptimizingCompilerStats* stats_; -}; - - class InstructionSimplifierArm64 : public HOptimization { public: InstructionSimplifierArm64(HGraph* graph, OptimizingCompilerStats* stats) @@ -88,10 +30,7 @@ class InstructionSimplifierArm64 : public HOptimization { static constexpr const char* kInstructionSimplifierArm64PassName = "instruction_simplifier_arm64"; - void Run() OVERRIDE { - InstructionSimplifierArm64Visitor visitor(graph_, stats_); - visitor.VisitReversePostOrder(); - } + void Run() OVERRIDE; }; } // namespace arm64 diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 7e37018229..fec64e2adf 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -74,19 +74,16 @@ static bool IsEarlyExit(HLoopInformation* loop_info) { // Forward declaration. static bool IsZeroExtensionAndGet(HInstruction* instruction, DataType::Type type, - /*out*/ HInstruction** operand, - bool to64 = false); + /*out*/ HInstruction** operand); -// Detect a sign extension in instruction from the given type. The to64 parameter -// denotes if result is long, and thus sign extension from int can be included. +// Detect a sign extension in instruction from the given type. // Returns the promoted operand on success. static bool IsSignExtensionAndGet(HInstruction* instruction, DataType::Type type, - /*out*/ HInstruction** operand, - bool to64 = false) { + /*out*/ HInstruction** operand) { // Accept any already wider constant that would be handled properly by sign // extension when represented in the *width* of the given narrower data type - // (the fact that char normally zero extends does not matter here). + // (the fact that Uint16 normally zero extends does not matter here). int64_t value = 0; if (IsInt64AndGet(instruction, /*out*/ &value)) { switch (type) { @@ -103,43 +100,39 @@ static bool IsSignExtensionAndGet(HInstruction* instruction, return true; } return false; - case DataType::Type::kInt32: - if (IsInt<32>(value)) { - *operand = instruction; - return to64; - } - return false; default: return false; } } - // An implicit widening conversion of a signed integer to an integral type sign-extends - // the two's-complement representation of the integer value to fill the wider format. - if (instruction->GetType() == type && (instruction->IsArrayGet() || - instruction->IsStaticFieldGet() || - instruction->IsInstanceFieldGet())) { + // An implicit widening conversion of any signed expression sign-extends. + if (instruction->GetType() == type) { switch (type) { case DataType::Type::kInt8: case DataType::Type::kInt16: *operand = instruction; return true; - case DataType::Type::kInt32: - *operand = instruction; - return to64; default: return false; } } - // Explicit type conversions. + // An explicit widening conversion of a signed expression sign-extends. if (instruction->IsTypeConversion()) { - DataType::Type from = instruction->InputAt(0)->GetType(); + HInstruction* conv = instruction->InputAt(0); + DataType::Type from = conv->GetType(); switch (instruction->GetType()) { + case DataType::Type::kInt32: case DataType::Type::kInt64: - return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true); + if (type == from && (from == DataType::Type::kInt8 || + from == DataType::Type::kInt16 || + from == DataType::Type::kInt32)) { + *operand = conv; + return true; + } + return false; case DataType::Type::kInt16: return type == DataType::Type::kUint16 && from == DataType::Type::kUint16 && - IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64); + IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand); default: return false; } @@ -147,16 +140,14 @@ static bool IsSignExtensionAndGet(HInstruction* instruction, return false; } -// Detect a zero extension in instruction from the given type. The to64 parameter -// denotes if result is long, and thus zero extension from int can be included. +// Detect a zero extension in instruction from the given type. // Returns the promoted operand on success. static bool IsZeroExtensionAndGet(HInstruction* instruction, DataType::Type type, - /*out*/ HInstruction** operand, - bool to64) { + /*out*/ HInstruction** operand) { // Accept any already wider constant that would be handled properly by zero // extension when represented in the *width* of the given narrower data type - // (the fact that byte/short/int normally sign extend does not matter here). + // (the fact that Int8/Int16 normally sign extend does not matter here). int64_t value = 0; if (IsInt64AndGet(instruction, /*out*/ &value)) { switch (type) { @@ -173,21 +164,12 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, return true; } return false; - case DataType::Type::kInt32: - if (IsUint<32>(value)) { - *operand = instruction; - return to64; - } - return false; default: return false; } } - // An implicit widening conversion of a char to an integral type zero-extends - // the representation of the char value to fill the wider format. - if (instruction->GetType() == type && (instruction->IsArrayGet() || - instruction->IsStaticFieldGet() || - instruction->IsInstanceFieldGet())) { + // An implicit widening conversion of any unsigned expression zero-extends. + if (instruction->GetType() == type) { if (type == DataType::Type::kUint16) { *operand = instruction; return true; @@ -195,6 +177,9 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, } // A sign (or zero) extension followed by an explicit removal of just the // higher sign bits is equivalent to a zero extension of the underlying operand. + // + // TODO: move this into simplifier and use new type system instead. + // if (instruction->IsAnd()) { int64_t mask = 0; HInstruction* a = instruction->InputAt(0); @@ -210,22 +195,26 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, case DataType::Type::kUint16: case DataType::Type::kInt16: return mask == std::numeric_limits<uint16_t>::max(); - case DataType::Type::kInt32: - return mask == std::numeric_limits<uint32_t>::max() && to64; default: return false; } } } - // Explicit type conversions. + // An explicit widening conversion of an unsigned expression zero-extends. if (instruction->IsTypeConversion()) { - DataType::Type from = instruction->InputAt(0)->GetType(); + HInstruction* conv = instruction->InputAt(0); + DataType::Type from = conv->GetType(); switch (instruction->GetType()) { + case DataType::Type::kInt32: case DataType::Type::kInt64: - return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true); + if (type == from && from == DataType::Type::kUint16) { + *operand = conv; + return true; + } + return false; case DataType::Type::kUint16: return type == DataType::Type::kInt16 && from == DataType::Type::kInt16 && - IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64); + IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand); default: return false; } @@ -360,6 +349,22 @@ static bool IsAddConst(HInstruction* instruction, return false; } +// Detect a + c for constant c. +static bool IsAddConst(HInstruction* instruction, + /*out*/ HInstruction** a, + /*out*/ int64_t* c) { + if (instruction->IsAdd()) { + if (IsInt64AndGet(instruction->InputAt(0), c)) { + *a = instruction->InputAt(1); + return true; + } else if (IsInt64AndGet(instruction->InputAt(1), c)) { + *a = instruction->InputAt(0); + return true; + } + } + return false; +} + // Detect reductions of the following forms, // x = x_phi + .. // x = x_phi - .. @@ -1148,6 +1153,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node, size_t size_vec = DataType::Size(type); size_t size_from = DataType::Size(from); size_t size_to = DataType::Size(to); + DataType::Type ctype = size_from == size_vec ? from : type; // Accept an integral conversion // (1a) narrowing into vector type, "wider" operations cannot bring in higher order bits, or // (1b) widening from at least vector type, and @@ -1157,7 +1163,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node, VectorizeUse(node, opa, generate_code, type, restrictions | kNoHiBits)) || (size_to >= size_from && size_from >= size_vec && - VectorizeUse(node, opa, generate_code, type, restrictions))) { + VectorizeUse(node, opa, generate_code, ctype, restrictions))) { if (generate_code) { if (vector_mode_ == kVector) { vector_map_->Put(instruction, vector_map_->Get(opa)); // operand pass-through @@ -1896,9 +1902,14 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node, (v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsInt || v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsLong)) { HInstruction* x = v->InputAt(0); - if (x->IsSub() && x->GetType() == reduction_type) { - a = x->InputAt(0); - b = x->InputAt(1); + if (x->GetType() == reduction_type) { + int64_t c = 0; + if (x->IsSub()) { + a = x->InputAt(0); + b = x->InputAt(1); + } else if (IsAddConst(x, /*out*/ &a, /*out*/ &c)) { + b = graph_->GetConstant(reduction_type, -c); // hidden SUB! + } } } if (a == nullptr || b == nullptr) { @@ -1906,22 +1917,21 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node, } // Accept same-type or consistent sign extension for narrower-type on operands a and b. // The same-type or narrower operands are called r (a or lower) and s (b or lower). + // We inspect the operands carefully to pick the most suited type. HInstruction* r = a; HInstruction* s = b; bool is_unsigned = false; DataType::Type sub_type = a->GetType(); - if (a->IsTypeConversion()) { - HInstruction* hunt = a; - while (hunt->IsTypeConversion()) { - hunt = hunt->InputAt(0); - } - sub_type = hunt->GetType(); - } else if (b->IsTypeConversion()) { - HInstruction* hunt = a; - while (hunt->IsTypeConversion()) { - hunt = hunt->InputAt(0); - } - sub_type = hunt->GetType(); + if (DataType::Size(b->GetType()) < DataType::Size(sub_type)) { + sub_type = b->GetType(); + } + if (a->IsTypeConversion() && + DataType::Size(a->InputAt(0)->GetType()) < DataType::Size(sub_type)) { + sub_type = a->InputAt(0)->GetType(); + } + if (b->IsTypeConversion() && + DataType::Size(b->InputAt(0)->GetType()) < DataType::Size(sub_type)) { + sub_type = b->InputAt(0)->GetType(); } if (reduction_type != sub_type && (!IsNarrowerOperands(a, b, sub_type, &r, &s, &is_unsigned) || is_unsigned)) { diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp index 0405fe1003..cca9ac4dbe 100644 --- a/dalvikvm/Android.bp +++ b/dalvikvm/Android.bp @@ -36,7 +36,7 @@ art_cc_binary { ], ldflags: ["-Wl,--export-dynamic"], }, - linux: { + linux_glibc: { ldflags: ["-Wl,--export-dynamic"], }, }, diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java index 418be30aad..f6d3bbab28 100644 --- a/test/623-checker-loop-regressions/src/Main.java +++ b/test/623-checker-loop-regressions/src/Main.java @@ -497,6 +497,13 @@ public class Main { } } + // Mixed of 16-bit and 8-bit array references. + static void castAndNarrow(byte[] x, char[] y) { + for (int i = 0; i < x.length; i++) { + x[i] = (byte) ((short) y[i] + 1); + } + } + public static void main(String[] args) { expectEquals(10, earlyExitFirst(-1)); for (int i = 0; i <= 10; i++) { @@ -650,6 +657,15 @@ public class Main { expectEquals(2805, f[i]); } + char[] cx = new char[259]; + for (int i = 0; i < 259; i++) { + cx[i] = (char) (i - 100); + } + castAndNarrow(b1, cx); + for (int i = 0; i < 259; i++) { + expectEquals((byte)((short) cx[i] + 1), b1[i]); + } + System.out.println("passed"); } diff --git a/test/645-checker-abs-simd/src/Main.java b/test/645-checker-abs-simd/src/Main.java index c49d85d33f..57c51a601c 100644 --- a/test/645-checker-abs-simd/src/Main.java +++ b/test/645-checker-abs-simd/src/Main.java @@ -131,6 +131,28 @@ public class Main { } } + /// CHECK-START: void Main.doitCastedChar(char[]) loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none + /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: ArraySet loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: void Main.doitCastedChar(char[]) loop_optimization (after) + /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none + /// CHECK-DAG: VecLoad loop:<<Loop1>> outer_loop:none + /// CHECK-DAG: VecAbs loop:<<Loop1>> outer_loop:none + /// CHECK-DAG: VecStore loop:<<Loop1>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:none + /// CHECK-DAG: ArrayGet loop:<<Loop2>> outer_loop:none + // + /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>" + // + private static void doitCastedChar(char[] x) { + for (int i = 0; i < x.length; i++) { + x[i] = (char) Math.abs((short) x[i]); + } + } + /// CHECK-START: void Main.doitInt(int[]) loop_optimization (before) /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: ArrayGet loop:<<Loop>> outer_loop:none @@ -298,7 +320,7 @@ public class Main { xc[i] = (char) i; } doitChar(xc); - for (int i = 0; i < 1024 *64; i++) { + for (int i = 0; i < 1024 * 64; i++) { expectEquals32((char) Math.abs((char) i), xc[i]); } short[] xs = new short[1024 * 64]; @@ -309,6 +331,13 @@ public class Main { for (int i = 0; i < 1024 * 64; i++) { expectEquals32((short) Math.abs((short) i), xs[i]); } + for (int i = 0; i < 1024 * 64; i++) { + xc[i] = (char) i; + } + doitCastedChar(xc); + for (int i = 0; i < 1024 * 64; i++) { + expectEquals32((char) Math.abs((short) i), xc[i]); + } // Set up minint32, maxint32 and some others. int[] xi = new int[8]; xi[0] = 0x80000000; diff --git a/test/660-checker-simd-sad-short3/expected.txt b/test/660-checker-simd-sad-short3/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/660-checker-simd-sad-short3/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/660-checker-simd-sad-short3/info.txt b/test/660-checker-simd-sad-short3/info.txt new file mode 100644 index 0000000000..b56c119129 --- /dev/null +++ b/test/660-checker-simd-sad-short3/info.txt @@ -0,0 +1 @@ +Functional tests on SAD vectorization. diff --git a/test/660-checker-simd-sad-short3/src/Main.java b/test/660-checker-simd-sad-short3/src/Main.java new file mode 100644 index 0000000000..c8850b41e4 --- /dev/null +++ b/test/660-checker-simd-sad-short3/src/Main.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Tests for SAD (sum of absolute differences). + * + * Some special cases: parameters, constants, invariants, casted computations. + */ +public class Main { + + /// CHECK-START: int Main.sadShort2IntParamRight(short[], short) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get>>,<<Param>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntParamRight(short[], short) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntParamRight(short[] s, short param) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + sad += Math.abs(s[i] - param); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Param>>,<<Get>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntParamLeft(short[], short) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<Param:s\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Param>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntParamLeft(short[] s, short param) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + sad += Math.abs(param - s[i]); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntConstRight(short[]) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant -32767 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> Add [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Add>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntConstRight(short[]) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntConstRight(short[] s) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + sad += Math.abs(s[i] - 32767); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntConstLeft(short[]) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<ConsI>>,<<Get>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntConstLeft(short[]) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 32767 loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntConstLeft(short[] s) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + sad += Math.abs(32767 - s[i]); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get>>,<<Conv>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntInvariantRight(short[], int) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons8>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntInvariantRight(short[] s, int val) { + int sad = 0; + short x = (short) (val + 1); + for (int i = 0; i < s.length; i++) { + sad += Math.abs(s[i] - x); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Conv>>,<<Get>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntInvariantLeft(short[], int) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [{{i\d+}}] loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<Conv>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Rep>>,<<Load>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntInvariantLeft(short[] s, int val) { + int sad = 0; + short x = (short) (val + 1); + for (int i = 0; i < s.length; i++) { + sad += Math.abs(x - s[i]); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<Add>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Get>>,<<Conv>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntCastedExprRight(short[]) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Load>>,<<Add>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntCastedExprRight(short[] s) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + short x = (short) (s[i] + 110); // narrower part sign extends + sad += Math.abs(s[i] - x); + } + return sad; + } + + /// CHECK-START: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (before) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons1:i\d+>> IntConstant 1 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Get:s\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:i\d+>> [<<Get>>,<<ConsI>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Conv:s\d+>> TypeConversion [<<Add>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Conv>>,<<Get>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Intrin:i\d+>> InvokeStaticOrDirect [<<Sub>>] intrinsic:MathAbsInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi2>>,<<Intrin>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none + // + /// CHECK-START-ARM64: int Main.sadShort2IntCastedExprLeft(short[]) loop_optimization (after) + /// CHECK-DAG: <<Cons0:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: <<Cons8:i\d+>> IntConstant 8 loop:none + /// CHECK-DAG: <<ConsI:i\d+>> IntConstant 110 loop:none + /// CHECK-DAG: <<Rep:d\d+>> VecReplicateScalar [<<ConsI>>] loop:none + /// CHECK-DAG: <<Set:d\d+>> VecSetScalars [<<Cons0>>] loop:none + /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: <<Phi2:d\d+>> Phi [<<Set>>,{{d\d+}}] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Add:d\d+>> VecAdd [<<Load>>,<<Rep>>] loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<SAD:d\d+>> VecSADAccumulate [<<Phi2>>,<<Add>>,<<Load>>] loop:<<Loop>> outer_loop:none + private static int sadShort2IntCastedExprLeft(short[] s) { + int sad = 0; + for (int i = 0; i < s.length; i++) { + short x = (short) (s[i] + 110); // narrower part sign extends + sad += Math.abs(x - s[i]); + } + return sad; + } + + public static void main(String[] args) { + short[] interesting = { + (short) 0x0000, + (short) 0x0001, + (short) 0x0002, + (short) 0x0003, + (short) 0x0004, + (short) 0x1234, + (short) 0x8000, + (short) 0x8001, + (short) 0x8002, + (short) 0x8003, + (short) 0x8004, + (short) 0x8004, + (short) 0x7000, + (short) 0x7fff, + (short) 0xf000, + (short) 0xffff + }; + short[] s = new short[64]; + for (int i = 0; i < 64; i++) { + s[i] = interesting[i % interesting.length]; + } + + expectEquals(1067200, sadShort2IntParamRight(s, (short)-1)); + expectEquals(1067200, sadShort2IntParamRight(s, (short) 0)); + expectEquals(1067208, sadShort2IntParamRight(s, (short) 1)); + expectEquals(1067224, sadShort2IntParamRight(s, (short) 2)); + expectEquals(2635416, sadShort2IntParamRight(s, (short) 0x7fff)); + expectEquals(1558824, sadShort2IntParamRight(s, (short) 0x8000)); + + expectEquals(1067200, sadShort2IntParamLeft(s, (short)-1)); + expectEquals(1067200, sadShort2IntParamLeft(s, (short) 0)); + expectEquals(1067208, sadShort2IntParamLeft(s, (short) 1)); + expectEquals(1067224, sadShort2IntParamLeft(s, (short) 2)); + expectEquals(2635416, sadShort2IntParamLeft(s, (short) 0x7fff)); + expectEquals(1558824, sadShort2IntParamLeft(s, (short) 0x8000)); + + expectEquals(2635416, sadShort2IntConstRight(s)); + expectEquals(2635416, sadShort2IntConstLeft(s)); + + expectEquals(1067200, sadShort2IntInvariantRight(s, -2)); + expectEquals(1067200, sadShort2IntInvariantRight(s, -1)); + expectEquals(1067208, sadShort2IntInvariantRight(s, 0)); + expectEquals(1067224, sadShort2IntInvariantRight(s, 1)); + expectEquals(2635416, sadShort2IntInvariantRight(s, 0x7ffe)); + expectEquals(1558824, sadShort2IntInvariantRight(s, 0x7fff)); + + expectEquals(1067200, sadShort2IntInvariantLeft(s, -2)); + expectEquals(1067200, sadShort2IntInvariantLeft(s, -1)); + expectEquals(1067208, sadShort2IntInvariantLeft(s, 0)); + expectEquals(1067224, sadShort2IntInvariantLeft(s, 1)); + expectEquals(2635416, sadShort2IntInvariantLeft(s, 0x7ffe)); + expectEquals(1558824, sadShort2IntInvariantLeft(s, 0x7fff)); + + expectEquals(268304, sadShort2IntCastedExprLeft(s)); + expectEquals(268304, sadShort2IntCastedExprRight(s)); + + System.out.println("passed"); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/910-methods/check b/test/910-methods/check index 835850004a..f9552ada26 100644 --- a/test/910-methods/check +++ b/test/910-methods/check @@ -19,4 +19,8 @@ if [[ "$USE_JACK" == true ]]; then patch -p0 expected.txt < expected_jack.diff fi +if [[ "$DX" == 'd8' ]]; then + patch -p0 expected.txt < expected_d8.diff +fi + ./default-check "$@" diff --git a/test/910-methods/expected_d8.diff b/test/910-methods/expected_d8.diff new file mode 100644 index 0000000000..2c5d085418 --- /dev/null +++ b/test/910-methods/expected_d8.diff @@ -0,0 +1,4 @@ +7c7 +< Location end: 39 +--- +> Location end: 36 diff --git a/test/Android.bp b/test/Android.bp index 2af03e3cbe..cb180704c0 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -74,7 +74,7 @@ art_cc_defaults { ], target: { - linux: { + linux_glibc: { ldflags: [ // Allow jni_compiler_test to find Java_MyClassNatives_bar // within itself using dlopen(NULL, ...). @@ -143,7 +143,7 @@ art_cc_defaults { "-Wno-missing-noreturn", ], }, - linux: { + linux_glibc: { cflags: [ // gtest issue "-Wno-used-but-marked-unused", diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 6017d28159..4b49142e10 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -22,8 +22,7 @@ TEST_ART_RUN_TEST_DEPENDENCIES := \ $(HOST_OUT_EXECUTABLES)/dx \ $(HOST_OUT_EXECUTABLES)/jasmin \ $(HOST_OUT_EXECUTABLES)/smali \ - $(HOST_OUT_EXECUTABLES)/dexmerger \ - $(JACK) + $(HOST_OUT_EXECUTABLES)/dexmerger # Convert's a rule name to the form used in variables, e.g. no-relocate to NO_RELOCATE define name-to-var @@ -124,19 +123,9 @@ endif # Host executables. host_prereq_rules := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES) -ifeq ($(ANDROID_COMPILE_WITH_JACK),true) -# Classpath for Jack compilation for host. -host_prereq_rules += $(HOST_JACK_CLASSPATH_DEPENDENCIES) -endif - -# Required for dx, jasmin, smali, dexmerger, jack. +# Required for dx, jasmin, smali, dexmerger. host_prereq_rules += $(TEST_ART_RUN_TEST_DEPENDENCIES) -ifeq ($(ANDROID_COMPILE_WITH_JACK),true) -# Classpath for Jack compilation for target. -target_prereq_rules := $(TARGET_JACK_CLASSPATH_DEPENDENCIES) -endif - # Sync test files to the target, depends upon all things that must be pushed #to the target. target_prereq_rules += test-art-target-sync diff --git a/tools/run-prebuilt-libjdwp-tests.sh b/tools/run-prebuilt-libjdwp-tests.sh new file mode 100755 index 0000000000..46c2a153a7 --- /dev/null +++ b/tools/run-prebuilt-libjdwp-tests.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +if [[ ! -d libcore ]]; then + echo "Script needs to be run at the root of the android tree" + exit 1 +fi + +source build/envsetup.sh >&/dev/null # for get_build_var, setpaths +setpaths # include platform prebuilt java, javac, etc in $PATH. + +if [[ `uname` != 'Linux' ]]; then + echo "Script cannot be run on $(uname). It is Linux only." + exit 2 +fi + +jdwp_path=${ANDROID_JAVA_HOME}/jre/lib/amd64/libjdwp.so +if [[ ! -f $jdwp_path ]]; then + echo "Unable to find prebuilts libjdwp.so! Did the version change from jdk8?" + exit 3 +fi + +args=("$@") +debug="no" +has_variant="no" +has_mode="no" + +while true; do + if [[ $1 == "--debug" ]]; then + debug="yes" + shift + elif [[ "$1" == --mode=* ]]; then + has_mode="yes" + if [[ $1 != "--mode=host" ]]; then + # Just print out an actually helpful error message. + echo "Only host tests can be run against prebuilt libjdwp" + exit 4 + fi + shift + elif [[ $1 == --variant=* ]]; then + has_variant="yes" + if [[ $1 != "--variant=x64" ]] && [[ $1 != "--variant=X64" ]]; then + # Just print out an actually helpful error message. + echo "Only 64bit runs can be tested against the prebuilt libjdwp!" + exit 5 + fi + shift + elif [[ "$1" == "" ]]; then + break + else + shift + fi +done + +if [[ "$has_mode" = "no" ]]; then + args+=(--mode=host) +fi + +if [[ "$has_variant" = "no" ]]; then + args+=(--variant=X64) +fi + +wrapper_name="" +plugin="" +if [[ "$debug" = "yes" ]]; then + wrapper_name=libwrapagentpropertiesd + plugin="$ANDROID_HOST_OUT/lib64/libopenjdkjvmtid.so" +else + wrapper_name=libwrapagentproperties + plugin="$ANDROID_HOST_OUT/lib64/libopenjdkjvmti.so" +fi +wrapper=$ANDROID_HOST_OUT/lib64/${wrapper_name}.so + +if [[ ! -f $wrapper ]]; then + echo "need to build $wrapper to run prebuild-libjdwp-tests!" + echo "m -j40 ${wrapper/.so/}" + exit 6 +fi + +if [[ ! -f $plugin ]]; then + echo "jvmti plugin not built!" + exit 7 +fi + +props_path=$PWD/art/tools/libjdwp-compat.props +expect_path=$PWD/art/tools/libjdwp_art_failures.txt + +function verbose_run() { + echo "$@" + env "$@" +} + +verbose_run LD_LIBRARY_PATH="$(dirname $jdwp_path):$LD_LIBRARY_PATH" \ + ./art/tools/run-jdwp-tests.sh \ + "${args[@]}" \ + "-Xplugin:$plugin" \ + --agent-wrapper "${wrapper}"="${props_path}" \ + --jdwp-path "$jdwp_path" \ + --expectations "$expect_path" |