LOperand* input = instr->InputAt(0);
ASSERT(input->IsRegister() && input->Equals(instr->result()));
if (instr->needs_check()) {
- __ tst(ToRegister(input), Operand(kSmiTagMask));
- DeoptimizeIf(ne, instr->environment());
+ ASSERT(kHeapObjectTag == 1);
+ // If the input is a HeapObject, SmiUntag will set the carry flag.
+ __ SmiUntag(ToRegister(input), SetCC);
+ DeoptimizeIf(cs, instr->environment());
+ } else {
+ __ SmiUntag(ToRegister(input));
}
- __ SmiUntag(ToRegister(input));
}
Label done;
+ // The input was optimistically untagged; revert it.
+ // The carry flag is set when we reach this deferred code as we just executed
+ // SmiUntag(heap_object, SetCC)
+ ASSERT(kHeapObjectTag == 1);
+ __ adc(input_reg, input_reg, Operand(input_reg));
+
// Heap number map check.
__ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
- // Smi check.
- __ tst(input_reg, Operand(kSmiTagMask));
- __ b(ne, deferred->entry());
-
- // Smi to int32 conversion
- __ SmiUntag(input_reg); // Untag smi.
-
+ // Optimistically untag the input.
+ // If the input is a HeapObject, SmiUntag will set the carry flag.
+ __ SmiUntag(input_reg, SetCC);
+ // Branch to deferred code if the input was tagged.
+ // The deferred code will take care of restoring the tag.
+ __ b(cs, deferred->entry());
__ bind(deferred->exit());
}
void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
Condition cond) {
#if USE_BX
- mov(ip, Operand(target, rmode), LeaveCC, cond);
+ mov(ip, Operand(target, rmode));
bx(ip, cond);
#else
mov(pc, Operand(target, rmode), LeaveCC, cond);
// we have to do it explicitly.
positions_recorder()->WriteRecordedPositions();
- mov(ip, Operand(target, rmode), LeaveCC, cond);
+ mov(ip, Operand(target, rmode));
blx(ip, cond);
ASSERT(kCallTargetAddressOffset == 2 * kInstrSize);
Call(function);
int stack_passed_arguments = (num_arguments <= kRegisterPassedArguments) ?
0 : num_arguments - kRegisterPassedArguments;
- if (OS::ActivationFrameAlignment() > kPointerSize) {
+ if (ActivationFrameAlignment() > kPointerSize) {
ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
// Calculate C flag value for additions.
-bool Simulator::CarryFrom(int32_t left, int32_t right) {
+bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
uint32_t uleft = static_cast<uint32_t>(left);
uint32_t uright = static_cast<uint32_t>(right);
uint32_t urest = 0xffffffffU - uleft;
- return (uright > urest);
+ return (uright > urest) ||
+ (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
}
}
case ADC: {
- Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
- Format(instr, "adc'cond's 'rd, 'rn, 'imm");
+ // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
+ // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
+ alu_out = rn_val + shifter_operand + GetCarry();
+ set_register(rd, alu_out);
+ if (instr->HasS()) {
+ SetNZFlags(alu_out);
+ SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
+ SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
+ }
break;
}
void SetNZFlags(int32_t val);
void SetCFlag(bool val);
void SetVFlag(bool val);
- bool CarryFrom(int32_t left, int32_t right);
+ bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
bool BorrowFrom(int32_t left, int32_t right);
bool OverflowFrom(int32_t alu_out,
int32_t left,
int32_t right,
bool addition);
+ inline int GetCarry() {
+ return c_flag_ ? 1 : 0;
+ };
+
// Support for VFP.
void Compute_FPSCR_Flags(double val1, double val2);
void Copy_FPSCR_to_APSR();
}
}
+
+TEST(11) {
+ // Test instructions using the carry flag.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+ } I;
+ I i;
+
+ i.a = 0xabcd0001;
+ i.b = 0xabcd0000;
+
+ Assembler assm(Isolate::Current(), NULL, 0);
+
+ // Test HeapObject untagging.
+ __ ldr(r1, MemOperand(r0, OFFSET_OF(I, a)));
+ __ mov(r1, Operand(r1, ASR, 1), SetCC);
+ __ adc(r1, r1, Operand(r1), LeaveCC, cs);
+ __ str(r1, MemOperand(r0, OFFSET_OF(I, a)));
+
+ __ ldr(r2, MemOperand(r0, OFFSET_OF(I, b)));
+ __ mov(r2, Operand(r2, ASR, 1), SetCC);
+ __ adc(r2, r2, Operand(r2), LeaveCC, cs);
+ __ str(r2, MemOperand(r0, OFFSET_OF(I, b)));
+
+ // Test corner cases.
+ __ mov(r1, Operand(0xffffffff));
+ __ mov(r2, Operand(0));
+ __ mov(r3, Operand(r1, ASR, 1), SetCC); // Set the carry.
+ __ adc(r3, r1, Operand(r2));
+ __ str(r3, MemOperand(r0, OFFSET_OF(I, c)));
+
+ __ mov(r1, Operand(0xffffffff));
+ __ mov(r2, Operand(0));
+ __ mov(r3, Operand(r2, ASR, 1), SetCC); // Unset the carry.
+ __ adc(r3, r1, Operand(r2));
+ __ str(r3, MemOperand(r0, OFFSET_OF(I, d)));
+
+ __ mov(pc, Operand(lr));
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+#ifdef DEBUG
+ Code::cast(code)->Print();
+#endif
+ F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
+ Object* dummy = CALL_GENERATED_CODE(f, &i, 0, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(0xabcd0001, i.a);
+ CHECK_EQ(static_cast<int32_t>(0xabcd0000) >> 1, i.b);
+ CHECK_EQ(0x00000000, i.c);
+ CHECK_EQ(0xffffffff, i.d);
+}
+
#undef __