summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ian Rogers <irogers@google.com> 2014-11-05 23:46:43 -0800
committer Ian Rogers <irogers@google.com> 2014-11-13 16:17:46 -0800
commitd582fa4ea62083a7598dded5b82dc2198b3daac7 (patch)
treec76704c266ef4687eab425612ddf3fd24f93fe8d
parentf20076ff813b8012096ff31af236d59db3c0f4e1 (diff)
Instruction set features for ARM64, MIPS and X86.
Also, refactor how feature strings are handled so they are additive or subtractive. Make MIPS have features for FPU 32-bit and MIPS v2. Use in the quick compiler rather than #ifdefs that wouldn't have worked in cross-compilation. Add SIMD features for x86/x86-64 proposed in: https://android-review.googlesource.com/#/c/112370/ Bug: 18056890 Change-Id: Ic88ff84a714926bd277beb74a430c5c7d5ed7666
-rw-r--r--build/Android.gtest.mk8
-rw-r--r--build/Android.oat.mk11
-rw-r--r--compiler/common_compiler_test.cc1
-rw-r--r--compiler/compiled_method.h2
-rw-r--r--compiler/dex/quick/arm/utility_arm.cc8
-rw-r--r--compiler/dex/quick/gen_common.cc1
-rw-r--r--compiler/dex/quick/mips/assemble_mips.cc1
-rw-r--r--compiler/dex/quick/mips/call_mips.cc1
-rw-r--r--compiler/dex/quick/mips/fp_mips.cc1
-rw-r--r--compiler/dex/quick/mips/int_mips.cc1
-rw-r--r--compiler/dex/quick/mips/mips_lir.h94
-rw-r--r--compiler/dex/quick/mips/target_mips.cc113
-rw-r--r--compiler/dex/quick/mips/utility_mips.cc28
-rw-r--r--compiler/dex/quick/mir_to_lir.h6
-rw-r--r--compiler/driver/compiler_driver.h3
-rw-r--r--compiler/elf_builder.h2
-rw-r--r--compiler/oat_test.cc5
-rw-r--r--compiler/optimizing/code_generator.h2
-rw-r--r--compiler/optimizing/codegen_test.cc4
-rw-r--r--compiler/utils/assembler.h8
-rw-r--r--compiler/utils/stack_checks.h5
-rw-r--r--dex2oat/dex2oat.cc22
-rw-r--r--disassembler/disassembler.h2
-rw-r--r--oatdump/oatdump.cc1
-rw-r--r--patchoat/patchoat.cc4
-rw-r--r--patchoat/patchoat.h4
-rw-r--r--runtime/Android.mk15
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc1
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.cc297
-rw-r--r--runtime/arch/arm/instruction_set_features_arm.h99
-rw-r--r--runtime/arch/arm/instruction_set_features_arm_test.cc115
-rw-r--r--runtime/arch/arm/instruction_set_features_assembly_tests.S (renamed from runtime/arch/arm/instruction_set_features_arm.S)4
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.cc137
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64.h90
-rw-r--r--runtime/arch/arm64/instruction_set_features_arm64_test.cc35
-rw-r--r--runtime/arch/instruction_set.cc125
-rw-r--r--runtime/arch/instruction_set.h (renamed from runtime/instruction_set.h)184
-rw-r--r--runtime/arch/instruction_set_features.cc275
-rw-r--r--runtime/arch/instruction_set_features.h119
-rw-r--r--runtime/arch/instruction_set_features_test.cc149
-rw-r--r--runtime/arch/instruction_set_test.cc53
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.cc167
-rw-r--r--runtime/arch/mips/instruction_set_features_mips.h98
-rw-r--r--runtime/arch/mips/instruction_set_features_mips_test.cc34
-rw-r--r--runtime/arch/x86/instruction_set_features_x86.cc280
-rw-r--r--runtime/arch/x86/instruction_set_features_x86.h101
-rw-r--r--runtime/arch/x86/instruction_set_features_x86_test.cc70
-rw-r--r--runtime/arch/x86_64/instruction_set_features_x86_64.h88
-rw-r--r--runtime/arch/x86_64/instruction_set_features_x86_64_test.cc35
-rw-r--r--runtime/elf_file.cc2
-rw-r--r--runtime/entrypoints/quick/callee_save_frame.h2
-rw-r--r--runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc1
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc1
-rw-r--r--runtime/gc/heap.h2
-rw-r--r--runtime/instruction_set.cc507
-rw-r--r--runtime/instruction_set_test.cc279
-rw-r--r--runtime/instrumentation.h2
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc14
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc2
-rw-r--r--runtime/oat.cc4
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/parsed_options.h2
-rw-r--r--runtime/runtime.cc1
-rw-r--r--runtime/runtime.h2
-rw-r--r--runtime/signal_catcher.cc2
-rw-r--r--runtime/stack.h2
-rw-r--r--runtime/thread.h2
-rw-r--r--runtime/utils.h2
68 files changed, 2620 insertions, 1122 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a8041c5365..991aacae87 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -70,8 +70,15 @@ LOCAL_PATH := art
RUNTIME_GTEST_COMMON_SRC_FILES := \
runtime/arch/arch_test.cc \
+ runtime/arch/instruction_set_test.cc \
+ runtime/arch/instruction_set_features_test.cc \
runtime/arch/memcmp16_test.cc \
runtime/arch/stub_test.cc \
+ runtime/arch/arm/instruction_set_features_arm_test.cc \
+ runtime/arch/arm64/instruction_set_features_arm64_test.cc \
+ runtime/arch/mips/instruction_set_features_mips_test.cc \
+ runtime/arch/x86/instruction_set_features_x86_test.cc \
+ runtime/arch/x86_64/instruction_set_features_x86_64_test.cc \
runtime/barrier_test.cc \
runtime/base/bit_field_test.cc \
runtime/base/bit_vector_test.cc \
@@ -109,7 +116,6 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
runtime/handle_scope_test.cc \
runtime/indenter_test.cc \
runtime/indirect_reference_table_test.cc \
- runtime/instruction_set_test.cc \
runtime/intern_table_test.cc \
runtime/interpreter/safe_math_test.cc \
runtime/java_vm_ext_test.cc \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 9fe38078d2..e8b363ba26 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -23,6 +23,13 @@
include art/build/Android.common_build.mk
+ifeq ($(DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+ DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
+ifeq ($($(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES),)
+ $(HOST_2ND_ARCH_VAR_PREFIX)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES := default
+endif
+
# Use dex2oat debug version for better error reporting
# $(1): compiler - default, optimizing or interpreter.
# $(2): pic/no-pic
@@ -91,7 +98,7 @@ $$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
$$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
--oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
--base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(3)ART_HOST_ARCH) \
- --instruction-set-features=$$($(3)HOST_INSTRUCTION_SET_FEATURES) \
+ --instruction-set-features=$$($(3)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES) \
--host --android-root=$$(HOST_OUT) --include-patch-information \
$$(PRIVATE_CORE_COMPILE_OPTIONS)
@@ -194,7 +201,7 @@ $$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
$$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
--oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
--base=$$(LIBART_IMG_TARGET_BASE_ADDRESS) --instruction-set=$$($(3)TARGET_ARCH) \
- --instruction-set-features=$$($(3)TARGET_INSTRUCTION_SET_FEATURES) \
+ --instruction-set-features=$$($(3)DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) \
--android-root=$$(PRODUCT_OUT)/system --include-patch-information \
$$(PRIVATE_CORE_COMPILE_OPTIONS) || (rm $$(PRIVATE_CORE_OAT_NAME); exit 1)
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 085d169c6d..97387a1c9c 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -16,6 +16,7 @@
#include "common_compiler_test.h"
+#include "arch/instruction_set_features.h"
#include "class_linker.h"
#include "compiled_method.h"
#include "dex/quick_compiler_callbacks.h"
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 0361cd18cc..7f76eef682 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -21,7 +21,7 @@
#include <string>
#include <vector>
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
#include "method_reference.h"
#include "utils.h"
#include "utils/array_ref.h"
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index 0d5aa90f35..0c7812ba09 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include "arm_lir.h"
#include "codegen_arm.h"
+
+#include "arch/arm/instruction_set_features_arm.h"
+#include "arm_lir.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/reg_storage_eq.h"
@@ -974,7 +976,7 @@ LIR* ArmMir2Lir::LoadBaseDisp(RegStorage r_base, int displacement, RegStorage r_
LIR* load;
if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
!cu_->compiler_driver->GetInstructionSetFeatures()->
- AsArmInstructionSetFeatures()->HasLpae()) {
+ AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
// Only 64-bit load needs special handling.
// If the cpu supports LPAE, aligned LDRD is atomic - fall through to LoadBaseDisp().
DCHECK(!r_dest.IsFloat()); // See RegClassForFieldLoadSave().
@@ -1104,7 +1106,7 @@ LIR* ArmMir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r
LIR* store;
if (is_volatile == kVolatile && (size == k64 || size == kDouble) &&
!cu_->compiler_driver->GetInstructionSetFeatures()->
- AsArmInstructionSetFeatures()->HasLpae()) {
+ AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()) {
// Only 64-bit store needs special handling.
// If the cpu supports LPAE, aligned STRD is atomic - fall through to StoreBaseDisp().
// Use STREXD for the atomic store. (Expect displacement > 0, don't optimize for == 0.)
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 7674e46fc0..98ddc36f63 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "arch/arm/instruction_set_features_arm.h"
#include "dex/compiler_ir.h"
#include "dex/compiler_internals.h"
#include "dex/quick/arm/arm_lir.h"
diff --git a/compiler/dex/quick/mips/assemble_mips.cc b/compiler/dex/quick/mips/assemble_mips.cc
index ca71c3010a..0d1d9bf7a9 100644
--- a/compiler/dex/quick/mips/assemble_mips.cc
+++ b/compiler/dex/quick/mips/assemble_mips.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_mips.h"
+
#include "dex/quick/mir_to_lir-inl.h"
#include "mips_lir.h"
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 01784e2fec..ed73ef0a00 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -17,6 +17,7 @@
/* This file contains codegen for the Mips ISA */
#include "codegen_mips.h"
+
#include "dex/quick/mir_to_lir-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "gc/accounting/card_table.h"
diff --git a/compiler/dex/quick/mips/fp_mips.cc b/compiler/dex/quick/mips/fp_mips.cc
index 0a7aa99c98..495d85e0a4 100644
--- a/compiler/dex/quick/mips/fp_mips.cc
+++ b/compiler/dex/quick/mips/fp_mips.cc
@@ -15,6 +15,7 @@
*/
#include "codegen_mips.h"
+
#include "dex/quick/mir_to_lir-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "mips_lir.h"
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index d58ddb0d09..fb47238000 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -17,6 +17,7 @@
/* This file contains codegen for the Mips ISA */
#include "codegen_mips.h"
+
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/reg_storage_eq.h"
#include "entrypoints/quick/quick_entrypoints.h"
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 3615916201..3df8f2ee0b 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -214,44 +214,43 @@ enum MipsNativeRegisterPool { // private marker to avoid generate-operator-out.
rF30 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 30,
rF31 = RegStorage::k32BitSolo | RegStorage::kFloatingPoint | 31,
#endif
-#if (FR_BIT == 0)
- rD0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
- rD1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
- rD2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
- rD3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
- rD4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
- rD5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
- rD6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
- rD7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+ // Double precision registers where the FPU is in 32-bit mode.
+ rD0_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+ rD1_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+ rD2_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+ rD3_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+ rD4_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
+ rD5_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+ rD6_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+ rD7_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
#if 0 // TODO: expand resource mask to enable use of all MIPS fp registers.
- rD8 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
- rD9 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
- rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
- rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
- rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
- rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
- rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
- rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
+ rD8_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 16,
+ rD9_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 18,
+ rD10_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 20,
+ rD11_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 22,
+ rD12_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 24,
+ rD13_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 26,
+ rD14_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 28,
+ rD15_fr0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 30,
#endif
-#else
- rD0 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
- rD1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
- rD2 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
- rD3 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
- rD4 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
- rD5 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
- rD6 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
- rD7 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
+ // Double precision registers where the FPU is in 64-bit mode.
+ rD0_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 0,
+ rD1_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 1,
+ rD2_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 2,
+ rD3_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 3,
+ rD4_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 4,
+ rD5_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 5,
+ rD6_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 6,
+ rD7_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 7,
#if 0 // TODO: expand resource mask to enable use of all MIPS fp registers.
- rD8 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
- rD9 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 9,
- rD10 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
- rD11 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
- rD12 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
- rD13 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
- rD14 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
- rD15 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
-#endif
+ rD8_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 8,
+ rD9_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 9,
+ rD10_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 10,
+ rD11_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 11,
+ rD12_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 12,
+ rD13_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 13,
+ rD14_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 14,
+ rD15_fr1 = RegStorage::k64BitSolo | RegStorage::kFloatingPoint | 15,
#endif
};
@@ -309,14 +308,23 @@ constexpr RegStorage rs_rF13(RegStorage::kValid | rF13);
constexpr RegStorage rs_rF14(RegStorage::kValid | rF14);
constexpr RegStorage rs_rF15(RegStorage::kValid | rF15);
-constexpr RegStorage rs_rD0(RegStorage::kValid | rD0);
-constexpr RegStorage rs_rD1(RegStorage::kValid | rD1);
-constexpr RegStorage rs_rD2(RegStorage::kValid | rD2);
-constexpr RegStorage rs_rD3(RegStorage::kValid | rD3);
-constexpr RegStorage rs_rD4(RegStorage::kValid | rD4);
-constexpr RegStorage rs_rD5(RegStorage::kValid | rD5);
-constexpr RegStorage rs_rD6(RegStorage::kValid | rD6);
-constexpr RegStorage rs_rD7(RegStorage::kValid | rD7);
+constexpr RegStorage rs_rD0_fr0(RegStorage::kValid | rD0_fr0);
+constexpr RegStorage rs_rD1_fr0(RegStorage::kValid | rD1_fr0);
+constexpr RegStorage rs_rD2_fr0(RegStorage::kValid | rD2_fr0);
+constexpr RegStorage rs_rD3_fr0(RegStorage::kValid | rD3_fr0);
+constexpr RegStorage rs_rD4_fr0(RegStorage::kValid | rD4_fr0);
+constexpr RegStorage rs_rD5_fr0(RegStorage::kValid | rD5_fr0);
+constexpr RegStorage rs_rD6_fr0(RegStorage::kValid | rD6_fr0);
+constexpr RegStorage rs_rD7_fr0(RegStorage::kValid | rD7_fr0);
+
+constexpr RegStorage rs_rD0_fr1(RegStorage::kValid | rD0_fr1);
+constexpr RegStorage rs_rD1_fr1(RegStorage::kValid | rD1_fr1);
+constexpr RegStorage rs_rD2_fr1(RegStorage::kValid | rD2_fr1);
+constexpr RegStorage rs_rD3_fr1(RegStorage::kValid | rD3_fr1);
+constexpr RegStorage rs_rD4_fr1(RegStorage::kValid | rD4_fr1);
+constexpr RegStorage rs_rD5_fr1(RegStorage::kValid | rD5_fr1);
+constexpr RegStorage rs_rD6_fr1(RegStorage::kValid | rD6_fr1);
+constexpr RegStorage rs_rD7_fr1(RegStorage::kValid | rD7_fr1);
// TODO: reduce/eliminate use of these.
#define rMIPS_SUSPEND rS0
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 4a340ecca0..185112dbf9 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -20,6 +20,7 @@
#include <string>
+#include "arch/mips/instruction_set_features_mips.h"
#include "backend_mips.h"
#include "dex/compiler_internals.h"
#include "dex/quick/mir_to_lir-inl.h"
@@ -34,8 +35,12 @@ static constexpr RegStorage core_regs_arr[] =
static constexpr RegStorage sp_regs_arr[] =
{rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
-static constexpr RegStorage dp_regs_arr[] =
- {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_regs_arr[] =
+ {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+ rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_regs_arr[] =
+ {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+ rs_rD7_fr1};
static constexpr RegStorage reserved_regs_arr[] =
{rs_rZERO, rs_rAT, rs_rS0, rs_rS1, rs_rK0, rs_rK1, rs_rGP, rs_rSP, rs_rRA};
static constexpr RegStorage core_temps_arr[] =
@@ -44,17 +49,23 @@ static constexpr RegStorage core_temps_arr[] =
static constexpr RegStorage sp_temps_arr[] =
{rs_rF0, rs_rF1, rs_rF2, rs_rF3, rs_rF4, rs_rF5, rs_rF6, rs_rF7, rs_rF8, rs_rF9, rs_rF10,
rs_rF11, rs_rF12, rs_rF13, rs_rF14, rs_rF15};
-static constexpr RegStorage dp_temps_arr[] =
- {rs_rD0, rs_rD1, rs_rD2, rs_rD3, rs_rD4, rs_rD5, rs_rD6, rs_rD7};
+static constexpr RegStorage dp_fr0_temps_arr[] =
+ {rs_rD0_fr0, rs_rD1_fr0, rs_rD2_fr0, rs_rD3_fr0, rs_rD4_fr0, rs_rD5_fr0, rs_rD6_fr0,
+ rs_rD7_fr0};
+static constexpr RegStorage dp_fr1_temps_arr[] =
+ {rs_rD0_fr1, rs_rD1_fr1, rs_rD2_fr1, rs_rD3_fr1, rs_rD4_fr1, rs_rD5_fr1, rs_rD6_fr1,
+ rs_rD7_fr1};
static constexpr ArrayRef<const RegStorage> empty_pool;
static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
-static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_regs(dp_fr0_regs_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_regs(dp_fr1_regs_arr);
static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
-static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr0_temps(dp_fr0_temps_arr);
+static constexpr ArrayRef<const RegStorage> dp_fr1_temps(dp_fr1_temps_arr);
RegLocation MipsMir2Lir::LocCReturn() {
return mips_loc_c_return;
@@ -129,14 +140,17 @@ RegStorage MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
* Decode the register id.
*/
ResourceMask MipsMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
- return reg.IsDouble()
- /* Each double register is equal to a pair of single-precision FP registers */
-#if (FR_BIT == 0)
- ? ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0)
-#else
- ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0)
-#endif
- : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kMipsFPReg0 : reg.GetRegNum());
+ if (reg.IsDouble()) {
+ if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+ return ResourceMask::TwoBits((reg.GetRegNum() & ~1) + kMipsFPReg0);
+ } else {
+ return ResourceMask::TwoBits(reg.GetRegNum() * 2 + kMipsFPReg0);
+ }
+ } else if (reg.IsSingle()) {
+ return ResourceMask::Bit(reg.GetRegNum() + kMipsFPReg0);
+ } else {
+ return ResourceMask::Bit(reg.GetRegNum());
+ }
}
ResourceMask MipsMir2Lir::GetPCUseDefEncoding() const {
@@ -382,14 +396,25 @@ void MipsMir2Lir::ClobberCallerSave() {
Clobber(rs_rF13);
Clobber(rs_rF14);
Clobber(rs_rF15);
- Clobber(rs_rD0);
- Clobber(rs_rD1);
- Clobber(rs_rD2);
- Clobber(rs_rD3);
- Clobber(rs_rD4);
- Clobber(rs_rD5);
- Clobber(rs_rD6);
- Clobber(rs_rD7);
+ if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint()) {
+ Clobber(rs_rD0_fr0);
+ Clobber(rs_rD1_fr0);
+ Clobber(rs_rD2_fr0);
+ Clobber(rs_rD3_fr0);
+ Clobber(rs_rD4_fr0);
+ Clobber(rs_rD5_fr0);
+ Clobber(rs_rD6_fr0);
+ Clobber(rs_rD7_fr0);
+ } else {
+ Clobber(rs_rD0_fr1);
+ Clobber(rs_rD1_fr1);
+ Clobber(rs_rD2_fr1);
+ Clobber(rs_rD3_fr1);
+ Clobber(rs_rD4_fr1);
+ Clobber(rs_rD5_fr1);
+ Clobber(rs_rD6_fr1);
+ Clobber(rs_rD7_fr1);
+ }
}
RegLocation MipsMir2Lir::GetReturnWideAlt() {
@@ -420,33 +445,37 @@ void MipsMir2Lir::FreeCallTemps() {
FreeTemp(rs_rMIPS_ARG3);
}
-bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
- UNUSED(barrier_kind);
-#if ANDROID_SMP != 0
- NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
- return true;
-#else
- return false;
-#endif
+bool MipsMir2Lir::GenMemBarrier(MemBarrierKind barrier_kind ATTRIBUTE_UNUSED) {
+ if (cu_->GetInstructionSetFeatures()->IsSmp()) {
+ NewLIR1(kMipsSync, 0 /* Only stype currently supported */);
+ return true;
+ } else {
+ return false;
+ }
}
void MipsMir2Lir::CompilerInitializeRegAlloc() {
+ const bool fpu_is_32bit =
+ cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()->Is32BitFloatingPoint();
reg_pool_.reset(new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */,
- sp_regs, dp_regs,
+ sp_regs,
+ fpu_is_32bit ? dp_fr0_regs : dp_fr1_regs,
reserved_regs, empty_pool /* reserved64 */,
core_temps, empty_pool /* core64_temps */,
- sp_temps, dp_temps));
+ sp_temps,
+ fpu_is_32bit ? dp_fr0_temps : dp_fr1_temps));
// Target-specific adjustments.
// Alias single precision floats to appropriate half of overlapping double.
for (RegisterInfo* info : reg_pool_->sp_regs_) {
int sp_reg_num = info->GetReg().GetRegNum();
-#if (FR_BIT == 0)
- int dp_reg_num = sp_reg_num & ~1;
-#else
- int dp_reg_num = sp_reg_num >> 1;
-#endif
+ int dp_reg_num;
+ if (fpu_is_32bit) {
+ dp_reg_num = sp_reg_num & ~1;
+ } else {
+ dp_reg_num = sp_reg_num >> 1;
+ }
RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
// Double precision register's master storage should refer to itself.
@@ -465,11 +494,11 @@ void MipsMir2Lir::CompilerInitializeRegAlloc() {
// TODO: adjust when we roll to hard float calling convention.
reg_pool_->next_core_reg_ = 2;
reg_pool_->next_sp_reg_ = 2;
-#if (FR_BIT == 0)
- reg_pool_->next_dp_reg_ = 2;
-#else
- reg_pool_->next_dp_reg_ = 1;
-#endif
+ if (fpu_is_32bit) {
+ reg_pool_->next_dp_reg_ = 2;
+ } else {
+ reg_pool_->next_dp_reg_ = 1;
+ }
}
/*
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index a7dc84f6aa..18f1cde353 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -15,6 +15,8 @@
*/
#include "codegen_mips.h"
+
+#include "arch/mips/instruction_set_features_mips.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "dex/reg_storage_eq.h"
#include "mips_lir.h"
@@ -304,20 +306,22 @@ LIR* MipsMir2Lir::OpRegReg(OpKind op, RegStorage r_dest_src1, RegStorage r_src2)
case kOpXor:
return OpRegRegReg(op, r_dest_src1, r_dest_src1, r_src2);
case kOp2Byte:
-#if __mips_isa_rev >= 2
- res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
- res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
- OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
-#endif
+ if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+ ->IsMipsIsaRevGreaterThanEqual2()) {
+ res = NewLIR2(kMipsSeb, r_dest_src1.GetReg(), r_src2.GetReg());
+ } else {
+ res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 24);
+ OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 24);
+ }
return res;
case kOp2Short:
-#if __mips_isa_rev >= 2
- res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
-#else
- res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
- OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
-#endif
+ if (cu_->GetInstructionSetFeatures()->AsMipsInstructionSetFeatures()
+ ->IsMipsIsaRevGreaterThanEqual2()) {
+ res = NewLIR2(kMipsSeh, r_dest_src1.GetReg(), r_src2.GetReg());
+ } else {
+ res = OpRegRegImm(kOpLsl, r_dest_src1, r_src2, 16);
+ OpRegRegImm(kOpAsr, r_dest_src1, r_dest_src1, 16);
+ }
return res;
case kOp2Char:
return NewLIR3(kMipsAndi, r_dest_src1.GetReg(), r_src2.GetReg(), 0xFFFF);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index bacc6d2e41..13ebc1e5d6 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -17,7 +17,7 @@
#ifndef ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
#define ART_COMPILER_DEX_QUICK_MIR_TO_LIR_H_
-#include "invoke_type.h"
+#include "arch/instruction_set.h"
#include "compiled_method.h"
#include "dex/compiler_enums.h"
#include "dex/compiler_ir.h"
@@ -26,9 +26,9 @@
#include "dex/backend.h"
#include "dex/quick/resource_mask.h"
#include "driver/compiler_driver.h"
-#include "instruction_set.h"
-#include "leb128.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "invoke_type.h"
+#include "leb128.h"
#include "safe_map.h"
#include "utils/array_ref.h"
#include "utils/arena_allocator.h"
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ddb2342b42..437a1a9c0e 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include "arch/instruction_set.h"
#include "base/mutex.h"
#include "base/timing_logger.h"
#include "class_reference.h"
@@ -28,7 +29,6 @@
#include "compiler.h"
#include "dex_file.h"
#include "driver/compiler_options.h"
-#include "instruction_set.h"
#include "invoke_type.h"
#include "method_reference.h"
#include "mirror/class.h" // For mirror::Class::Status.
@@ -51,6 +51,7 @@ class CompilerOptions;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
struct InlineIGetIPutData;
+class InstructionSetFeatures;
class OatWriter;
class ParallelCompilationManager;
class ScopedObjectAccess;
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 7f3056500c..273b62deee 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -17,12 +17,12 @@
#ifndef ART_COMPILER_ELF_BUILDER_H_
#define ART_COMPILER_ELF_BUILDER_H_
+#include "arch/instruction_set.h"
#include "base/stl_util.h"
#include "base/value_object.h"
#include "buffered_output_stream.h"
#include "elf_utils.h"
#include "file_output_stream.h"
-#include "instruction_set.h"
namespace art {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index c384c57c3a..ce4ed6d22b 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "arch/instruction_set_features.h"
#include "class_linker.h"
#include "common_compiler_test.h"
#include "compiler.h"
@@ -97,7 +98,7 @@ TEST_F(OatTest, WriteRead) {
std::string error_msg;
std::unique_ptr<const InstructionSetFeatures> insn_features(
- InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+ InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
compiler_options_.reset(new CompilerOptions);
verification_results_.reset(new VerificationResults(compiler_options_.get()));
@@ -198,7 +199,7 @@ TEST_F(OatTest, OatHeaderIsValid) {
InstructionSet insn_set = kX86;
std::string error_msg;
std::unique_ptr<const InstructionSetFeatures> insn_features(
- InstructionSetFeatures::FromFeatureString(insn_set, "default", &error_msg));
+ InstructionSetFeatures::FromVariant(insn_set, "default", &error_msg));
ASSERT_TRUE(insn_features.get() != nullptr) << error_msg;
std::vector<const DexFile*> dex_files;
uint32_t image_file_location_oat_checksum = 0;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index ac4fc67c2c..63bf96ca5a 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -17,9 +17,9 @@
#ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
+#include "arch/instruction_set.h"
#include "base/bit_field.h"
#include "globals.h"
-#include "instruction_set.h"
#include "locations.h"
#include "memory_region.h"
#include "nodes.h"
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 9752b1d34b..fee3ea6f8c 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -16,6 +16,7 @@
#include <functional>
+#include "arch/instruction_set.h"
#include "base/macros.h"
#include "builder.h"
#include "code_generator_arm.h"
@@ -25,7 +26,6 @@
#include "common_compiler_test.h"
#include "dex_file.h"
#include "dex_instruction.h"
-#include "instruction_set.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "prepare_for_register_allocation.h"
@@ -39,7 +39,7 @@ namespace art {
class InternalCodeAllocator : public CodeAllocator {
public:
- InternalCodeAllocator() { }
+ InternalCodeAllocator() : size_(0) { }
virtual uint8_t* Allocate(size_t size) {
size_ = size;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index ad7e98d906..67711e312c 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -19,16 +19,16 @@
#include <vector>
+#include "arch/instruction_set.h"
#include "base/logging.h"
#include "base/macros.h"
#include "arm/constants_arm.h"
-#include "mips/constants_mips.h"
-#include "x86/constants_x86.h"
-#include "x86_64/constants_x86_64.h"
-#include "instruction_set.h"
#include "managed_register.h"
#include "memory_region.h"
+#include "mips/constants_mips.h"
#include "offsets.h"
+#include "x86/constants_x86.h"
+#include "x86_64/constants_x86_64.h"
namespace art {
diff --git a/compiler/utils/stack_checks.h b/compiler/utils/stack_checks.h
index e762f7d266..c348f2c8ee 100644
--- a/compiler/utils/stack_checks.h
+++ b/compiler/utils/stack_checks.h
@@ -17,7 +17,7 @@
#ifndef ART_COMPILER_UTILS_STACK_CHECKS_H_
#define ART_COMPILER_UTILS_STACK_CHECKS_H_
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
namespace art {
@@ -34,8 +34,7 @@ static constexpr size_t kSmallFrameSize = 1 * KB;
// stack overflow check on method entry.
//
// A frame is considered large when it's above kLargeFrameSize.
-static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa) {
- UNUSED(isa);
+static inline bool FrameNeedsStackCheck(size_t size, InstructionSet isa ATTRIBUTE_UNUSED) {
return size >= kLargeFrameSize;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 47b492ae7c..2d2a82e985 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -31,8 +31,9 @@
#endif
#define ATRACE_TAG ATRACE_TAG_DALVIK
-#include "cutils/trace.h"
+#include <cutils/trace.h>
+#include "arch/instruction_set_features.h"
#include "base/dumpable.h"
#include "base/stl_util.h"
#include "base/stringpiece.h"
@@ -577,11 +578,18 @@ class Dex2Oat FINAL {
}
} else if (option.starts_with("--instruction-set-features=")) {
StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
+ if (instruction_set_features_.get() == nullptr) {
+ instruction_set_features_.reset(
+ InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+ if (instruction_set_features_.get() == nullptr) {
+ Usage("Problem initializing default instruction set features variant: %s",
+ error_msg.c_str());
+ }
+ }
instruction_set_features_.reset(
- InstructionSetFeatures::FromFeatureString(instruction_set_, str.as_string(),
- &error_msg));
+ instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
if (instruction_set_features_.get() == nullptr) {
- Usage("%s", error_msg.c_str());
+ Usage("Error parsing '%s': %s", option.data(), error_msg.c_str());
}
} else if (option.starts_with("--compiler-backend=")) {
StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
@@ -802,7 +810,11 @@ class Dex2Oat FINAL {
// instruction set.
if (instruction_set_features_.get() == nullptr) {
instruction_set_features_.reset(
- InstructionSetFeatures::FromFeatureString(instruction_set_, "default", &error_msg));
+ InstructionSetFeatures::FromVariant(instruction_set_, "default", &error_msg));
+ if (instruction_set_features_.get() == nullptr) {
+ Usage("Problem initializing default instruction set features variant: %s",
+ error_msg.c_str());
+ }
}
if (instruction_set_ == kRuntimeISA) {
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 487f43315a..9cd631c984 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -21,8 +21,8 @@
#include <iosfwd>
+#include "arch/instruction_set.h"
#include "base/macros.h"
-#include "instruction_set.h"
namespace art {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f1f1a56ae4..d6309f7be3 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -23,6 +23,7 @@
#include <unordered_map>
#include <vector>
+#include "arch/instruction_set_features.h"
#include "base/stringpiece.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 75160ca3d5..6b6d11e96c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -34,12 +34,8 @@
#include "elf_file_impl.h"
#include "gc/space/image_space.h"
#include "image.h"
-#include "instruction_set.h"
-#include "mirror/art_field.h"
#include "mirror/art_field-inl.h"
-#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
-#include "mirror/object.h"
#include "mirror/object-inl.h"
#include "mirror/reference.h"
#include "noop_compiler_callbacks.h"
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index 0ceef6430b..5a3545bb7b 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -17,14 +17,14 @@
#ifndef ART_PATCHOAT_PATCHOAT_H_
#define ART_PATCHOAT_PATCHOAT_H_
+#include "arch/instruction_set.h"
#include "base/macros.h"
#include "base/mutex.h"
-#include "instruction_set.h"
-#include "os.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc/accounting/space_bitmap.h"
#include "gc/heap.h"
+#include "os.h"
#include "utils.h"
namespace art {
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 082e8dd9cd..8ced4d9d61 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -73,7 +73,6 @@ LIBART_COMMON_SRC_FILES := \
hprof/hprof.cc \
image.cc \
indirect_reference_table.cc \
- instruction_set.cc \
instrumentation.cc \
intern_table.cc \
interpreter/interpreter.cc \
@@ -165,11 +164,18 @@ LIBART_COMMON_SRC_FILES := \
LIBART_COMMON_SRC_FILES += \
arch/context.cc \
+ arch/instruction_set.cc \
+ arch/instruction_set_features.cc \
arch/memcmp16.cc \
+ arch/arm/instruction_set_features_arm.cc \
arch/arm/registers_arm.cc \
+ arch/arm64/instruction_set_features_arm64.cc \
arch/arm64/registers_arm64.cc \
- arch/x86/registers_x86.cc \
+ arch/mips/instruction_set_features_mips.cc \
arch/mips/registers_mips.cc \
+ arch/x86/instruction_set_features_x86.cc \
+ arch/x86/registers_x86.cc \
+ arch/x86_64/registers_x86_64.cc \
entrypoints/entrypoint_utils.cc \
entrypoints/interpreter/interpreter_entrypoints.cc \
entrypoints/jni/jni_entrypoints.cc \
@@ -216,7 +222,7 @@ LIBART_TARGET_SRC_FILES := \
LIBART_TARGET_SRC_FILES_arm := \
arch/arm/context_arm.cc.arm \
arch/arm/entrypoints_init_arm.cc \
- arch/arm/instruction_set_features_arm.S \
+ arch/arm/instruction_set_features_assembly_tests.S \
arch/arm/jni_entrypoints_arm.S \
arch/arm/memcmp16_arm.S \
arch/arm/portable_entrypoints_arm.S \
@@ -292,7 +298,7 @@ LIBART_HOST_SRC_FILES_64 := \
$(LIBART_SRC_FILES_x86_64)
LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
- arch/x86_64/registers_x86_64.h \
+ arch/instruction_set.h \
base/allocator.h \
base/mutex.h \
debugger.h \
@@ -306,7 +312,6 @@ LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
gc/heap.h \
instrumentation.h \
indirect_reference_table.h \
- instruction_set.h \
invoke_type.h \
jdwp/jdwp.h \
jdwp/jdwp_constants.h \
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 480190a4bb..325b283b83 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -23,7 +23,6 @@
#include "globals.h"
#include "base/logging.h"
#include "base/hex_dump.h"
-#include "instruction_set.h"
#include "mirror/art_method.h"
#include "mirror/art_method-inl.h"
#include "thread.h"
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc
new file mode 100644
index 0000000000..f49c0371e0
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.cc
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_arm.h"
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
+#include "signal.h"
+#include <fstream>
+
+#include "base/stringprintf.h"
+#include "utils.h" // For Trim.
+
+#if defined(__arm__)
+extern "C" bool artCheckForArmSdivInstruction();
+#endif
+
+namespace art {
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
+ const std::string& variant, std::string* error_msg) {
+ // Assume all ARM processors are SMP.
+ // TODO: set the SMP support based on variant.
+ const bool smp = true;
+
+ // Look for variants that have divide support.
+ static const char* arm_variants_with_div[] = {
+ "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
+ "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
+ "cyclone", "denver", "krait", "swift"};
+
+ bool has_div = FindVariantInArray(arm_variants_with_div, arraysize(arm_variants_with_div),
+ variant);
+
+ // Look for variants that have LPAE support.
+ static const char* arm_variants_with_lpae[] = {
+ "cortex-a7", "cortex-a15", "krait", "denver"
+ };
+ bool has_lpae = FindVariantInArray(arm_variants_with_lpae, arraysize(arm_variants_with_lpae),
+ variant);
+
+ if (has_div == false && has_lpae == false) {
+ // Avoid unsupported variants.
+ static const char* unsupported_arm_variants[] = {
+ // ARM processors that aren't ARMv7 compatible aren't supported.
+ "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
+ "cortex-m0", "cortex-m0plus", "cortex-m1",
+ "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
+ "iwmmxt", "iwmmxt2",
+ "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
+ "xscale"
+ };
+ if (FindVariantInArray(unsupported_arm_variants, arraysize(unsupported_arm_variants),
+ variant)) {
+ *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", variant.c_str());
+ return nullptr;
+ }
+ // Warn if the variant is unknown.
+ // TODO: some of the variants below may have feature support, but that support is currently
+ // unknown so we'll choose conservative (sub-optimal) defaults without warning.
+ // TODO: some of the architectures may not support all features required by ART and should be
+ // moved to unsupported_arm_variants[] above.
+ static const char* arm_variants_without_known_features[] = {
+ "default",
+ "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
+ "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
+ "arm710t", "arm720t", "arm740t",
+ "arm8", "arm810",
+ "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
+ "arm926ej-s", "arm940t", "arm9tdmi",
+ "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
+ "arm1136j-s", "arm1136jf-s",
+ "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
+ "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
+ "marvell-pj4", "mpcore", "mpcorenovfp"
+ };
+ if (!FindVariantInArray(arm_variants_without_known_features,
+ arraysize(arm_variants_without_known_features),
+ variant)) {
+ LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
+ << ") using conservative defaults";
+ }
+ }
+ return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+ bool smp = (bitmap & kSmpBitfield) != 0;
+ bool has_div = (bitmap & kDivBitfield) != 0;
+ bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0;
+ return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+ const bool smp = false;
+#else
+ const bool smp = true;
+#endif
+
+#if defined(__ARM_ARCH_EXT_IDIV__)
+ const bool has_div = true;
+#else
+ const bool has_div = false;
+#endif
+#if defined(__ARM_FEATURE_LPAE)
+ const bool has_lpae = true;
+#else
+ const bool has_lpae = false;
+#endif
+ return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ bool smp = false;
+ bool has_lpae = false;
+ bool has_div = false;
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("Features") != std::string::npos) {
+ LOG(INFO) << "found features";
+ if (line.find("idivt") != std::string::npos) {
+ // We always expect both ARM and Thumb divide instructions to be available or not
+ // available.
+ CHECK_NE(line.find("idiva"), std::string::npos);
+ has_div = true;
+ }
+ if (line.find("lpae") != std::string::npos) {
+ has_lpae = true;
+ }
+ } else if (line.find("processor") != std::string::npos &&
+ line.find(": 1") != std::string::npos) {
+ smp = true;
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(ERROR) << "Failed to open /proc/cpuinfo";
+ }
+ return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
+ bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+
+ bool has_div = false;
+ bool has_lpae = false;
+
+#if defined(HAVE_ANDROID_OS) && defined(__arm__)
+ uint64_t hwcaps = getauxval(AT_HWCAP);
+ LOG(INFO) << "hwcaps=" << hwcaps;
+ if ((hwcaps & HWCAP_IDIVT) != 0) {
+ // We always expect both ARM and Thumb divide instructions to be available or not
+ // available.
+ CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
+ has_div = true;
+ }
+ if ((hwcaps & HWCAP_LPAE) != 0) {
+ has_lpae = true;
+ }
+#endif
+
+ return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+// A signal handler called by a fault for an illegal instruction. We record the fact in r0
+// and then increment the PC in the signal context to return to the next instruction. We know the
+// instruction is an sdiv (4 bytes long).
+static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED,
+ void* data) {
+#if defined(__arm__)
+ struct ucontext *uc = (struct ucontext *)data;
+ struct sigcontext *sc = &uc->uc_mcontext;
+ sc->arm_r0 = 0; // Set R0 to #0 to signal error.
+ sc->arm_pc += 4; // Skip offending instruction.
+#else
+ UNUSED(data);
+#endif
+}
+
+const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+ const bool smp = false;
+#else
+ const bool smp = true;
+#endif
+ // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv
+ // instruction. If we get a SIGILL then it's not supported.
+ struct sigaction sa, osa;
+ sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
+ sa.sa_sigaction = bad_divide_inst_handle;
+ sigaction(SIGILL, &sa, &osa);
+
+ bool has_div = false;
+#if defined(__arm__)
+ if (artCheckForArmSdivInstruction()) {
+ has_div = true;
+ }
+#endif
+
+ // Restore the signal handler.
+ sigaction(SIGILL, &osa, nullptr);
+
+ // Use compile time features to "detect" LPAE support.
+ // TODO: write an assembly LPAE support test.
+#if defined(__ARM_FEATURE_LPAE)
+ const bool has_lpae = true;
+#else
+ const bool has_lpae = false;
+#endif
+ return new ArmInstructionSetFeatures(smp, has_div, has_lpae);
+}
+
+bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+ if (kArm != other->GetInstructionSet()) {
+ return false;
+ }
+ const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
+ return IsSmp() == other_as_arm->IsSmp() &&
+ has_div_ == other_as_arm->has_div_ &&
+ has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_;
+}
+
+uint32_t ArmInstructionSetFeatures::AsBitmap() const {
+ return (IsSmp() ? kSmpBitfield : 0) |
+ (has_div_ ? kDivBitfield : 0) |
+ (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0);
+}
+
+std::string ArmInstructionSetFeatures::GetFeatureString() const {
+ std::string result;
+ if (IsSmp()) {
+ result += "smp";
+ } else {
+ result += "-smp";
+ }
+ if (has_div_) {
+ result += ",div";
+ } else {
+ result += ",-div";
+ }
+ if (has_atomic_ldrd_strd_) {
+ result += ",atomic_ldrd_strd";
+ } else {
+ result += ",-atomic_ldrd_strd";
+ }
+ return result;
+}
+
+const InstructionSetFeatures* ArmInstructionSetFeatures::AddFeaturesFromSplitString(
+ const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_;
+ bool has_div = has_div_;
+ for (auto i = features.begin(); i != features.end(); i++) {
+ std::string feature = Trim(*i);
+ if (feature == "div") {
+ has_div = true;
+ } else if (feature == "-div") {
+ has_div = false;
+ } else if (feature == "atomic_ldrd_strd") {
+ has_atomic_ldrd_strd = true;
+ } else if (feature == "-atomic_ldrd_strd") {
+ has_atomic_ldrd_strd = false;
+ } else {
+ *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+ return nullptr;
+ }
+ }
+ return new ArmInstructionSetFeatures(smp, has_div, has_atomic_ldrd_strd);
+}
+
+} // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.h b/runtime/arch/arm/instruction_set_features_arm.h
new file mode 100644
index 0000000000..221bf1fbc4
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+#define ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the ARM architecture.
+class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+ // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg);
+
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const ArmInstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const ArmInstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const ArmInstructionSetFeatures* FromAssembly();
+
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return kArm;
+ }
+
+ uint32_t AsBitmap() const OVERRIDE;
+
+ // Return a string of the form "div,lpae" or "none".
+ std::string GetFeatureString() const OVERRIDE;
+
+ // Is the divide instruction feature enabled?
+ bool HasDivideInstruction() const {
+ return has_div_;
+ }
+
+ // Are the ldrd and strd instructions atomic? This is commonly true when the Large Physical
+ // Address Extension (LPAE) is present.
+ bool HasAtomicLdrdAndStrd() const {
+ return has_atomic_ldrd_strd_;
+ }
+
+ virtual ~ArmInstructionSetFeatures() {}
+
+ protected:
+ // Parse a vector of the form "div", "lpae" adding these to a new ArmInstructionSetFeatures.
+ const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const OVERRIDE;
+
+ private:
+ ArmInstructionSetFeatures(bool smp, bool has_div, bool has_atomic_ldrd_strd)
+ : InstructionSetFeatures(smp),
+ has_div_(has_div), has_atomic_ldrd_strd_(has_atomic_ldrd_strd) {
+ }
+
+ // Bitmap positions for encoding features as a bitmap.
+ enum {
+ kSmpBitfield = 1,
+ kDivBitfield = 2,
+ kAtomicLdrdStrdBitfield = 4,
+ };
+
+ const bool has_div_;
+ const bool has_atomic_ldrd_strd_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_ARM_INSTRUCTION_SET_FEATURES_ARM_H_
diff --git a/runtime/arch/arm/instruction_set_features_arm_test.cc b/runtime/arch/arm/instruction_set_features_arm_test.cc
new file mode 100644
index 0000000000..44b1640f04
--- /dev/null
+++ b/runtime/arch/arm/instruction_set_features_arm_test.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_arm.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(ArmInstructionSetFeaturesTest, ArmFeaturesFromVariant) {
+ // Build features for a 32-bit ARM krait processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> krait_features(
+ InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
+ ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+ ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+ EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+ EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+ // Build features for a 32-bit ARM denver processor.
+ std::unique_ptr<const InstructionSetFeatures> denver_features(
+ InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
+ ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+ EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+ // Build features for a 32-bit ARMv7 processor.
+ std::unique_ptr<const InstructionSetFeatures> arm7_features(
+ InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+ ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+
+ // ARM6 is not a supported architecture variant.
+ std::unique_ptr<const InstructionSetFeatures> arm6_features(
+ InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
+ EXPECT_TRUE(arm6_features.get() == nullptr);
+ EXPECT_NE(error_msg.size(), 0U);
+}
+
+TEST(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> base_features(
+ InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
+ ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+ // Build features for a 32-bit ARM with LPAE and div processor.
+ std::unique_ptr<const InstructionSetFeatures> krait_features(
+ base_features->AddFeaturesFromString("atomic_ldrd_strd,div", &error_msg));
+ ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
+
+ ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
+ EXPECT_TRUE(krait_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str());
+ EXPECT_EQ(krait_features->AsBitmap(), 7U);
+
+ // Build features for a 32-bit ARM processor with LPAE and div flipped.
+ std::unique_ptr<const InstructionSetFeatures> denver_features(
+ base_features->AddFeaturesFromString("div,atomic_ldrd_strd", &error_msg));
+ ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(denver_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->Equals(krait_features.get()));
+ EXPECT_TRUE(krait_features->Equals(denver_features.get()));
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str());
+ EXPECT_EQ(denver_features->AsBitmap(), 7U);
+
+ // Build features for a 32-bit default ARM processor.
+ std::unique_ptr<const InstructionSetFeatures> arm7_features(
+ base_features->AddFeaturesFromString("default", &error_msg));
+ ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
+ EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
+ EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd());
+ EXPECT_STREQ("smp,-div,-atomic_ldrd_strd", arm7_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm7_features->AsBitmap(), 1U);
+}
+
+} // namespace art
diff --git a/runtime/arch/arm/instruction_set_features_arm.S b/runtime/arch/arm/instruction_set_features_assembly_tests.S
index c26f2cd003..c1086df0f6 100644
--- a/runtime/arch/arm/instruction_set_features_arm.S
+++ b/runtime/arch/arm/instruction_set_features_assembly_tests.S
@@ -23,7 +23,7 @@
// caller must arrange for the signal handler to set the r0
// register to 0 and move the pc forward by 4 bytes (to skip
// the invalid instruction).
-ENTRY artCheckForARMSDIVInstruction
+ENTRY artCheckForArmSdivInstruction
mov r1,#1
// depending on the architecture, the assembler will not allow an
// sdiv instruction, so we will have to output the bytes directly.
@@ -35,4 +35,4 @@ ENTRY artCheckForARMSDIVInstruction
// It will have 0 otherwise (set by the signal handler)
// the value is just returned from this function.
bx lr
-END artCheckForARMSDIVInstruction
+END artCheckForArmSdivInstruction
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc
new file mode 100644
index 0000000000..18536ed6d6
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_arm64.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h" // For Trim.
+
+namespace art {
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromVariant(
+ const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED) {
+ if (variant != "default") {
+ std::ostringstream os;
+ os << "Unexpected CPU variant for Arm64: " << variant;
+ *error_msg = os.str();
+ return nullptr;
+ }
+ const bool smp = true; // Conservative default.
+ const bool is_a53 = true; // Pessimistically assume all ARM64s are A53s.
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+ bool smp = (bitmap & kSmpBitfield) != 0;
+ bool is_a53 = (bitmap & kA53Bitfield) != 0;
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+ const bool smp = false;
+#else
+ const bool smp = true;
+#endif
+
+ const bool is_a53 = true; // Pessimistically assume all ARM64s are A53s.
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromCpuInfo() {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ bool smp = false;
+ const bool is_a53 = true; // Conservative default.
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+ smp = true;
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(ERROR) << "Failed to open /proc/cpuinfo";
+ }
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromHwcap() {
+ bool smp = sysconf(_SC_NPROCESSORS_CONF) > 1;
+ const bool is_a53 = true; // Pessimistically assume all ARM64s are A53s.
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+const Arm64InstructionSetFeatures* Arm64InstructionSetFeatures::FromAssembly() {
+ UNIMPLEMENTED(WARNING);
+ return FromCppDefines();
+}
+
+bool Arm64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+ if (kArm64 != other->GetInstructionSet()) {
+ return false;
+ }
+ const Arm64InstructionSetFeatures* other_as_arm = other->AsArm64InstructionSetFeatures();
+ return fix_cortex_a53_835769_ == other_as_arm->fix_cortex_a53_835769_;
+}
+
+uint32_t Arm64InstructionSetFeatures::AsBitmap() const {
+ return (IsSmp() ? kSmpBitfield : 0) | (fix_cortex_a53_835769_ ? kA53Bitfield : 0);
+}
+
+std::string Arm64InstructionSetFeatures::GetFeatureString() const {
+ std::string result;
+ if (IsSmp()) {
+ result += "smp";
+ } else {
+ result += "-smp";
+ }
+ if (fix_cortex_a53_835769_) {
+ result += ",a53";
+ } else {
+ result += ",-a53";
+ }
+ return result;
+}
+
+const InstructionSetFeatures* Arm64InstructionSetFeatures::AddFeaturesFromSplitString(
+ const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ bool is_a53 = fix_cortex_a53_835769_;
+ for (auto i = features.begin(); i != features.end(); i++) {
+ std::string feature = Trim(*i);
+ if (feature == "a53") {
+ is_a53 = true;
+ } else if (feature == "-a53") {
+ is_a53 = false;
+ } else {
+ *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+ return nullptr;
+ }
+ }
+ return new Arm64InstructionSetFeatures(smp, is_a53);
+}
+
+} // namespace art
diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h
new file mode 100644
index 0000000000..ee41536449
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+#define ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the ARM64 architecture.
+class Arm64InstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+ // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
+ static const Arm64InstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg);
+
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const Arm64InstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const Arm64InstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const Arm64InstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const Arm64InstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const Arm64InstructionSetFeatures* FromAssembly();
+
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return kArm64;
+ }
+
+ uint32_t AsBitmap() const OVERRIDE;
+
+ // Return a string of the form "a53" or "none".
+ std::string GetFeatureString() const OVERRIDE;
+
+ // Generate code addressing Cortex-A53 erratum 835769?
+ bool NeedFixCortexA53_835769() const {
+ return fix_cortex_a53_835769_;
+ }
+
+ virtual ~Arm64InstructionSetFeatures() {}
+
+ protected:
+ // Parse a vector of the form "a53" adding these to a new ArmInstructionSetFeatures.
+ const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const OVERRIDE;
+
+ private:
+ explicit Arm64InstructionSetFeatures(bool smp, bool is_a53)
+ : InstructionSetFeatures(smp), fix_cortex_a53_835769_(is_a53) {
+ }
+
+ // Bitmap positions for encoding features as a bitmap.
+ enum {
+ kSmpBitfield = 1,
+ kA53Bitfield = 2,
+ };
+
+ const bool fix_cortex_a53_835769_;
+
+ DISALLOW_COPY_AND_ASSIGN(Arm64InstructionSetFeatures);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_ARM64_INSTRUCTION_SET_FEATURES_ARM64_H_
diff --git a/runtime/arch/arm64/instruction_set_features_arm64_test.cc b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
new file mode 100644
index 0000000000..027e59c57a
--- /dev/null
+++ b/runtime/arch/arm64/instruction_set_features_arm64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_arm64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(Arm64InstructionSetFeaturesTest, Arm64Features) {
+ // Build features for an ARM64 processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> arm64_features(
+ InstructionSetFeatures::FromVariant(kArm64, "default", &error_msg));
+ ASSERT_TRUE(arm64_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(arm64_features->GetInstructionSet(), kArm64);
+ EXPECT_TRUE(arm64_features->Equals(arm64_features.get()));
+ EXPECT_STREQ("smp,a53", arm64_features->GetFeatureString().c_str());
+ EXPECT_EQ(arm64_features->AsBitmap(), 3U);
+}
+
+} // namespace art
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
new file mode 100644
index 0000000000..92fa727674
--- /dev/null
+++ b/runtime/arch/instruction_set.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set.h"
+
+#include "globals.h"
+
+namespace art {
+
+const char* GetInstructionSetString(const InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ return "arm";
+ case kArm64:
+ return "arm64";
+ case kX86:
+ return "x86";
+ case kX86_64:
+ return "x86_64";
+ case kMips:
+ return "mips";
+ case kMips64:
+ return "mips64";
+ case kNone:
+ return "none";
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+InstructionSet GetInstructionSetFromString(const char* isa_str) {
+ CHECK(isa_str != nullptr);
+
+ if (strcmp("arm", isa_str) == 0) {
+ return kArm;
+ } else if (strcmp("arm64", isa_str) == 0) {
+ return kArm64;
+ } else if (strcmp("x86", isa_str) == 0) {
+ return kX86;
+ } else if (strcmp("x86_64", isa_str) == 0) {
+ return kX86_64;
+ } else if (strcmp("mips", isa_str) == 0) {
+ return kMips;
+ } else if (strcmp("mips64", isa_str) == 0) {
+ return kMips;
+ }
+
+ return kNone;
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ // Fall-through.
+ case kThumb2:
+ return kArmAlignment;
+ case kArm64:
+ return kArm64Alignment;
+ case kX86:
+ // Fall-through.
+ case kX86_64:
+ return kX86Alignment;
+ case kMips:
+ return kMipsAlignment;
+ case kNone:
+ LOG(FATAL) << "ISA kNone does not have alignment.";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
+static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+
+static constexpr size_t kArmStackOverflowReservedBytes = 8 * KB;
+static constexpr size_t kArm64StackOverflowReservedBytes = 8 * KB;
+static constexpr size_t kX86StackOverflowReservedBytes = 8 * KB;
+static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa) {
+ switch (isa) {
+ case kArm: // Intentional fall-through.
+ case kThumb2:
+ return kArmStackOverflowReservedBytes;
+
+ case kArm64:
+ return kArm64StackOverflowReservedBytes;
+
+ case kMips:
+ return kMipsStackOverflowReservedBytes;
+
+ case kX86:
+ return kX86StackOverflowReservedBytes;
+
+ case kX86_64:
+ return kX86_64StackOverflowReservedBytes;
+
+ case kNone:
+ LOG(FATAL) << "kNone has no stack overflow size";
+ UNREACHABLE();
+
+ default:
+ LOG(FATAL) << "Unknown instruction set" << isa;
+ UNREACHABLE();
+ }
+}
+
+} // namespace art
diff --git a/runtime/instruction_set.h b/runtime/arch/instruction_set.h
index 84a3e80636..46622eb37d 100644
--- a/runtime/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -14,16 +14,13 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_INSTRUCTION_SET_H_
-#define ART_RUNTIME_INSTRUCTION_SET_H_
+#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
#include <iosfwd>
#include <string>
#include "base/logging.h" // Logging is required for FATAL in the helper functions.
-#include "base/macros.h"
-#include "base/value_object.h"
-#include "globals.h" // For KB.
namespace art {
@@ -99,10 +96,10 @@ static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
return kMips64PointerSize;
case kNone:
LOG(FATAL) << "ISA kNone does not have pointer size.";
- return 0;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
+ UNREACHABLE();
}
}
@@ -123,10 +120,10 @@ static inline bool Is64BitInstructionSet(InstructionSet isa) {
case kNone:
LOG(FATAL) << "ISA kNone does not have bit width.";
- return 0;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
+ UNREACHABLE();
}
}
@@ -146,10 +143,10 @@ static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
return 4;
case kNone:
LOG(FATAL) << "ISA kNone does not have spills.";
- return 0;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
+ UNREACHABLE();
}
}
@@ -169,174 +166,15 @@ static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
return 4;
case kNone:
LOG(FATAL) << "ISA kNone does not have spills.";
- return 0;
+ UNREACHABLE();
default:
LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
+ UNREACHABLE();
}
}
size_t GetStackOverflowReservedBytes(InstructionSet isa);
-class ArmInstructionSetFeatures;
-
-// Abstraction used to describe features of a different instruction sets.
-class InstructionSetFeatures {
- public:
- // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
- static const InstructionSetFeatures* FromVariant(InstructionSet isa,
- const std::string& variant,
- std::string* error_msg);
-
- // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
- static const InstructionSetFeatures* FromFeatureString(InstructionSet isa,
- const std::string& feature_list,
- std::string* error_msg);
-
- // Parse a bitmap for the given isa and create an InstructionSetFeatures.
- static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
-
- // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
- static const InstructionSetFeatures* FromCppDefines();
-
- // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
- static const InstructionSetFeatures* FromCpuInfo();
-
- // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
- // InstructionSetFeatures.
- static const InstructionSetFeatures* FromHwcap();
-
- // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
- // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
- static const InstructionSetFeatures* FromAssembly();
-
- // Are these features the same as the other given features?
- virtual bool Equals(const InstructionSetFeatures* other) const = 0;
-
- // Return the ISA these features relate to.
- virtual InstructionSet GetInstructionSet() const = 0;
-
- // Return a bitmap that represents the features. ISA specific.
- virtual uint32_t AsBitmap() const = 0;
-
- // Return a string of the form "div,lpae" or "none".
- virtual std::string GetFeatureString() const = 0;
-
- // Down cast this ArmInstructionFeatures.
- const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
-
- virtual ~InstructionSetFeatures() {}
-
- protected:
- InstructionSetFeatures() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
-};
-std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
-
-// Instruction set features relevant to the ARM architecture.
-class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures {
- public:
- // Process a CPU variant string like "krait" or "cortex-a15" and create InstructionSetFeatures.
- static const ArmInstructionSetFeatures* FromVariant(const std::string& variant,
- std::string* error_msg);
-
- // Parse a string of the form "div,lpae" and create an InstructionSetFeatures.
- static const ArmInstructionSetFeatures* FromFeatureString(const std::string& feature_list,
- std::string* error_msg);
-
- // Parse a bitmap and create an InstructionSetFeatures.
- static const ArmInstructionSetFeatures* FromBitmap(uint32_t bitmap);
-
- // Turn C pre-processor #defines into the equivalent instruction set features.
- static const ArmInstructionSetFeatures* FromCppDefines();
-
- // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
- static const ArmInstructionSetFeatures* FromCpuInfo();
-
- // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
- // InstructionSetFeatures.
- static const ArmInstructionSetFeatures* FromHwcap();
-
- // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
- // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
- static const ArmInstructionSetFeatures* FromAssembly();
-
- bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
-
- InstructionSet GetInstructionSet() const OVERRIDE {
- return kArm;
- }
-
- uint32_t AsBitmap() const OVERRIDE;
-
- // Return a string of the form "div,lpae" or "none".
- std::string GetFeatureString() const OVERRIDE;
-
- // Is the divide instruction feature enabled?
- bool HasDivideInstruction() const {
- return has_div_;
- }
-
- // Is the Large Physical Address Extension (LPAE) instruction feature enabled? When true code can
- // be used that assumes double register loads and stores (ldrd, strd) don't tear.
- bool HasLpae() const {
- return has_lpae_;
- }
-
- virtual ~ArmInstructionSetFeatures() {}
-
- private:
- ArmInstructionSetFeatures(bool has_lpae, bool has_div)
- : has_lpae_(has_lpae), has_div_(has_div) {
- }
-
- // Bitmap positions for encoding features as a bitmap.
- enum {
- kDivBitfield = 1,
- kLpaeBitfield = 2,
- };
-
- const bool has_lpae_;
- const bool has_div_;
-
- DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures);
-};
-
-// A class used for instruction set features on ISAs that don't yet have any features defined.
-class UnknownInstructionSetFeatures FINAL : public InstructionSetFeatures {
- public:
- static const UnknownInstructionSetFeatures* Unknown(InstructionSet isa) {
- return new UnknownInstructionSetFeatures(isa);
- }
-
- bool Equals(const InstructionSetFeatures* other) const OVERRIDE {
- return isa_ == other->GetInstructionSet();
- }
-
- InstructionSet GetInstructionSet() const OVERRIDE {
- return isa_;
- }
-
- uint32_t AsBitmap() const OVERRIDE {
- return 0;
- }
-
- std::string GetFeatureString() const OVERRIDE {
- return "none";
- }
-
- virtual ~UnknownInstructionSetFeatures() {}
-
- private:
- explicit UnknownInstructionSetFeatures(InstructionSet isa) : isa_(isa) {}
-
- const InstructionSet isa_;
-
- DISALLOW_COPY_AND_ASSIGN(UnknownInstructionSetFeatures);
-};
-
// The following definitions create return types for two word-sized entities that will be passed
// in registers so that memory operations for the interface trampolines can be avoided. The entities
// are the resolved method and the pointer to the code to be invoked.
@@ -402,4 +240,4 @@ static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
} // namespace art
-#endif // ART_RUNTIME_INSTRUCTION_SET_H_
+#endif // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
new file mode 100644
index 0000000000..10725620a4
--- /dev/null
+++ b/runtime/arch/instruction_set_features.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features.h"
+
+#include "base/casts.h"
+#include "utils.h"
+
+
+#include "arm/instruction_set_features_arm.h"
+#include "arm64/instruction_set_features_arm64.h"
+#include "mips/instruction_set_features_mips.h"
+#include "x86/instruction_set_features_x86.h"
+#include "x86_64/instruction_set_features_x86_64.h"
+
+namespace art {
+
+const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
+ const std::string& variant,
+ std::string* error_msg) {
+ const InstructionSetFeatures* result;
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromVariant(variant, error_msg);
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << isa;
+ UNREACHABLE();
+ }
+ CHECK_EQ(result == nullptr, error_msg->size() != 0);
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
+ uint32_t bitmap) {
+ const InstructionSetFeatures* result;
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromBitmap(bitmap);
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << isa;
+ UNREACHABLE();
+ }
+ CHECK_EQ(bitmap, result->AsBitmap());
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromCppDefines();
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromCppDefines();
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromCppDefines();
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromCppDefines();
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromCppDefines();
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << kRuntimeISA;
+ UNREACHABLE();
+ }
+ return result;
+}
+
+
+const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromCpuInfo();
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromCpuInfo();
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromCpuInfo();
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromCpuInfo();
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromCpuInfo();
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << kRuntimeISA;
+ UNREACHABLE();
+ }
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromHwcap();
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromHwcap();
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromHwcap();
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromHwcap();
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromHwcap();
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << kRuntimeISA;
+ UNREACHABLE();
+ }
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
+ const InstructionSetFeatures* result;
+ switch (kRuntimeISA) {
+ case kArm:
+ case kThumb2:
+ result = ArmInstructionSetFeatures::FromAssembly();
+ break;
+ case kArm64:
+ result = Arm64InstructionSetFeatures::FromAssembly();
+ break;
+ case kMips:
+ result = MipsInstructionSetFeatures::FromAssembly();
+ break;
+ case kX86:
+ result = X86InstructionSetFeatures::FromAssembly();
+ break;
+ case kX86_64:
+ result = X86_64InstructionSetFeatures::FromAssembly();
+ break;
+ default:
+ UNIMPLEMENTED(FATAL) << kRuntimeISA;
+ UNREACHABLE();
+ }
+ return result;
+}
+
+const InstructionSetFeatures* InstructionSetFeatures::AddFeaturesFromString(
+ const std::string& feature_list, std::string* error_msg) const {
+ if (feature_list.empty()) {
+ *error_msg = "No instruction set features specified";
+ return nullptr;
+ }
+ std::vector<std::string> features;
+ Split(feature_list, ',', &features);
+ bool smp = smp_;
+ bool use_default = false; // Have we seen the 'default' feature?
+ bool first = false; // Is this first feature?
+ for (auto it = features.begin(); it != features.end();) {
+ if (use_default) {
+ *error_msg = "Unexpected instruction set features after 'default'";
+ return nullptr;
+ }
+ std::string feature = Trim(*it);
+ bool erase = false;
+ if (feature == "default") {
+ if (!first) {
+ use_default = true;
+ erase = true;
+ } else {
+ *error_msg = "Unexpected instruction set features before 'default'";
+ return nullptr;
+ }
+ } else if (feature == "smp") {
+ smp = true;
+ erase = true;
+ } else if (feature == "-smp") {
+ smp = false;
+ erase = true;
+ }
+ // Erase the smp feature once processed.
+ if (!erase) {
+ ++it;
+ } else {
+ it = features.erase(it);
+ }
+ first = true;
+ }
+ DCHECK_EQ(use_default, features.empty());
+ return AddFeaturesFromSplitString(smp, features, error_msg);
+}
+
+const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
+ DCHECK_EQ(kArm, GetInstructionSet());
+ return down_cast<const ArmInstructionSetFeatures*>(this);
+}
+
+const Arm64InstructionSetFeatures* InstructionSetFeatures::AsArm64InstructionSetFeatures() const {
+ DCHECK_EQ(kArm64, GetInstructionSet());
+ return down_cast<const Arm64InstructionSetFeatures*>(this);
+}
+
+const MipsInstructionSetFeatures* InstructionSetFeatures::AsMipsInstructionSetFeatures() const {
+ DCHECK_EQ(kMips, GetInstructionSet());
+ return down_cast<const MipsInstructionSetFeatures*>(this);
+}
+
+const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
+ DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
+ return down_cast<const X86InstructionSetFeatures*>(this);
+}
+
+const X86_64InstructionSetFeatures* InstructionSetFeatures::AsX86_64InstructionSetFeatures() const {
+ DCHECK_EQ(kX86_64, GetInstructionSet());
+ return down_cast<const X86_64InstructionSetFeatures*>(this);
+}
+
+bool InstructionSetFeatures::FindVariantInArray(const char* variants[], size_t num_variants,
+ const std::string& variant) {
+ const char** begin = variants;
+ const char** end = begin + num_variants;
+ return std::find(begin, end, variant) != end;
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
+ os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
+ return os;
+}
+
+} // namespace art
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
new file mode 100644
index 0000000000..2c6e6995bc
--- /dev/null
+++ b/runtime/arch/instruction_set_features.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
+#define ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
+
+#include <ostream>
+#include <vector>
+
+#include "base/macros.h"
+#include "instruction_set.h"
+
+namespace art {
+
+class ArmInstructionSetFeatures;
+class Arm64InstructionSetFeatures;
+class MipsInstructionSetFeatures;
+class X86InstructionSetFeatures;
+class X86_64InstructionSetFeatures;
+
+// Abstraction used to describe features of a different instruction sets.
+class InstructionSetFeatures {
+ public:
+ // Process a CPU variant string for the given ISA and create an InstructionSetFeatures.
+ static const InstructionSetFeatures* FromVariant(InstructionSet isa,
+ const std::string& variant,
+ std::string* error_msg);
+
+ // Parse a bitmap for the given isa and create an InstructionSetFeatures.
+ static const InstructionSetFeatures* FromBitmap(InstructionSet isa, uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features for kRuntimeISA.
+ static const InstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const InstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const InstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const InstructionSetFeatures* FromAssembly();
+
+ // Parse a string of the form "div,-atomic_ldrd_strd" adding and removing these features to
+ // create a new InstructionSetFeatures.
+ const InstructionSetFeatures* AddFeaturesFromString(const std::string& feature_list,
+ std::string* error_msg) const WARN_UNUSED;
+
+ // Are these features the same as the other given features?
+ virtual bool Equals(const InstructionSetFeatures* other) const = 0;
+
+ // Return the ISA these features relate to.
+ virtual InstructionSet GetInstructionSet() const = 0;
+
+ // Return a bitmap that represents the features. ISA specific.
+ virtual uint32_t AsBitmap() const = 0;
+
+ // Return a string of the form "div,lpae" or "none".
+ virtual std::string GetFeatureString() const = 0;
+
+ // Does the instruction set variant require instructions for correctness with SMP?
+ bool IsSmp() const {
+ return smp_;
+ }
+
+ // Down cast this ArmInstructionFeatures.
+ const ArmInstructionSetFeatures* AsArmInstructionSetFeatures() const;
+
+ // Down cast this Arm64InstructionFeatures.
+ const Arm64InstructionSetFeatures* AsArm64InstructionSetFeatures() const;
+
+ // Down cast this MipsInstructionFeatures.
+ const MipsInstructionSetFeatures* AsMipsInstructionSetFeatures() const;
+
+ // Down cast this X86InstructionFeatures.
+ const X86InstructionSetFeatures* AsX86InstructionSetFeatures() const;
+
+ // Down cast this X86_64InstructionFeatures.
+ const X86_64InstructionSetFeatures* AsX86_64InstructionSetFeatures() const;
+
+ virtual ~InstructionSetFeatures() {}
+
+ protected:
+ explicit InstructionSetFeatures(bool smp) : smp_(smp) {}
+
+ // Returns true if variant appears in the array variants.
+ static bool FindVariantInArray(const char* variants[], size_t num_variants,
+ const std::string& variant);
+
+ // Add architecture specific features in sub-classes.
+ virtual const InstructionSetFeatures*
+ AddFeaturesFromSplitString(bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const = 0;
+
+ private:
+ const bool smp_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstructionSetFeatures);
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs);
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
new file mode 100644
index 0000000000..83571cf2b1
--- /dev/null
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features.h"
+
+#include <gtest/gtest.h>
+
+#ifdef HAVE_ANDROID_OS
+#include "cutils/properties.h"
+#endif
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+#ifdef HAVE_ANDROID_OS
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Read the features property.
+ std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
+ char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+ if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+ // Use features from property to build InstructionSetFeatures and check against build's
+ // features.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> property_features(
+ InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
+ ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+ << "System property features: " << *property_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+ }
+}
+
+TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) {
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Read the features property.
+ std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
+ char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+ if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+ // Use features from property to build InstructionSetFeatures and check against build's
+ // features.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> base_features(
+ InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
+ ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
+
+ std::unique_ptr<const InstructionSetFeatures> property_features(
+ base_features->AddFeaturesFromString(dex2oat_isa_features, &error_msg));
+ ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
+
+ EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
+ << "System property features: " << *property_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+ }
+}
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromCpuInfo) {
+ LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromCpuInfo) {
+#endif
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using /proc/cpuinfo.
+ std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
+ InstructionSetFeatures::FromCpuInfo());
+ EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
+ << "CPU Info features: " << *cpuinfo_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+#endif
+
+#ifndef HAVE_ANDROID_OS
+TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> default_features(
+ InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
+ ASSERT_TRUE(error_msg.empty());
+
+ std::unique_ptr<const InstructionSetFeatures> cpp_features(
+ InstructionSetFeatures::FromCppDefines());
+ EXPECT_TRUE(default_features->Equals(cpp_features.get()))
+ << "Default variant features: " << *default_features.get()
+ << "\nFeatures from build: " << *cpp_features.get();
+}
+#endif
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromHwcap) {
+ LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromHwcap) {
+#endif
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using AT_HWCAP.
+ std::unique_ptr<const InstructionSetFeatures> hwcap_features(
+ InstructionSetFeatures::FromHwcap());
+ EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
+ << "Hwcap features: " << *hwcap_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+
+#if defined(__arm__)
+TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromAssembly) {
+ LOG(WARNING) << "Test disabled due to buggy ARM kernels";
+#else
+TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) {
+#endif
+ // Take the default set of instruction features from the build.
+ std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
+ InstructionSetFeatures::FromCppDefines());
+
+ // Check we get the same instruction set features using assembly tests.
+ std::unique_ptr<const InstructionSetFeatures> assembly_features(
+ InstructionSetFeatures::FromAssembly());
+ EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
+ << "Assembly features: " << *assembly_features.get()
+ << "\nFeatures from build: " << *instruction_set_features.get();
+}
+
+} // namespace art
diff --git a/runtime/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc
new file mode 100644
index 0000000000..932ef323fc
--- /dev/null
+++ b/runtime/arch/instruction_set_test.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set.h"
+
+#include <gtest/gtest.h>
+
+#include "base/stringprintf.h"
+
+namespace art {
+
+TEST(InstructionSetTest, GetInstructionSetFromString) {
+ EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
+ EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
+ EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
+ EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
+ EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
+ EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
+ EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
+}
+
+TEST(InstructionSetTest, GetInstructionSetString) {
+ EXPECT_STREQ("arm", GetInstructionSetString(kArm));
+ EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
+ EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
+ EXPECT_STREQ("x86", GetInstructionSetString(kX86));
+ EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
+ EXPECT_STREQ("mips", GetInstructionSetString(kMips));
+ EXPECT_STREQ("none", GetInstructionSetString(kNone));
+}
+
+TEST(InstructionSetTest, TestRoundTrip) {
+ EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
+}
+
+TEST(InstructionSetTest, PointerSize) {
+ EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
+}
+
+} // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.cc b/runtime/arch/mips/instruction_set_features_mips.cc
new file mode 100644
index 0000000000..efec993340
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_mips.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h" // For Trim.
+
+namespace art {
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromVariant(
+ const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED) {
+ if (variant != "default") {
+ std::ostringstream os;
+ LOG(WARNING) << "Unexpected CPU variant for Mips using defaults: " << variant;
+ }
+ bool smp = true; // Conservative default.
+ bool fpu_32bit = true;
+ bool mips_isa_gte2 = true;
+ return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+ bool smp = (bitmap & kSmpBitfield) != 0;
+ bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0;
+ bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0;
+ return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCppDefines() {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+ const bool smp = false;
+#else
+ const bool smp = true;
+#endif
+
+ // TODO: here we assume the FPU is always 32-bit.
+ const bool fpu_32bit = true;
+
+#if __mips_isa_rev >= 2
+ const bool mips_isa_gte2 = true;
+#else
+ const bool mips_isa_gte2 = false;
+#endif
+
+ return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromCpuInfo() {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ bool smp = false;
+
+ // TODO: here we assume the FPU is always 32-bit.
+ const bool fpu_32bit = true;
+
+ // TODO: here we assume all MIPS processors are >= v2.
+#if __mips_isa_rev >= 2
+ const bool mips_isa_gte2 = true;
+#else
+ const bool mips_isa_gte2 = false;
+#endif
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+ smp = true;
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(ERROR) << "Failed to open /proc/cpuinfo";
+ }
+ return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromHwcap() {
+ UNIMPLEMENTED(WARNING);
+ return FromCppDefines();
+}
+
+const MipsInstructionSetFeatures* MipsInstructionSetFeatures::FromAssembly() {
+ UNIMPLEMENTED(WARNING);
+ return FromCppDefines();
+}
+
+bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+ if (kMips != other->GetInstructionSet()) {
+ return false;
+ }
+ const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures();
+ return (IsSmp() == other->IsSmp()) &&
+ (fpu_32bit_ == other_as_mips->fpu_32bit_) &&
+ (mips_isa_gte2_ == other_as_mips->mips_isa_gte2_);
+}
+
+uint32_t MipsInstructionSetFeatures::AsBitmap() const {
+ return (IsSmp() ? kSmpBitfield : 0) |
+ (fpu_32bit_ ? kFpu32Bitfield : 0) |
+ (mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0);
+}
+
+std::string MipsInstructionSetFeatures::GetFeatureString() const {
+ std::string result;
+ if (IsSmp()) {
+ result += "smp";
+ } else {
+ result += "-smp";
+ }
+ if (fpu_32bit_) {
+ result += ",fpu32";
+ } else {
+ result += ",-fpu32";
+ }
+ if (mips_isa_gte2_) {
+ result += ",mips2";
+ } else {
+ result += ",-mips2";
+ }
+ return result;
+}
+
+const InstructionSetFeatures* MipsInstructionSetFeatures::AddFeaturesFromSplitString(
+ const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+ bool fpu_32bit = fpu_32bit_;
+ bool mips_isa_gte2 = mips_isa_gte2_;
+ for (auto i = features.begin(); i != features.end(); i++) {
+ std::string feature = Trim(*i);
+ if (feature == "fpu32") {
+ fpu_32bit = true;
+ } else if (feature == "-fpu32") {
+ fpu_32bit = false;
+ } else if (feature == "mips2") {
+ mips_isa_gte2 = true;
+ } else if (feature == "-mips2") {
+ mips_isa_gte2 = false;
+ } else {
+ *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+ return nullptr;
+ }
+ }
+ return new MipsInstructionSetFeatures(smp, fpu_32bit, mips_isa_gte2);
+}
+
+} // namespace art
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
new file mode 100644
index 0000000000..f7c64fef10
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+#define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the MIPS architecture.
+class MipsInstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+ // Process a CPU variant string like "r4000" and create InstructionSetFeatures.
+ static const MipsInstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg);
+
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const MipsInstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const MipsInstructionSetFeatures* FromCppDefines();
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const MipsInstructionSetFeatures* FromCpuInfo();
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const MipsInstructionSetFeatures* FromHwcap();
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const MipsInstructionSetFeatures* FromAssembly();
+
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return kMips;
+ }
+
+ uint32_t AsBitmap() const OVERRIDE;
+
+ std::string GetFeatureString() const OVERRIDE;
+
+ // Is this an ISA revision greater than 2 opening up new opcodes.
+ bool IsMipsIsaRevGreaterThanEqual2() const {
+ return mips_isa_gte2_;
+ }
+
+ // Floating point double registers are encoded differently based on whether the Status.FR bit is
+ // set. When the FR bit is 0 then the FPU is 32-bit, 1 its 64-bit. Return true if the code should
+ // be generated assuming Status.FR is 0.
+ bool Is32BitFloatingPoint() const {
+ return fpu_32bit_;
+ }
+
+ virtual ~MipsInstructionSetFeatures() {}
+
+ protected:
+ // Parse a vector of the form "fpu32", "mips2" adding these to a new MipsInstructionSetFeatures.
+ virtual const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const OVERRIDE;
+
+ private:
+ MipsInstructionSetFeatures(bool smp, bool fpu_32bit, bool mips_isa_gte2)
+ : InstructionSetFeatures(smp), fpu_32bit_(fpu_32bit), mips_isa_gte2_(mips_isa_gte2) {
+ }
+
+ // Bitmap positions for encoding features as a bitmap.
+ enum {
+ kSmpBitfield = 1,
+ kFpu32Bitfield = 2,
+ kIsaRevGte2Bitfield = 4,
+ };
+
+ const bool fpu_32bit_;
+ const bool mips_isa_gte2_;
+
+ DISALLOW_COPY_AND_ASSIGN(MipsInstructionSetFeatures);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
diff --git a/runtime/arch/mips/instruction_set_features_mips_test.cc b/runtime/arch/mips/instruction_set_features_mips_test.cc
new file mode 100644
index 0000000000..9b81ce2582
--- /dev/null
+++ b/runtime/arch/mips/instruction_set_features_mips_test.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_mips.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(MipsInstructionSetFeaturesTest, MipsFeatures) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> mips_features(
+ InstructionSetFeatures::FromVariant(kMips, "default", &error_msg));
+ ASSERT_TRUE(mips_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(mips_features->GetInstructionSet(), kMips);
+ EXPECT_TRUE(mips_features->Equals(mips_features.get()));
+ EXPECT_STREQ("smp,fpu32,mips2", mips_features->GetFeatureString().c_str());
+ EXPECT_EQ(mips_features->AsBitmap(), 7U);
+}
+
+} // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.cc b/runtime/arch/x86/instruction_set_features_x86.cc
new file mode 100644
index 0000000000..32cf909fd1
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.cc
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_x86.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "arch/x86_64/instruction_set_features_x86_64.h"
+#include "base/stringprintf.h"
+#include "utils.h" // For Trim.
+
+namespace art {
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromVariant(
+ const std::string& variant ATTRIBUTE_UNUSED, std::string* error_msg ATTRIBUTE_UNUSED,
+ bool x86_64) {
+ bool known_variant = false;
+ bool smp = true; // Conservative default.
+ static const char* x86_variants_with_ssse3[] = {
+ "atom"
+ };
+ bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
+ variant);
+ bool has_SSE4_1 = false;
+ bool has_SSE4_2 = false;
+ bool has_AVX = false;
+ bool has_AVX2 = false;
+ if (!known_variant && variant != "default") {
+ std::ostringstream os;
+ LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
+ }
+
+ if (x86_64) {
+ return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ } else {
+ return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromBitmap(uint32_t bitmap,
+ bool x86_64) {
+ bool smp = (bitmap & kSmpBitfield) != 0;
+ bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
+ bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
+ bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
+ bool has_AVX = (bitmap & kAvxBitfield) != 0;
+ bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
+ if (x86_64) {
+ return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+ } else {
+ return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
+#if defined(HAVE_ANDROID_OS) && (ANDROID_SMP == 0)
+ const bool smp = false;
+#else
+ const bool smp = true;
+#endif
+
+#ifndef __SSSE3__
+ const bool has_SSSE3 = false;
+#else
+ const bool has_SSSE3 = true;
+#endif
+
+#ifndef __SSE4_1__
+ const bool has_SSE4_1 = false;
+#else
+ const bool has_SSE4_1 = true;
+#endif
+
+#ifndef __SSE4_2__
+ const bool has_SSE4_2 = false;
+#else
+ const bool has_SSE4_2 = true;
+#endif
+
+#ifndef __AVX__
+ const bool has_AVX = false;
+#else
+ const bool has_AVX = true;
+#endif
+
+#ifndef __AVX2__
+ const bool has_AVX2 = false;
+#else
+ const bool has_AVX2 = true;
+#endif
+
+ if (x86_64) {
+ return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+ } else {
+ return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
+ // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
+ // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
+ bool smp = false;
+ bool has_SSSE3 = false;
+ bool has_SSE4_1 = false;
+ bool has_SSE4_2 = false;
+ bool has_AVX = false;
+ bool has_AVX2 = false;
+
+ std::ifstream in("/proc/cpuinfo");
+ if (!in.fail()) {
+ while (!in.eof()) {
+ std::string line;
+ std::getline(in, line);
+ if (!in.eof()) {
+ LOG(INFO) << "cpuinfo line: " << line;
+ if (line.find("flags") != std::string::npos) {
+ LOG(INFO) << "found flags";
+ if (line.find("ssse3") != std::string::npos) {
+ has_SSSE3 = true;
+ }
+ if (line.find("sse4_1") != std::string::npos) {
+ has_SSE4_1 = true;
+ }
+ if (line.find("sse4_2") != std::string::npos) {
+ has_SSE4_2 = true;
+ }
+ if (line.find("avx") != std::string::npos) {
+ has_AVX = true;
+ }
+ if (line.find("avx2") != std::string::npos) {
+ has_AVX2 = true;
+ }
+ } else if (line.find("processor") != std::string::npos &&
+ line.find(": 1") != std::string::npos) {
+ smp = true;
+ }
+ }
+ }
+ in.close();
+ } else {
+ LOG(ERROR) << "Failed to open /proc/cpuinfo";
+ }
+ if (x86_64) {
+ return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
+ } else {
+ return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ }
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromHwcap(bool x86_64) {
+ UNIMPLEMENTED(WARNING);
+ return FromCppDefines(x86_64);
+}
+
+const X86InstructionSetFeatures* X86InstructionSetFeatures::FromAssembly(bool x86_64) {
+ UNIMPLEMENTED(WARNING);
+ return FromCppDefines(x86_64);
+}
+
+bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+ if (GetInstructionSet() != other->GetInstructionSet()) {
+ return false;
+ }
+ const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
+ return (IsSmp() == other->IsSmp()) &&
+ (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
+ (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
+ (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
+ (has_AVX_ == other_as_x86->has_AVX_) &&
+ (has_AVX2_ == other_as_x86->has_AVX2_);
+}
+
+uint32_t X86InstructionSetFeatures::AsBitmap() const {
+ return (IsSmp() ? kSmpBitfield : 0) |
+ (has_SSSE3_ ? kSsse3Bitfield : 0) |
+ (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
+ (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
+ (has_AVX_ ? kAvxBitfield : 0) |
+ (has_AVX2_ ? kAvx2Bitfield : 0);
+}
+
+std::string X86InstructionSetFeatures::GetFeatureString() const {
+ std::string result;
+ if (IsSmp()) {
+ result += "smp";
+ } else {
+ result += "-smp";
+ }
+ if (has_SSSE3_) {
+ result += ",ssse3";
+ } else {
+ result += ",-ssse3";
+ }
+ if (has_SSE4_1_) {
+ result += ",sse4.1";
+ } else {
+ result += ",-sse4.1";
+ }
+ if (has_SSE4_2_) {
+ result += ",sse4.2";
+ } else {
+ result += ",-sse4.2";
+ }
+ if (has_AVX_) {
+ result += ",avx";
+ } else {
+ result += ",-avx";
+ }
+ if (has_AVX2_) {
+ result += ",avx2";
+ } else {
+ result += ",-avx2";
+ }
+ return result;
+}
+
+const InstructionSetFeatures* X86InstructionSetFeatures::AddFeaturesFromSplitString(
+ const bool smp, const std::vector<std::string>& features, bool x86_64,
+ std::string* error_msg) const {
+ bool has_SSSE3 = has_SSSE3_;
+ bool has_SSE4_1 = has_SSE4_1_;
+ bool has_SSE4_2 = has_SSE4_2_;
+ bool has_AVX = has_AVX_;
+ bool has_AVX2 = has_AVX2_;
+ for (auto i = features.begin(); i != features.end(); i++) {
+ std::string feature = Trim(*i);
+ if (feature == "ssse3") {
+ has_SSSE3 = true;
+ } else if (feature == "-ssse3") {
+ has_SSSE3 = false;
+ } else if (feature == "sse4.1") {
+ has_SSE4_1 = true;
+ } else if (feature == "-sse4.1") {
+ has_SSE4_1 = false;
+ } else if (feature == "sse4.2") {
+ has_SSE4_2 = true;
+ } else if (feature == "-sse4.2") {
+ has_SSE4_2 = false;
+ } else if (feature == "avx") {
+ has_AVX = true;
+ } else if (feature == "-avx") {
+ has_AVX = false;
+ } else if (feature == "avx2") {
+ has_AVX2 = true;
+ } else if (feature == "-avx2") {
+ has_AVX2 = false;
+ } else {
+ *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+ return nullptr;
+ }
+ }
+ if (x86_64) {
+ return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ } else {
+ return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
+ has_AVX2);
+ }
+}
+
+} // namespace art
diff --git a/runtime/arch/x86/instruction_set_features_x86.h b/runtime/arch/x86/instruction_set_features_x86.h
new file mode 100644
index 0000000000..926fabbb9d
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+#define ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86 architecture.
+class X86InstructionSetFeatures : public InstructionSetFeatures {
+ public:
+ // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+ static const X86InstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg,
+ bool x86_64 = false);
+
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const X86InstructionSetFeatures* FromBitmap(uint32_t bitmap, bool x86_64 = false);
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const X86InstructionSetFeatures* FromCppDefines(bool x86_64 = false);
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const X86InstructionSetFeatures* FromCpuInfo(bool x86_64 = false);
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const X86InstructionSetFeatures* FromHwcap(bool x86_64 = false);
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const X86InstructionSetFeatures* FromAssembly(bool x86_64 = false);
+
+ bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+ virtual InstructionSet GetInstructionSet() const OVERRIDE {
+ return kX86;
+ }
+
+ uint32_t AsBitmap() const OVERRIDE;
+
+ std::string GetFeatureString() const OVERRIDE;
+
+ virtual ~X86InstructionSetFeatures() {}
+
+ protected:
+ // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+ virtual const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const OVERRIDE {
+ return AddFeaturesFromSplitString(smp, features, false, error_msg);
+ }
+
+ const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ bool x86_64, std::string* error_msg) const;
+
+ X86InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+ bool has_AVX, bool has_AVX2)
+ : InstructionSetFeatures(smp), has_SSSE3_(has_SSSE3), has_SSE4_1_(has_SSE4_1),
+ has_SSE4_2_(has_SSE4_2), has_AVX_(has_AVX), has_AVX2_(has_AVX2) {
+ }
+
+ private:
+ // Bitmap positions for encoding features as a bitmap.
+ enum {
+ kSmpBitfield = 1,
+ kSsse3Bitfield = 2,
+ kSse4_1Bitfield = 4,
+ kSse4_2Bitfield = 8,
+ kAvxBitfield = 16,
+ kAvx2Bitfield = 32,
+ };
+
+ const bool has_SSSE3_; // x86 128bit SIMD - Supplemental SSE.
+ const bool has_SSE4_1_; // x86 128bit SIMD SSE4.1.
+ const bool has_SSE4_2_; // x86 128bit SIMD SSE4.2.
+ const bool has_AVX_; // x86 256bit SIMD AVX.
+ const bool has_AVX2_; // x86 256bit SIMD AVX 2.0.
+
+ DISALLOW_COPY_AND_ASSIGN(X86InstructionSetFeatures);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_X86_INSTRUCTION_SET_FEATURES_X86_H_
diff --git a/runtime/arch/x86/instruction_set_features_x86_test.cc b/runtime/arch/x86/instruction_set_features_x86_test.cc
new file mode 100644
index 0000000000..d231beb40d
--- /dev/null
+++ b/runtime/arch/x86/instruction_set_features_x86_test.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_x86.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromDefaultVariant) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> x86_features(
+ InstructionSetFeatures::FromVariant(kX86, "default", &error_msg));
+ ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+ EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+ EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_features->AsBitmap(), 1U);
+}
+
+TEST(X86InstructionSetFeaturesTest, X86FeaturesFromAtomVariant) {
+ // Build features for a 32-bit x86 atom processor.
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> x86_features(
+ InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
+ ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
+ EXPECT_TRUE(x86_features->Equals(x86_features.get()));
+ EXPECT_STREQ("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2", x86_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_features->AsBitmap(), 3U);
+
+ // Build features for a 32-bit x86 default processor.
+ std::unique_ptr<const InstructionSetFeatures> x86_default_features(
+ InstructionSetFeatures::FromVariant(kX86, "default", &error_msg));
+ ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
+ EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
+ EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+ x86_default_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_default_features->AsBitmap(), 1U);
+
+ // Build features for a 64-bit x86-64 atom processor.
+ std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+ InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
+ ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+ EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+ EXPECT_STREQ("smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+ x86_64_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_64_features->AsBitmap(), 3U);
+
+ EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
+ EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
+ EXPECT_FALSE(x86_features->Equals(x86_default_features.get()));
+}
+
+} // namespace art
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64.h b/runtime/arch/x86_64/instruction_set_features_x86_64.h
new file mode 100644
index 0000000000..328017716e
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+#define ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
+
+#include "arch/x86/instruction_set_features_x86.h"
+
+namespace art {
+
+// Instruction set features relevant to the X86_64 architecture.
+class X86_64InstructionSetFeatures FINAL : public X86InstructionSetFeatures {
+ public:
+ // Process a CPU variant string like "atom" or "nehalem" and create InstructionSetFeatures.
+ static const X86_64InstructionSetFeatures* FromVariant(const std::string& variant,
+ std::string* error_msg) {
+ return X86InstructionSetFeatures::FromVariant(variant, error_msg, true)
+ ->AsX86_64InstructionSetFeatures();
+ }
+
+ // Parse a bitmap and create an InstructionSetFeatures.
+ static const X86_64InstructionSetFeatures* FromBitmap(uint32_t bitmap) {
+ return X86InstructionSetFeatures::FromBitmap(bitmap, true)->AsX86_64InstructionSetFeatures();
+ }
+
+ // Turn C pre-processor #defines into the equivalent instruction set features.
+ static const X86_64InstructionSetFeatures* FromCppDefines() {
+ return X86InstructionSetFeatures::FromCppDefines(true)->AsX86_64InstructionSetFeatures();
+ }
+
+ // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+ static const X86_64InstructionSetFeatures* FromCpuInfo() {
+ return X86InstructionSetFeatures::FromCpuInfo(true)->AsX86_64InstructionSetFeatures();
+ }
+
+ // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+ // InstructionSetFeatures.
+ static const X86_64InstructionSetFeatures* FromHwcap() {
+ return X86InstructionSetFeatures::FromHwcap(true)->AsX86_64InstructionSetFeatures();
+ }
+
+ // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+ // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+ static const X86_64InstructionSetFeatures* FromAssembly() {
+ return X86InstructionSetFeatures::FromAssembly(true)->AsX86_64InstructionSetFeatures();
+ }
+
+ InstructionSet GetInstructionSet() const OVERRIDE {
+ return kX86_64;
+ }
+
+ virtual ~X86_64InstructionSetFeatures() {}
+
+ protected:
+ // Parse a string of the form "ssse3" adding these to a new InstructionSetFeatures.
+ const InstructionSetFeatures*
+ AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+ std::string* error_msg) const OVERRIDE {
+ return X86InstructionSetFeatures::AddFeaturesFromSplitString(smp, features, true, error_msg);
+ }
+
+ private:
+ X86_64InstructionSetFeatures(bool smp, bool has_SSSE3, bool has_SSE4_1, bool has_SSE4_2,
+ bool has_AVX, bool has_AVX2)
+ : X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2) {
+ }
+
+ friend class X86InstructionSetFeatures;
+
+ DISALLOW_COPY_AND_ASSIGN(X86_64InstructionSetFeatures);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ARCH_X86_64_INSTRUCTION_SET_FEATURES_X86_64_H_
diff --git a/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
new file mode 100644
index 0000000000..5171080912
--- /dev/null
+++ b/runtime/arch/x86_64/instruction_set_features_x86_64_test.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_set_features_x86_64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(X86_64InstructionSetFeaturesTest, X86Features) {
+ std::string error_msg;
+ std::unique_ptr<const InstructionSetFeatures> x86_64_features(
+ InstructionSetFeatures::FromVariant(kX86_64, "default", &error_msg));
+ ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
+ EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
+ EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
+ EXPECT_STREQ("smp,-ssse3,-sse4.1,-sse4.2,-avx,-avx2",
+ x86_64_features->GetFeatureString().c_str());
+ EXPECT_EQ(x86_64_features->AsBitmap(), 1U);
+}
+
+} // namespace art
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index b6cf921f2c..37c5f9c975 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include "arch/instruction_set.h"
#include "base/logging.h"
#include "base/stringprintf.h"
#include "base/stl_util.h"
@@ -29,7 +30,6 @@
#include "elf_utils.h"
#include "leb128.h"
#include "utils.h"
-#include "instruction_set.h"
namespace art {
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 49357ad276..9ffd199786 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -17,8 +17,8 @@
#ifndef ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
#define ART_RUNTIME_ENTRYPOINTS_QUICK_CALLEE_SAVE_FRAME_H_
+#include "arch/instruction_set.h"
#include "base/mutex.h"
-#include "instruction_set.h"
#include "runtime.h"
#include "thread-inl.h"
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index f78273f24c..00f5cd5eb1 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -16,7 +16,6 @@
#include "callee_save_frame.h"
#include "entrypoints/runtime_asm_entrypoints.h"
-#include "instruction_set.h"
#include "instrumentation.h"
#include "mirror/art_method-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 4f61707040..c4bc969038 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -21,7 +21,6 @@
#include "entrypoints/entrypoint_utils-inl.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
-#include "instruction_set.h"
#include "interpreter/interpreter.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index cf7352e75c..69a573ef98 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -22,6 +22,7 @@
#include <vector>
#include "allocator_type.h"
+#include "arch/instruction_set.h"
#include "atomic.h"
#include "base/timing_logger.h"
#include "gc/accounting/atomic_stack.h"
@@ -32,7 +33,6 @@
#include "gc/collector_type.h"
#include "gc/space/large_object_space.h"
#include "globals.h"
-#include "instruction_set.h"
#include "jni.h"
#include "object_callbacks.h"
#include "offsets.h"
diff --git a/runtime/instruction_set.cc b/runtime/instruction_set.cc
deleted file mode 100644
index e165a75659..0000000000
--- a/runtime/instruction_set.cc
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "instruction_set.h"
-
-#include <signal.h>
-#include <fstream>
-
-#include "base/casts.h"
-#include "base/stringprintf.h"
-#include "utils.h"
-
-namespace art {
-
-const char* GetInstructionSetString(const InstructionSet isa) {
- switch (isa) {
- case kArm:
- case kThumb2:
- return "arm";
- case kArm64:
- return "arm64";
- case kX86:
- return "x86";
- case kX86_64:
- return "x86_64";
- case kMips:
- return "mips";
- case kNone:
- return "none";
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- UNREACHABLE();
- }
-}
-
-InstructionSet GetInstructionSetFromString(const char* isa_str) {
- CHECK(isa_str != nullptr);
-
- if (strcmp("arm", isa_str) == 0) {
- return kArm;
- } else if (strcmp("arm64", isa_str) == 0) {
- return kArm64;
- } else if (strcmp("x86", isa_str) == 0) {
- return kX86;
- } else if (strcmp("x86_64", isa_str) == 0) {
- return kX86_64;
- } else if (strcmp("mips", isa_str) == 0) {
- return kMips;
- }
-
- return kNone;
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa) {
- switch (isa) {
- case kArm:
- // Fall-through.
- case kThumb2:
- return kArmAlignment;
- case kArm64:
- return kArm64Alignment;
- case kX86:
- // Fall-through.
- case kX86_64:
- return kX86Alignment;
- case kMips:
- return kMipsAlignment;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have alignment.";
- return 0;
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
- }
-}
-
-
-static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
-static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
-
-static constexpr size_t kArmStackOverflowReservedBytes = 8 * KB;
-static constexpr size_t kArm64StackOverflowReservedBytes = 8 * KB;
-static constexpr size_t kX86StackOverflowReservedBytes = 8 * KB;
-static constexpr size_t kX86_64StackOverflowReservedBytes = 8 * KB;
-
-size_t GetStackOverflowReservedBytes(InstructionSet isa) {
- switch (isa) {
- case kArm: // Intentional fall-through.
- case kThumb2:
- return kArmStackOverflowReservedBytes;
-
- case kArm64:
- return kArm64StackOverflowReservedBytes;
-
- case kMips:
- return kMipsStackOverflowReservedBytes;
-
- case kX86:
- return kX86StackOverflowReservedBytes;
-
- case kX86_64:
- return kX86_64StackOverflowReservedBytes;
-
- case kNone:
- LOG(FATAL) << "kNone has no stack overflow size";
- return 0;
-
- default:
- LOG(FATAL) << "Unknown instruction set" << isa;
- return 0;
- }
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
- const std::string& variant,
- std::string* error_msg) {
- const InstructionSetFeatures* result;
- switch (isa) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(isa);
- break;
- }
- CHECK_EQ(result == nullptr, error_msg->size() != 0);
- return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromFeatureString(InstructionSet isa,
- const std::string& feature_list,
- std::string* error_msg) {
- const InstructionSetFeatures* result;
- switch (isa) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromFeatureString(feature_list, error_msg);
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(isa);
- break;
- }
- // TODO: warn if feature_list doesn't agree with result's GetFeatureList().
- CHECK_EQ(result == nullptr, error_msg->size() != 0);
- return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
- uint32_t bitmap) {
- const InstructionSetFeatures* result;
- switch (isa) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromBitmap(bitmap);
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(isa);
- break;
- }
- CHECK_EQ(bitmap, result->AsBitmap());
- return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
- const InstructionSetFeatures* result;
- switch (kRuntimeISA) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromCppDefines();
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
- break;
- }
- return result;
-}
-
-
-const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
- const InstructionSetFeatures* result;
- switch (kRuntimeISA) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromCpuInfo();
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
- break;
- }
- return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
- const InstructionSetFeatures* result;
- switch (kRuntimeISA) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromHwcap();
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
- break;
- }
- return result;
-}
-
-const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
- const InstructionSetFeatures* result;
- switch (kRuntimeISA) {
- case kArm:
- case kThumb2:
- result = ArmInstructionSetFeatures::FromAssembly();
- break;
- default:
- result = UnknownInstructionSetFeatures::Unknown(kRuntimeISA);
- break;
- }
- return result;
-}
-
-const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
- DCHECK_EQ(kArm, GetInstructionSet());
- return down_cast<const ArmInstructionSetFeatures*>(this);
-}
-
-std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
- os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
- return os;
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromFeatureString(
- const std::string& feature_list, std::string* error_msg) {
- std::vector<std::string> features;
- Split(feature_list, ',', &features);
- bool has_lpae = false;
- bool has_div = false;
- for (auto i = features.begin(); i != features.end(); i++) {
- std::string feature = Trim(*i);
- if (feature == "default" || feature == "none") {
- // Nothing to do.
- } else if (feature == "div") {
- has_div = true;
- } else if (feature == "nodiv") {
- has_div = false;
- } else if (feature == "lpae") {
- has_lpae = true;
- } else if (feature == "nolpae") {
- has_lpae = false;
- } else {
- *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
- return nullptr;
- }
- }
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromVariant(
- const std::string& variant, std::string* error_msg) {
- // Look for variants that have divide support.
- bool has_div = false;
- {
- static const char* arm_variants_with_div[] = {
- "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", "cortex-a53", "cortex-a57",
- "cortex-m3", "cortex-m4", "cortex-r4", "cortex-r5",
- "cyclone", "denver", "krait", "swift"
- };
- for (const char* div_variant : arm_variants_with_div) {
- if (variant == div_variant) {
- has_div = true;
- break;
- }
- }
- }
- // Look for variants that have LPAE support.
- bool has_lpae = false;
- {
- static const char* arm_variants_with_lpae[] = {
- "cortex-a7", "cortex-a15", "krait", "denver"
- };
- for (const char* lpae_variant : arm_variants_with_lpae) {
- if (variant == lpae_variant) {
- has_lpae = true;
- break;
- }
- }
- }
- if (has_div == false && has_lpae == false) {
- // Avoid unsupported variants.
- static const char* unsupported_arm_variants[] = {
- // ARM processors that aren't ARMv7 compatible aren't supported.
- "arm2", "arm250", "arm3", "arm6", "arm60", "arm600", "arm610", "arm620",
- "cortex-m0", "cortex-m0plus", "cortex-m1",
- "fa526", "fa626", "fa606te", "fa626te", "fmp626", "fa726te",
- "iwmmxt", "iwmmxt2",
- "strongarm", "strongarm110", "strongarm1100", "strongarm1110",
- "xscale"
- };
- for (const char* us_variant : unsupported_arm_variants) {
- if (variant == us_variant) {
- *error_msg = StringPrintf("Attempt to use unsupported ARM variant: %s", us_variant);
- return nullptr;
- }
- }
- // Warn if the variant is unknown.
- // TODO: some of the variants below may have feature support, but that support is currently
- // unknown so we'll choose conservative (sub-optimal) defaults without warning.
- // TODO: some of the architectures may not support all features required by ART and should be
- // moved to unsupported_arm_variants[] above.
- static const char* arm_variants_without_known_features[] = {
- "arm7", "arm7m", "arm7d", "arm7dm", "arm7di", "arm7dmi", "arm70", "arm700", "arm700i",
- "arm710", "arm710c", "arm7100", "arm720", "arm7500", "arm7500fe", "arm7tdmi", "arm7tdmi-s",
- "arm710t", "arm720t", "arm740t",
- "arm8", "arm810",
- "arm9", "arm9e", "arm920", "arm920t", "arm922t", "arm946e-s", "arm966e-s", "arm968e-s",
- "arm926ej-s", "arm940t", "arm9tdmi",
- "arm10tdmi", "arm1020t", "arm1026ej-s", "arm10e", "arm1020e", "arm1022e",
- "arm1136j-s", "arm1136jf-s",
- "arm1156t2-s", "arm1156t2f-s", "arm1176jz-s", "arm1176jzf-s",
- "cortex-a5", "cortex-a8", "cortex-a9", "cortex-a9-mp", "cortex-r4f",
- "marvell-pj4", "mpcore", "mpcorenovfp"
- };
- bool found = false;
- for (const char* ff_variant : arm_variants_without_known_features) {
- if (variant == ff_variant) {
- found = true;
- break;
- }
- }
- if (!found) {
- LOG(WARNING) << "Unknown instruction set features for ARM CPU variant (" << variant
- << ") using conservative defaults";
- }
- }
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) {
- bool has_lpae = (bitmap & kLpaeBitfield) != 0;
- bool has_div = (bitmap & kDivBitfield) != 0;
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCppDefines() {
-#if defined(__ARM_ARCH_EXT_IDIV__)
- bool has_div = true;
-#else
- bool has_div = false;
-#endif
-#if defined(__ARM_FEATURE_LPAE)
- bool has_lpae = true;
-#else
- bool has_lpae = false;
-#endif
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromCpuInfo() {
- // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
- // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
- bool has_lpae = false;
- bool has_div = false;
-
- std::ifstream in("/proc/cpuinfo");
- if (!in.fail()) {
- while (!in.eof()) {
- std::string line;
- std::getline(in, line);
- if (!in.eof()) {
- LOG(INFO) << "cpuinfo line: " << line;
- if (line.find("Features") != std::string::npos) {
- LOG(INFO) << "found features";
- if (line.find("idivt") != std::string::npos) {
- // We always expect both ARM and Thumb divide instructions to be available or not
- // available.
- CHECK_NE(line.find("idiva"), std::string::npos);
- has_div = true;
- }
- if (line.find("lpae") != std::string::npos) {
- has_lpae = true;
- }
- }
- }
- }
- in.close();
- } else {
- LOG(INFO) << "Failed to open /proc/cpuinfo";
- }
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-#if defined(HAVE_ANDROID_OS) && defined(__arm__)
-#include <sys/auxv.h>
-#include <asm/hwcap.h>
-#endif
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromHwcap() {
- bool has_lpae = false;
- bool has_div = false;
-
-#if defined(HAVE_ANDROID_OS) && defined(__arm__)
- uint64_t hwcaps = getauxval(AT_HWCAP);
- LOG(INFO) << "hwcaps=" << hwcaps;
- if ((hwcaps & HWCAP_IDIVT) != 0) {
- // We always expect both ARM and Thumb divide instructions to be available or not
- // available.
- CHECK_NE(hwcaps & HWCAP_IDIVA, 0U);
- has_div = true;
- }
- if ((hwcaps & HWCAP_LPAE) != 0) {
- has_lpae = true;
- }
-#endif
-
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-// A signal handler called by a fault for an illegal instruction. We record the fact in r0
-// and then increment the PC in the signal context to return to the next instruction. We know the
-// instruction is an sdiv (4 bytes long).
-static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED,
- void* data) {
-#if defined(__arm__)
- struct ucontext *uc = (struct ucontext *)data;
- struct sigcontext *sc = &uc->uc_mcontext;
- sc->arm_r0 = 0; // Set R0 to #0 to signal error.
- sc->arm_pc += 4; // Skip offending instruction.
-#else
- UNUSED(data);
-#endif
-}
-
-#if defined(__arm__)
-extern "C" bool artCheckForARMSDIVInstruction();
-#endif
-
-const ArmInstructionSetFeatures* ArmInstructionSetFeatures::FromAssembly() {
- // See if have a sdiv instruction. Register a signal handler and try to execute an sdiv
- // instruction. If we get a SIGILL then it's not supported.
- struct sigaction sa, osa;
- sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
- sa.sa_sigaction = bad_divide_inst_handle;
- sigaction(SIGILL, &sa, &osa);
-
- bool has_div = false;
-#if defined(__arm__)
- if (artCheckForARMSDIVInstruction()) {
- has_div = true;
- }
-#endif
-
- // Restore the signal handler.
- sigaction(SIGILL, &osa, nullptr);
-
- // Use compile time features to "detect" LPAE support.
- // TODO: write an assembly LPAE support test.
-#if defined(__ARM_FEATURE_LPAE)
- bool has_lpae = true;
-#else
- bool has_lpae = false;
-#endif
- return new ArmInstructionSetFeatures(has_lpae, has_div);
-}
-
-
-bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
- if (kArm != other->GetInstructionSet()) {
- return false;
- }
- const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures();
- return has_lpae_ == other_as_arm->has_lpae_ && has_div_ == other_as_arm->has_div_;
-}
-
-uint32_t ArmInstructionSetFeatures::AsBitmap() const {
- return (has_lpae_ ? kLpaeBitfield : 0) | (has_div_ ? kDivBitfield : 0);
-}
-
-std::string ArmInstructionSetFeatures::GetFeatureString() const {
- std::string result;
- if (has_div_) {
- result += ",div";
- }
- if (has_lpae_) {
- result += ",lpae";
- }
- if (result.size() == 0) {
- return "none";
- } else {
- // Strip leading comma.
- return result.substr(1, result.size());
- }
-}
-
-} // namespace art
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
deleted file mode 100644
index 3f2d16bd2c..0000000000
--- a/runtime/instruction_set_test.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "instruction_set.h"
-
-#include "base/stringprintf.h"
-#include "common_runtime_test.h"
-
-namespace art {
-
-class InstructionSetTest : public CommonRuntimeTest {};
-
-TEST_F(InstructionSetTest, GetInstructionSetFromString) {
- EXPECT_EQ(kArm, GetInstructionSetFromString("arm"));
- EXPECT_EQ(kArm64, GetInstructionSetFromString("arm64"));
- EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
- EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
- EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
- EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
- EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
-}
-
-TEST_F(InstructionSetTest, GetInstructionSetString) {
- EXPECT_STREQ("arm", GetInstructionSetString(kArm));
- EXPECT_STREQ("arm", GetInstructionSetString(kThumb2));
- EXPECT_STREQ("arm64", GetInstructionSetString(kArm64));
- EXPECT_STREQ("x86", GetInstructionSetString(kX86));
- EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
- EXPECT_STREQ("mips", GetInstructionSetString(kMips));
- EXPECT_STREQ("none", GetInstructionSetString(kNone));
-}
-
-TEST_F(InstructionSetTest, TestRoundTrip) {
- EXPECT_EQ(kRuntimeISA, GetInstructionSetFromString(GetInstructionSetString(kRuntimeISA)));
-}
-
-TEST_F(InstructionSetTest, PointerSize) {
- EXPECT_EQ(sizeof(void*), GetInstructionSetPointerSize(kRuntimeISA));
-}
-
-TEST_F(InstructionSetTest, X86Features) {
- // Build features for a 32-bit x86 atom processor.
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> x86_features(
- InstructionSetFeatures::FromVariant(kX86, "atom", &error_msg));
- ASSERT_TRUE(x86_features.get() != nullptr) << error_msg;
- EXPECT_EQ(x86_features->GetInstructionSet(), kX86);
- EXPECT_TRUE(x86_features->Equals(x86_features.get()));
- EXPECT_STREQ("none", x86_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_features->AsBitmap(), 0U);
-
- // Build features for a 32-bit x86 default processor.
- std::unique_ptr<const InstructionSetFeatures> x86_default_features(
- InstructionSetFeatures::FromFeatureString(kX86, "default", &error_msg));
- ASSERT_TRUE(x86_default_features.get() != nullptr) << error_msg;
- EXPECT_EQ(x86_default_features->GetInstructionSet(), kX86);
- EXPECT_TRUE(x86_default_features->Equals(x86_default_features.get()));
- EXPECT_STREQ("none", x86_default_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_default_features->AsBitmap(), 0U);
-
- // Build features for a 64-bit x86-64 atom processor.
- std::unique_ptr<const InstructionSetFeatures> x86_64_features(
- InstructionSetFeatures::FromVariant(kX86_64, "atom", &error_msg));
- ASSERT_TRUE(x86_64_features.get() != nullptr) << error_msg;
- EXPECT_EQ(x86_64_features->GetInstructionSet(), kX86_64);
- EXPECT_TRUE(x86_64_features->Equals(x86_64_features.get()));
- EXPECT_STREQ("none", x86_64_features->GetFeatureString().c_str());
- EXPECT_EQ(x86_64_features->AsBitmap(), 0U);
-
- EXPECT_FALSE(x86_64_features->Equals(x86_features.get()));
- EXPECT_FALSE(x86_64_features->Equals(x86_default_features.get()));
- EXPECT_TRUE(x86_features->Equals(x86_default_features.get()));
-}
-
-TEST_F(InstructionSetTest, ArmFeaturesFromVariant) {
- // Build features for a 32-bit ARM krait processor.
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> krait_features(
- InstructionSetFeatures::FromVariant(kArm, "krait", &error_msg));
- ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
-
- ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
- EXPECT_TRUE(krait_features->Equals(krait_features.get()));
- EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
- EXPECT_EQ(krait_features->AsBitmap(), 3U);
-
- // Build features for a 32-bit ARM denver processor.
- std::unique_ptr<const InstructionSetFeatures> denver_features(
- InstructionSetFeatures::FromVariant(kArm, "denver", &error_msg));
- ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(denver_features->Equals(denver_features.get()));
- EXPECT_TRUE(denver_features->Equals(krait_features.get()));
- EXPECT_TRUE(krait_features->Equals(denver_features.get()));
- EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
- EXPECT_EQ(denver_features->AsBitmap(), 3U);
-
- // Build features for a 32-bit ARMv7 processor.
- std::unique_ptr<const InstructionSetFeatures> arm7_features(
- InstructionSetFeatures::FromVariant(kArm, "arm7", &error_msg));
- ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
- EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
- EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
- EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
- EXPECT_EQ(arm7_features->AsBitmap(), 0U);
-
- // ARM6 is not a supported architecture variant.
- std::unique_ptr<const InstructionSetFeatures> arm6_features(
- InstructionSetFeatures::FromVariant(kArm, "arm6", &error_msg));
- EXPECT_TRUE(arm6_features.get() == nullptr);
- EXPECT_NE(error_msg.size(), 0U);
-}
-
-TEST_F(InstructionSetTest, ArmFeaturesFromString) {
- // Build features for a 32-bit ARM with LPAE and div processor.
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> krait_features(
- InstructionSetFeatures::FromFeatureString(kArm, "lpae,div", &error_msg));
- ASSERT_TRUE(krait_features.get() != nullptr) << error_msg;
-
- ASSERT_EQ(krait_features->GetInstructionSet(), kArm);
- EXPECT_TRUE(krait_features->Equals(krait_features.get()));
- EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("div,lpae", krait_features->GetFeatureString().c_str());
- EXPECT_EQ(krait_features->AsBitmap(), 3U);
-
- // Build features for a 32-bit ARM processor with LPAE and div flipped.
- std::unique_ptr<const InstructionSetFeatures> denver_features(
- InstructionSetFeatures::FromFeatureString(kArm, "div,lpae", &error_msg));
- ASSERT_TRUE(denver_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(denver_features->Equals(denver_features.get()));
- EXPECT_TRUE(denver_features->Equals(krait_features.get()));
- EXPECT_TRUE(krait_features->Equals(denver_features.get()));
- EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("div,lpae", denver_features->GetFeatureString().c_str());
- EXPECT_EQ(denver_features->AsBitmap(), 3U);
-
- // Build features for a 32-bit default ARM processor.
- std::unique_ptr<const InstructionSetFeatures> arm7_features(
- InstructionSetFeatures::FromFeatureString(kArm, "default", &error_msg));
- ASSERT_TRUE(arm7_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(arm7_features->Equals(arm7_features.get()));
- EXPECT_FALSE(arm7_features->Equals(krait_features.get()));
- EXPECT_FALSE(krait_features->Equals(arm7_features.get()));
- EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasDivideInstruction());
- EXPECT_FALSE(arm7_features->AsArmInstructionSetFeatures()->HasLpae());
- EXPECT_STREQ("none", arm7_features->GetFeatureString().c_str());
- EXPECT_EQ(arm7_features->AsBitmap(), 0U);
-}
-
-#ifdef HAVE_ANDROID_OS
-#include "cutils/properties.h"
-
-TEST_F(InstructionSetTest, FeaturesFromSystemPropertyVariant) {
- // Take the default set of instruction features from the build.
- std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
- InstructionSetFeatures::FromCppDefines());
-
- // Read the features property.
- std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
- char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
- if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
- // Use features from property to build InstructionSetFeatures and check against build's
- // features.
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> property_features(
- InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
- ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
- << "System property features: " << *property_features.get()
- << "\nFeatures from build: " << *instruction_set_features.get();
- }
-}
-
-TEST_F(InstructionSetTest, FeaturesFromSystemPropertyString) {
- // Take the default set of instruction features from the build.
- std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
- InstructionSetFeatures::FromCppDefines());
-
- // Read the features property.
- std::string key = StringPrintf("dalvik.vm.isa.%s.features", GetInstructionSetString(kRuntimeISA));
- char dex2oat_isa_features[PROPERTY_VALUE_MAX];
- if (property_get(key.c_str(), dex2oat_isa_features, nullptr) > 0) {
- // Use features from property to build InstructionSetFeatures and check against build's
- // features.
- std::string error_msg;
- std::unique_ptr<const InstructionSetFeatures> property_features(
- InstructionSetFeatures::FromFeatureString(kRuntimeISA, dex2oat_isa_features, &error_msg));
- ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
-
- EXPECT_TRUE(property_features->Equals(instruction_set_features.get()))
- << "System property features: " << *property_features.get()
- << "\nFeatures from build: " << *instruction_set_features.get();
- }
-}
-#endif
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromCpuInfo) {
- LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromCpuInfo) {
-#endif
- // Take the default set of instruction features from the build.
- std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
- InstructionSetFeatures::FromCppDefines());
-
- // Check we get the same instruction set features using /proc/cpuinfo.
- std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
- InstructionSetFeatures::FromCpuInfo());
- EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get()))
- << "CPU Info features: " << *cpuinfo_features.get()
- << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromHwcap) {
- LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromHwcap) {
-#endif
- // Take the default set of instruction features from the build.
- std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
- InstructionSetFeatures::FromCppDefines());
-
- // Check we get the same instruction set features using AT_HWCAP.
- std::unique_ptr<const InstructionSetFeatures> hwcap_features(
- InstructionSetFeatures::FromHwcap());
- EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get()))
- << "Hwcap features: " << *hwcap_features.get()
- << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-
-#if defined(__arm__)
-TEST_F(InstructionSetTest, DISABLED_FeaturesFromAssembly) {
- LOG(WARNING) << "Test disabled due to buggy ARM kernels";
-#else
-TEST_F(InstructionSetTest, FeaturesFromAssembly) {
-#endif
- // Take the default set of instruction features from the build.
- std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
- InstructionSetFeatures::FromCppDefines());
-
- // Check we get the same instruction set features using assembly tests.
- std::unique_ptr<const InstructionSetFeatures> assembly_features(
- InstructionSetFeatures::FromAssembly());
- EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get()))
- << "Assembly features: " << *assembly_features.get()
- << "\nFeatures from build: " << *instruction_set_features.get();
-}
-
-} // namespace art
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index 646c7ae9c5..369039d39f 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -21,8 +21,8 @@
#include <list>
#include <map>
+#include "arch/instruction_set.h"
#include "atomic.h"
-#include "instruction_set.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "gc_root.h"
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index f6e2b218fc..d40d64b437 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -17,8 +17,14 @@
#include "dalvik_system_VMRuntime.h"
#include <limits.h>
+#include <ScopedUtfChars.h>
-#include "ScopedUtfChars.h"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include "toStringArray.h"
+#pragma GCC diagnostic pop
+
+#include "arch/instruction_set.h"
#include "class_linker-inl.h"
#include "common_throws.h"
#include "debugger.h"
@@ -28,7 +34,6 @@
#include "gc/heap.h"
#include "gc/space/dlmalloc_space.h"
#include "gc/space/image_space.h"
-#include "instruction_set.h"
#include "intern_table.h"
#include "jni_internal.h"
#include "mirror/art_method-inl.h"
@@ -41,11 +46,6 @@
#include "thread.h"
#include "thread_list.h"
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#include "toStringArray.h"
-#pragma GCC diagnostic pop
-
namespace art {
static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 09669543a8..f1a04cb35d 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -18,8 +18,8 @@
#include <stdlib.h>
+#include "arch/instruction_set.h"
#include "debugger.h"
-#include "instruction_set.h"
#include "java_vm_ext.h"
#include "jni_internal.h"
#include "JNIHelp.h"
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 0749c06551..02c60abb59 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -15,11 +15,13 @@
*/
#include "oat.h"
-#include "utils.h"
#include <string.h>
#include <zlib.h>
+#include "arch/instruction_set_features.h"
+#include "utils.h"
+
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
diff --git a/runtime/oat.h b/runtime/oat.h
index f577b077bf..8fb02b8882 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -19,14 +19,16 @@
#include <vector>
+#include "arch/instruction_set.h"
#include "base/macros.h"
#include "dex_file.h"
-#include "instruction_set.h"
#include "quick/quick_method_frame_info.h"
#include "safe_map.h"
namespace art {
+class InstructionSetFeatures;
+
class PACKED(4) OatHeader {
public:
static const uint8_t kOatMagic[4];
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 26a2f31b13..9294868349 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -25,7 +25,7 @@
#include "globals.h"
#include "gc/collector_type.h"
#include "gc/space/large_object_space.h"
-#include "instruction_set.h"
+#include "arch/instruction_set.h"
#include "profiler_options.h"
namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d338ad7c38..78c6542827 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -37,6 +37,7 @@
#include "arch/arm/registers_arm.h"
#include "arch/arm64/quick_method_frame_info_arm64.h"
#include "arch/arm64/registers_arm64.h"
+#include "arch/instruction_set_features.h"
#include "arch/mips/quick_method_frame_info_mips.h"
#include "arch/mips/registers_mips.h"
#include "arch/x86/quick_method_frame_info_x86.h"
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3cbe1e5eb5..39fd910893 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -26,11 +26,11 @@
#include <utility>
#include <vector>
+#include "arch/instruction_set.h"
#include "base/allocator.h"
#include "compiler_callbacks.h"
#include "gc_root.h"
#include "instrumentation.h"
-#include "instruction_set.h"
#include "jobject_comparator.h"
#include "object_callbacks.h"
#include "offsets.h"
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index d4ec80372d..d448460dc3 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -27,10 +27,10 @@
#include <sstream>
+#include "arch/instruction_set.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "gc/heap.h"
-#include "instruction_set.h"
#include "os.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
diff --git a/runtime/stack.h b/runtime/stack.h
index 66c840d7c3..1d772e6ae2 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -20,8 +20,8 @@
#include <stdint.h>
#include <string>
+#include "arch/instruction_set.h"
#include "dex_file.h"
-#include "instruction_set.h"
#include "mirror/object_reference.h"
#include "throw_location.h"
#include "utils.h"
diff --git a/runtime/thread.h b/runtime/thread.h
index 7e567fb77c..b69d2f4a83 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -25,6 +25,7 @@
#include <setjmp.h>
#include <string>
+#include "arch/instruction_set.h"
#include "atomic.h"
#include "base/macros.h"
#include "base/mutex.h"
@@ -34,7 +35,6 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "globals.h"
#include "handle_scope.h"
-#include "instruction_set.h"
#include "jvalue.h"
#include "object_callbacks.h"
#include "offsets.h"
diff --git a/runtime/utils.h b/runtime/utils.h
index 669fe6cd06..891b47b7a7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -24,10 +24,10 @@
#include <string>
#include <vector>
+#include "arch/instruction_set.h"
#include "base/logging.h"
#include "base/mutex.h"
#include "globals.h"
-#include "instruction_set.h"
#include "primitive.h"
namespace art {