From 2618422ed5777f86feda0b7f112902640f58fbd1 Mon Sep 17 00:00:00 2001 From: "sgjesse@chromium.org" Date: Fri, 5 Feb 2010 08:46:41 +0000 Subject: [PATCH] ARMv7 ubfx support Patch from Kun Zhang , see http://codereview.chromium.org/569015. Review URL: http://codereview.chromium.org/573027 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3804 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/assembler-arm.cc | 31 ++++++++++++++++++++++++++++--- src/arm/assembler-arm.h | 3 +++ src/arm/codegen-arm.cc | 13 ++++--------- src/arm/disasm-arm.cc | 25 +++++++++++++++++++++++-- src/arm/macro-assembler-arm.cc | 12 ++++++++++++ src/arm/macro-assembler-arm.h | 3 +++ src/arm/simulator-arm.cc | 26 +++++++++++++++++++++----- src/flag-definitions.h | 2 ++ src/globals.h | 1 + src/platform-linux.cc | 5 +++++ 10 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 1e1d71941..c79aac656 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -51,9 +51,14 @@ void CpuFeatures::Probe() { // If the compiler is allowed to use vfp then we can use vfp too in our // code generation. #if !defined(__arm__) - // For the simulator=arm build, always use VFP since the arm simulator has - // VFP support. - supported_ |= 1u << VFP3; + // For the simulator=arm build, use VFP when FLAG_enable_vfp3 is enabled. + if (FLAG_enable_vfp3) { + supported_ |= 1u << VFP3; + } + // For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled + if (FLAG_enable_armv7) { + supported_ |= 1u << ARMv7; + } #else if (Serializer::enabled()) { supported_ |= OS::CpuFeaturesImpliedByPlatform(); @@ -66,6 +71,11 @@ void CpuFeatures::Probe() { supported_ |= 1u << VFP3; found_by_runtime_probing_ |= 1u << VFP3; } + + if (OS::ArmCpuHasFeature(ARMv7)) { + supported_ |= 1u << ARMv7; + found_by_runtime_probing_ |= 1u << ARMv7; + } #endif } @@ -850,6 +860,21 @@ void Assembler::bx(Register target, Condition cond) { // v5 and above, plus v4t // Data-processing instructions. + +// UBFX ,,#,# +// Instruction details available in ARM DDI 0406A, A8-464. +// cond(31-28) | 01111(27-23)| 1(22) | 1(21) | widthm1(20-16) | +// Rd(15-12) | lsb(11-7) | 101(6-4) | Rn(3-0) +void Assembler::ubfx(Register dst, Register src1, const Operand& src2, + const Operand& src3, Condition cond) { + ASSERT(!src2.rm_.is_valid() && !src3.rm_.is_valid()); + ASSERT(static_cast(src2.imm32_) <= 0x1f); + ASSERT(static_cast(src3.imm32_) <= 0x1f); + emit(cond | 0x3F*B21 | src3.imm32_*B16 | + dst.code()*B12 | src2.imm32_*B7 | 0x5*B4 | src1.code()); +} + + void Assembler::and_(Register dst, Register src1, const Operand& src2, SBit s, Condition cond) { addrmod1(cond | 0*B21 | s, src1, dst, src2); diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 9a3c29141..f6b7a06aa 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -628,6 +628,9 @@ class Assembler : public Malloced { void blx(Label* L) { blx(branch_offset(L, false)); } // v5 and above // Data-processing instructions + void ubfx(Register dst, Register src1, const Operand& src2, + const Operand& src3, Condition cond = al); + void and_(Register dst, Register src1, const Operand& src2, SBit s = LeaveCC, Condition cond = al); diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index 5d4298d64..c33c1dacc 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -5843,6 +5843,7 @@ const char* GenericBinaryOpStub::GetName() { } + void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // r1 : x // r0 : y @@ -6035,9 +6036,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break; case Token::SAR: // Remove tags from right operand. - __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y - // Use only the 5 least significant bits of the shift count. - __ and_(r2, r2, Operand(0x1f)); + __ GetLeastBitsFromSmi(r2, r0, 5); __ mov(r0, Operand(r1, ASR, r2)); // Smi tag result. __ bic(r0, r0, Operand(kSmiTagMask)); @@ -6046,9 +6045,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { // Remove tags from operands. We can't do this on a 31 bit number // because then the 0s get shifted into bit 30 instead of bit 31. __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x - __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y - // Use only the 5 least significant bits of the shift count. - __ and_(r2, r2, Operand(0x1f)); + __ GetLeastBitsFromSmi(r2, r0, 5); __ mov(r3, Operand(r3, LSR, r2)); // Unsigned shift is not allowed to produce a negative number, so // check the sign bit and the sign bit after Smi tagging. @@ -6060,9 +6057,7 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) { case Token::SHL: // Remove tags from operands. __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x - __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y - // Use only the 5 least significant bits of the shift count. - __ and_(r2, r2, Operand(0x1f)); + __ GetLeastBitsFromSmi(r2, r0, 5); __ mov(r3, Operand(r3, LSL, r2)); // Check that the signed result fits in a Smi. __ add(r2, r3, Operand(0x40000000), SetCC); diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 5b314557d..127c16086 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -429,12 +429,22 @@ int Decoder::FormatOption(Instr* instr, const char* format) { return 3; } case 'o': { - if (format[3] == '1') { + if ((format[3] == '1') && (format[4] == '2')) { // 'off12: 12-bit offset for load and store instructions ASSERT(STRING_STARTS_WITH(format, "off12")); out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", instr->Offset12Field()); return 5; + } else if ((format[3] == '1') && (format[4] == '6')) { + ASSERT(STRING_STARTS_WITH(format, "off16to20")); + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", instr->Bits(20, 16) +1); + return 9; + } else if (format[3] == '7') { + ASSERT(STRING_STARTS_WITH(format, "off7to11")); + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", instr->ShiftAmountField()); + return 8; } // 'off8: 8-bit offset for extra load and store instructions ASSERT(STRING_STARTS_WITH(format, "off8")); @@ -795,7 +805,18 @@ void Decoder::DecodeType3(Instr* instr) { break; } case 3: { - Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); + if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) { + uint32_t widthminus1 = static_cast(instr->Bits(20, 16)); + uint32_t lsbit = static_cast(instr->ShiftAmountField()); + uint32_t msbit = widthminus1 + lsbit; + if (msbit <= 31) { + Format(instr, "ubfx'cond 'rd, 'rm, #'off7to11, #'off16to20"); + } else { + UNREACHABLE(); + } + } else { + Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); + } break; } default: { diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index b34a10154..a3273ed56 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -1106,6 +1106,18 @@ void MacroAssembler::IntegerToDoubleConversionWithVFP3(Register inReg, } +void MacroAssembler::GetLeastBitsFromSmi(Register dst, + Register src, + int num_least_bits) { + if (CpuFeatures::IsSupported(ARMv7)) { + ubfx(dst, src, Operand(kSmiTagSize), Operand(num_least_bits - 1)); + } else { + mov(dst, Operand(src, ASR, kSmiTagSize)); + and_(dst, dst, Operand((1 << num_least_bits) - 1)); + } +} + + void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { // All parameters are on the stack. r0 has the return value after call. diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index e7df34d61..6a13ad9a1 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -287,6 +287,9 @@ class MacroAssembler: public Assembler { // occurred. void IllegalOperation(int num_arguments); + // Get the number of least significant bits from a register + void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits); + // Uses VFP instructions to Convert a Smi to a double. void IntegerToDoubleConversionWithVFP3(Register inReg, Register outHighReg, diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 2de09b011..cee5aea0d 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -1741,7 +1741,7 @@ void Simulator::DecodeType2(Instr* instr) { void Simulator::DecodeType3(Instr* instr) { - ASSERT(instr->Bit(4) == 0); + ASSERT(instr->Bits(6, 4) == 0x5 || instr->Bit(4) == 0); int rd = instr->RdField(); int rn = instr->RnField(); int32_t rn_val = get_register(rn); @@ -1768,10 +1768,26 @@ void Simulator::DecodeType3(Instr* instr) { break; } case 3: { - // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); - addr = rn_val + shifter_operand; - if (instr->HasW()) { - set_register(rn, addr); + if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) { + uint32_t widthminus1 = static_cast(instr->Bits(20, 16)); + uint32_t lsbit = static_cast(instr->ShiftAmountField()); + uint32_t msbit = widthminus1 + lsbit; + if (msbit <= 31) { + uint32_t rm_val = + static_cast(get_register(instr->RmField())); + uint32_t extr_val = rm_val << (31 - msbit); + extr_val = extr_val >> (31 - widthminus1); + set_register(instr->RdField(), extr_val); + } else { + UNREACHABLE(); + } + return; + } else { + // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); + addr = rn_val + shifter_operand; + if (instr->HasW()) { + set_register(rn, addr); + } } break; } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 07b2aa502..6e22d5bbc 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -116,6 +116,8 @@ DEFINE_bool(enable_sahf, true, "enable use of SAHF instruction if available (X64 only)") DEFINE_bool(enable_vfp3, true, "enable use of VFP3 instructions if available (ARM only)") +DEFINE_bool(enable_armv7, true, + "enable use of ARMv7 instructions if available (ARM only)") // bootstrapper.cc DEFINE_string(expose_natives_as, NULL, "expose natives in global object") diff --git a/src/globals.h b/src/globals.h index 369aafa68..8f6f47c65 100644 --- a/src/globals.h +++ b/src/globals.h @@ -612,6 +612,7 @@ enum CpuFeature { SSE3 = 32, // x86 RDTSC = 4, // x86 CPUID = 10, // x86 VFP3 = 1, // ARM + ARMv7 = 2, // ARM SAHF = 0}; // x86 } } // namespace v8::internal diff --git a/src/platform-linux.cc b/src/platform-linux.cc index df7ab4cf9..e890f94aa 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -89,6 +89,8 @@ uint64_t OS::CpuFeaturesImpliedByPlatform() { // Here gcc is telling us that we are on an ARM and gcc is assuming that we // have VFP3 instructions. If gcc can assume it then so can we. return 1u << VFP3; +#elif CAN_USE_ARMV7_INSTRUCTIONS + return 1u << ARMv7; #else return 0; // Linux runs on anything. #endif @@ -113,6 +115,9 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) { case VFP3: search_string = "vfp"; break; + case ARMv7: + search_string = "ARMv7"; + break; default: UNREACHABLE(); } -- 2.34.1