// 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();
supported_ |= 1u << VFP3;
found_by_runtime_probing_ |= 1u << VFP3;
}
+
+ if (OS::ArmCpuHasFeature(ARMv7)) {
+ supported_ |= 1u << ARMv7;
+ found_by_runtime_probing_ |= 1u << ARMv7;
+ }
#endif
}
// Data-processing instructions.
+
+// UBFX <Rd>,<Rn>,#<lsb>,#<width - 1>
+// 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<uint32_t>(src2.imm32_) <= 0x1f);
+ ASSERT(static_cast<uint32_t>(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);
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);
}
+
void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
// r1 : x
// r0 : y
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));
// 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.
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);
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"));
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<uint32_t>(instr->Bits(20, 16));
+ uint32_t lsbit = static_cast<uint32_t>(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: {
}
+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.
// 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,
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);
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<uint32_t>(instr->Bits(20, 16));
+ uint32_t lsbit = static_cast<uint32_t>(instr->ShiftAmountField());
+ uint32_t msbit = widthminus1 + lsbit;
+ if (msbit <= 31) {
+ uint32_t rm_val =
+ static_cast<uint32_t>(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;
}
"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")
RDTSC = 4, // x86
CPUID = 10, // x86
VFP3 = 1, // ARM
+ ARMv7 = 2, // ARM
SAHF = 0}; // x86
} } // namespace v8::internal
// 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
case VFP3:
search_string = "vfp";
break;
+ case ARMv7:
+ search_string = "ARMv7";
+ break;
default:
UNREACHABLE();
}