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
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a8041c5..991aaca 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -70,8 +70,15 @@
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/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 9fe3807..e8b363b 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 @@
$$(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 @@
$$(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 085d169..97387a1 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 0361cd1..7f76eef 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 0d5aa90..0c7812b 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* 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* 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 7674e46..98ddc36 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 ca71c30..0d1d9bf 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 01784e2..ed73ef0 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 0a7aa99..495d85e 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 d58ddb0..fb47238 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 3615916..3df8f2e 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -214,44 +214,43 @@
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_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 4a340ec..185112d 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 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 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 @@
* 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 @@
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 @@
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 @@
// 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 a7dc84f..18f1cde 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 @@
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 bacc6d2..13ebc1e 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 ddb2342..437a1a9 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 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 7f30565..273b62d 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 c384c57..ce4ed6d 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 @@
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 @@
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 ac4fc67..63bf96c 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 9752b1d..fee3ea6 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 @@
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 ad7e98d..67711e3 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 e762f7d..c348f2c 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 @@
// 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 47b492a..2d2a82e 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 @@
}
} else if (option.starts_with("--instruction-set-features=")) {
StringPiece str = option.substr(strlen("--instruction-set-features=")).data();
- instruction_set_features_.reset(
- InstructionSetFeatures::FromFeatureString(instruction_set_, str.as_string(),
- &error_msg));
if (instruction_set_features_.get() == nullptr) {
- Usage("%s", error_msg.c_str());
+ 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(
+ instruction_set_features_->AddFeaturesFromString(str.as_string(), &error_msg));
+ if (instruction_set_features_.get() == nullptr) {
+ 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 @@
// 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 487f433..9cd631c 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 f1f1a56..d6309f7 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 75160ca..6b6d11e 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 0ceef64..5a3545b 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 082e8dd..8ced4d9 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -73,7 +73,6 @@
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 += \
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_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_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 @@
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 480190a..325b283 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 0000000..f49c037
--- /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 0000000..221bf1f
--- /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 0000000..44b1640
--- /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
similarity index 94%
rename from runtime/arch/arm/instruction_set_features_arm.S
rename to runtime/arch/arm/instruction_set_features_assembly_tests.S
index c26f2cd..c1086df 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 @@
// 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 0000000..18536ed
--- /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 0000000..ee41536
--- /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 0000000..027e59c
--- /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 0000000..92fa727
--- /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/arch/instruction_set.h b/runtime/arch/instruction_set.h
new file mode 100644
index 0000000..46622eb
--- /dev/null
+++ b/runtime/arch/instruction_set.h
@@ -0,0 +1,243 @@
+/*
+ * 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_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.
+
+namespace art {
+
+enum InstructionSet {
+ kNone,
+ kArm,
+ kArm64,
+ kThumb2,
+ kX86,
+ kX86_64,
+ kMips,
+ kMips64
+};
+std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
+
+#if defined(__arm__)
+static constexpr InstructionSet kRuntimeISA = kArm;
+#elif defined(__aarch64__)
+static constexpr InstructionSet kRuntimeISA = kArm64;
+#elif defined(__mips__)
+static constexpr InstructionSet kRuntimeISA = kMips;
+#elif defined(__i386__)
+static constexpr InstructionSet kRuntimeISA = kX86;
+#elif defined(__x86_64__)
+static constexpr InstructionSet kRuntimeISA = kX86_64;
+#else
+static constexpr InstructionSet kRuntimeISA = kNone;
+#endif
+
+// Architecture-specific pointer sizes
+static constexpr size_t kArmPointerSize = 4;
+static constexpr size_t kArm64PointerSize = 8;
+static constexpr size_t kMipsPointerSize = 4;
+static constexpr size_t kMips64PointerSize = 8;
+static constexpr size_t kX86PointerSize = 4;
+static constexpr size_t kX86_64PointerSize = 8;
+
+// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
+// but ARM ELF requires 8..
+static constexpr size_t kArmAlignment = 8;
+
+// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kArm64Alignment = 16;
+
+// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned.
+// TODO: Can this be 4?
+static constexpr size_t kMipsAlignment = 8;
+
+// X86 instruction alignment. This is the recommended alignment for maximum performance.
+static constexpr size_t kX86Alignment = 16;
+
+
+const char* GetInstructionSetString(InstructionSet isa);
+
+// Note: Returns kNone when the string cannot be parsed to a known value.
+InstructionSet GetInstructionSetFromString(const char* instruction_set);
+
+static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ // Fall-through.
+ case kThumb2:
+ return kArmPointerSize;
+ case kArm64:
+ return kArm64PointerSize;
+ case kX86:
+ return kX86PointerSize;
+ case kX86_64:
+ return kX86_64PointerSize;
+ case kMips:
+ return kMipsPointerSize;
+ case kMips64:
+ return kMips64PointerSize;
+ case kNone:
+ LOG(FATAL) << "ISA kNone does not have pointer size.";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+size_t GetInstructionSetAlignment(InstructionSet isa);
+
+static inline bool Is64BitInstructionSet(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ case kThumb2:
+ case kX86:
+ case kMips:
+ return false;
+
+ case kArm64:
+ case kX86_64:
+ case kMips64:
+ return true;
+
+ case kNone:
+ LOG(FATAL) << "ISA kNone does not have bit width.";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ // Fall-through.
+ case kThumb2:
+ return 4;
+ case kArm64:
+ return 8;
+ case kX86:
+ return 4;
+ case kX86_64:
+ return 8;
+ case kMips:
+ return 4;
+ case kNone:
+ LOG(FATAL) << "ISA kNone does not have spills.";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
+ switch (isa) {
+ case kArm:
+ // Fall-through.
+ case kThumb2:
+ return 4;
+ case kArm64:
+ return 8;
+ case kX86:
+ return 8;
+ case kX86_64:
+ return 8;
+ case kMips:
+ return 4;
+ case kNone:
+ LOG(FATAL) << "ISA kNone does not have spills.";
+ UNREACHABLE();
+ default:
+ LOG(FATAL) << "Unknown ISA " << isa;
+ UNREACHABLE();
+ }
+}
+
+size_t GetStackOverflowReservedBytes(InstructionSet isa);
+
+// 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.
+//
+// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
+// uint64_t or long long int.
+//
+// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
+// size_t-sized values.
+//
+// We need two operations:
+//
+// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
+// GetTwoWordFailureValue() will return a value that has lower part == 0.
+//
+// 2) A value that combines two word-sized values.
+// GetTwoWordSuccessValue() constructs this.
+//
+// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
+// that the object does not move or the value is updated. Simple use of this is NOT SAFE
+// when the garbage collector can move objects concurrently. Ensure that required locks
+// are held when using!
+
+#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+typedef uint64_t TwoWordReturn;
+
+// Encodes method_ptr==nullptr and code_ptr==nullptr
+static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
+ return 0;
+}
+
+// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+ static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
+ uint32_t lo32 = lo;
+ uint64_t hi64 = static_cast<uint64_t>(hi);
+ return ((hi64 << 32) | lo32);
+}
+
+#elif defined(__x86_64__) || defined(__aarch64__)
+struct TwoWordReturn {
+ uintptr_t lo;
+ uintptr_t hi;
+};
+
+// Encodes method_ptr==nullptr. Leaves random value in code pointer.
+static inline TwoWordReturn GetTwoWordFailureValue() {
+ TwoWordReturn ret;
+ ret.lo = 0;
+ return ret;
+}
+
+// Write values into their respective members.
+static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
+ TwoWordReturn ret;
+ ret.lo = lo;
+ ret.hi = hi;
+ return ret;
+}
+#else
+#error "Unsupported architecture"
+#endif
+
+} // namespace art
+
+#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 0000000..1072562
--- /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 0000000..2c6e699
--- /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 0000000..83571cf
--- /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 0000000..932ef32
--- /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 0000000..efec993
--- /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 0000000..f7c64fe
--- /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 0000000..9b81ce2
--- /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 0000000..32cf909
--- /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 0000000..926fabb
--- /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 0000000..d231beb
--- /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 0000000..3280177
--- /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 0000000..5171080
--- /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 b6cf921..37c5f9c 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 49357ad..9ffd199 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 f78273f..00f5cd5 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 4f61707..c4bc969 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 cf7352e..69a573e 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 e165a75..0000000
--- 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.h b/runtime/instruction_set.h
deleted file mode 100644
index 84a3e80..0000000
--- a/runtime/instruction_set.h
+++ /dev/null
@@ -1,405 +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.
- */
-
-#ifndef ART_RUNTIME_INSTRUCTION_SET_H_
-#define ART_RUNTIME_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 {
-
-enum InstructionSet {
- kNone,
- kArm,
- kArm64,
- kThumb2,
- kX86,
- kX86_64,
- kMips,
- kMips64
-};
-std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
-
-#if defined(__arm__)
-static constexpr InstructionSet kRuntimeISA = kArm;
-#elif defined(__aarch64__)
-static constexpr InstructionSet kRuntimeISA = kArm64;
-#elif defined(__mips__)
-static constexpr InstructionSet kRuntimeISA = kMips;
-#elif defined(__i386__)
-static constexpr InstructionSet kRuntimeISA = kX86;
-#elif defined(__x86_64__)
-static constexpr InstructionSet kRuntimeISA = kX86_64;
-#else
-static constexpr InstructionSet kRuntimeISA = kNone;
-#endif
-
-// Architecture-specific pointer sizes
-static constexpr size_t kArmPointerSize = 4;
-static constexpr size_t kArm64PointerSize = 8;
-static constexpr size_t kMipsPointerSize = 4;
-static constexpr size_t kMips64PointerSize = 8;
-static constexpr size_t kX86PointerSize = 4;
-static constexpr size_t kX86_64PointerSize = 8;
-
-// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
-// but ARM ELF requires 8..
-static constexpr size_t kArmAlignment = 8;
-
-// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kArm64Alignment = 16;
-
-// MIPS instruction alignment. MIPS processors require code to be 4-byte aligned.
-// TODO: Can this be 4?
-static constexpr size_t kMipsAlignment = 8;
-
-// X86 instruction alignment. This is the recommended alignment for maximum performance.
-static constexpr size_t kX86Alignment = 16;
-
-
-const char* GetInstructionSetString(InstructionSet isa);
-
-// Note: Returns kNone when the string cannot be parsed to a known value.
-InstructionSet GetInstructionSetFromString(const char* instruction_set);
-
-static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
- switch (isa) {
- case kArm:
- // Fall-through.
- case kThumb2:
- return kArmPointerSize;
- case kArm64:
- return kArm64PointerSize;
- case kX86:
- return kX86PointerSize;
- case kX86_64:
- return kX86_64PointerSize;
- case kMips:
- return kMipsPointerSize;
- case kMips64:
- return kMips64PointerSize;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have pointer size.";
- return 0;
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
- }
-}
-
-size_t GetInstructionSetAlignment(InstructionSet isa);
-
-static inline bool Is64BitInstructionSet(InstructionSet isa) {
- switch (isa) {
- case kArm:
- case kThumb2:
- case kX86:
- case kMips:
- return false;
-
- case kArm64:
- case kX86_64:
- case kMips64:
- return true;
-
- case kNone:
- LOG(FATAL) << "ISA kNone does not have bit width.";
- return 0;
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
- }
-}
-
-static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
- switch (isa) {
- case kArm:
- // Fall-through.
- case kThumb2:
- return 4;
- case kArm64:
- return 8;
- case kX86:
- return 4;
- case kX86_64:
- return 8;
- case kMips:
- return 4;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have spills.";
- return 0;
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
- }
-}
-
-static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
- switch (isa) {
- case kArm:
- // Fall-through.
- case kThumb2:
- return 4;
- case kArm64:
- return 8;
- case kX86:
- return 8;
- case kX86_64:
- return 8;
- case kMips:
- return 4;
- case kNone:
- LOG(FATAL) << "ISA kNone does not have spills.";
- return 0;
- default:
- LOG(FATAL) << "Unknown ISA " << isa;
- return 0;
- }
-}
-
-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.
-//
-// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
-// uint64_t or long long int.
-//
-// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
-// size_t-sized values.
-//
-// We need two operations:
-//
-// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
-// GetTwoWordFailureValue() will return a value that has lower part == 0.
-//
-// 2) A value that combines two word-sized values.
-// GetTwoWordSuccessValue() constructs this.
-//
-// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
-// that the object does not move or the value is updated. Simple use of this is NOT SAFE
-// when the garbage collector can move objects concurrently. Ensure that required locks
-// are held when using!
-
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
-typedef uint64_t TwoWordReturn;
-
-// Encodes method_ptr==nullptr and code_ptr==nullptr
-static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
- return 0;
-}
-
-// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
- static_assert(sizeof(uint32_t) == sizeof(uintptr_t), "Unexpected size difference");
- uint32_t lo32 = lo;
- uint64_t hi64 = static_cast<uint64_t>(hi);
- return ((hi64 << 32) | lo32);
-}
-
-#elif defined(__x86_64__) || defined(__aarch64__)
-struct TwoWordReturn {
- uintptr_t lo;
- uintptr_t hi;
-};
-
-// Encodes method_ptr==nullptr. Leaves random value in code pointer.
-static inline TwoWordReturn GetTwoWordFailureValue() {
- TwoWordReturn ret;
- ret.lo = 0;
- return ret;
-}
-
-// Write values into their respective members.
-static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
- TwoWordReturn ret;
- ret.lo = lo;
- ret.hi = hi;
- return ret;
-}
-#else
-#error "Unsupported architecture"
-#endif
-
-} // namespace art
-
-#endif // ART_RUNTIME_INSTRUCTION_SET_H_
diff --git a/runtime/instruction_set_test.cc b/runtime/instruction_set_test.cc
deleted file mode 100644
index 3f2d16b..0000000
--- 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 646c7ae..369039d 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 f6e2b21..d40d64b 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 0966954..f1a04cb 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 0749c06..02c60ab 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 f577b07..8fb02b8 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 26a2f31..9294868 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 d338ad7..78c6542 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 3cbe1e5..39fd910 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 d4ec803..d448460 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 66c840d..1d772e6 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 7e567fb..b69d2f4 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 669fe6c..891b47b 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 {