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