// FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7?
// - dTR is likely used more than aTR, and we'll get better instruction
// encoding if it's in the low 8 registers.
- static const ARM::RegisterID dataTempRegister = ARM::ip;
- static const RegisterID addressTempRegister = ARM::r3;
- static const FPRegisterID fpTempRegister = ARM::d7;
+ static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip;
+ static const RegisterID addressTempRegister = ARMRegisters::r3;
+ static const FPRegisterID fpTempRegister = ARMRegisters::d7;
struct ArmAddress {
enum AddressType {
Zero = ARMv7Assembler::ConditionEQ,
NonZero = ARMv7Assembler::ConditionNE
};
-
enum DoubleCondition {
+ // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
DoubleEqual = ARMv7Assembler::ConditionEQ,
+ DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently.
DoubleGreaterThan = ARMv7Assembler::ConditionGT,
DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE,
DoubleLessThan = ARMv7Assembler::ConditionLO,
DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS,
+ // If either operand is NaN, these conditions always evaluate to true.
+ DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently.
+ DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE,
+ DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI,
+ DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS,
+ DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT,
+ DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE,
};
- static const RegisterID stackPointerRegister = ARM::sp;
- static const RegisterID linkRegister = ARM::lr;
+ static const RegisterID stackPointerRegister = ARMRegisters::sp;
+ static const RegisterID linkRegister = ARMRegisters::lr;
// Integer arithmetic operations:
//
}
}
- void lshift32(Imm32 imm, RegisterID dest)
+ void lshift32(RegisterID shift_amount, RegisterID dest)
{
- m_assembler.lsl(dest, dest, imm.m_value);
+ // Clamp the shift to the range 0..31
+ ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
+ ASSERT(armImm.isValid());
+ m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
+
+ m_assembler.lsl(dest, dest, dataTempRegister);
}
- void lshift32(RegisterID shift_amount, RegisterID dest)
+ void lshift32(Imm32 imm, RegisterID dest)
{
- m_assembler.lsl(dest, dest, shift_amount);
+ m_assembler.lsl(dest, dest, imm.m_value & 0x1f);
}
void mul32(RegisterID src, RegisterID dest)
void rshift32(RegisterID shift_amount, RegisterID dest)
{
- m_assembler.asr(dest, dest, shift_amount);
+ // Clamp the shift to the range 0..31
+ ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f);
+ ASSERT(armImm.isValid());
+ m_assembler.ARM_and(dataTempRegister, shift_amount, armImm);
+
+ m_assembler.asr(dest, dest, dataTempRegister);
}
void rshift32(Imm32 imm, RegisterID dest)
{
- m_assembler.asr(dest, dest, imm.m_value);
+ m_assembler.asr(dest, dest, imm.m_value & 0x1f);
}
void sub32(RegisterID src, RegisterID dest)
load32(setupArmAddress(address), dest);
}
+ void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
+ {
+ load32(setupArmAddress(address), dest);
+ }
+
void load32(void* address, RegisterID dest)
{
move(ImmPtr(address), addressTempRegister);
{
m_assembler.vcmp_F64(left, right);
m_assembler.vmrs_APSR_nzcv_FPSCR();
+
+ if (cond == DoubleNotEqual) {
+ // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump.
+ Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
+ Jump result = makeBranch(ARMv7Assembler::ConditionNE);
+ unordered.link(this);
+ return result;
+ }
+ if (cond == DoubleEqualOrUnordered) {
+ Jump unordered = makeBranch(ARMv7Assembler::ConditionVS);
+ Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE);
+ unordered.link(this);
+ // We get here if either unordered, or equal.
+ Jump result = makeJump();
+ notEqual.link(this);
+ return result;
+ }
return makeBranch(cond);
}
Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID)
{
ASSERT_NOT_REACHED();
+ return jump();
}
void pop(RegisterID dest)
{
// store postindexed with writeback
- m_assembler.ldr(dest, ARM::sp, sizeof(void*), false, true);
+ m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
}
void push(RegisterID src)
{
// store preindexed with writeback
- m_assembler.str(src, ARM::sp, -sizeof(void*), true, true);
+ m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
}
void push(Address address)
return branch32(cond, addressTempRegister, right);
}
+ Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right)
+ {
+ // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/
+ load32WithUnalignedHalfWords(left, addressTempRegister);
+ return branch32(cond, addressTempRegister, right);
+ }
+
Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, dataTempRegister);
protected:
ARMv7Assembler::JmpSrc makeJump()
{
- return m_assembler.b();
+ moveFixedWidthEncoding(Imm32(0), dataTempRegister);
+ return m_assembler.bx(dataTempRegister);
}
ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond)
{
- m_assembler.it(cond);
- return m_assembler.b();
+ m_assembler.it(cond, true, true);
+ moveFixedWidthEncoding(Imm32(0), dataTempRegister);
+ return m_assembler.bx(dataTempRegister);
}
ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); }
ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); }
return addressTempRegister;
}
- DataLabel32 moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
+ void moveFixedWidthEncoding(Imm32 imm, RegisterID dst)
{
uint32_t value = imm.m_value;
m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff));