ARM: Optimisations for call, jump and untag.
authorkarlklose@chromium.org <karlklose@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Apr 2011 13:53:11 +0000 (13:53 +0000)
committerkarlklose@chromium.org <karlklose@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Apr 2011 13:53:11 +0000 (13:53 +0000)
Improves some V8 benchmarks by a few % on A9.

Patch by ARM Ltd.

BUG=none
TEST=Added to test-assembler-arm.cc.

Review URL: http://codereview.chromium.org/6874010

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7647 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/lithium-codegen-arm.cc
src/arm/macro-assembler-arm.cc
src/arm/simulator-arm.cc
src/arm/simulator-arm.h
test/cctest/test-assembler-arm.cc

index 2d415cbaf12ee8c96dcb72288c1c60525af004b1..c820e2e31ba1fba25d3b2a9f60cc12fb2f8c9ec1 100644 (file)
@@ -3614,10 +3614,13 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
   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));
 }
 
 
@@ -3688,6 +3691,12 @@ void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
 
   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);
@@ -3760,13 +3769,12 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
 
   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());
 }
 
index c800ffc2fa39691c62421ff968aa5c5fd3a62c27..f71a887a180f1ff5acbe8a8a1a729fa86449504d 100644 (file)
@@ -83,7 +83,7 @@ void MacroAssembler::Jump(Register target, Condition cond) {
 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);
@@ -168,7 +168,7 @@ void MacroAssembler::Call(intptr_t target,
   // 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);
@@ -2887,7 +2887,7 @@ void MacroAssembler::CallCFunctionHelper(Register function,
   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)));
index da554c29533637883c078e2972c7929cba7ec196..1f55f73a0203fd3c33c5e7ca069e16378523241c 100644 (file)
@@ -1282,12 +1282,13 @@ void Simulator::SetVFlag(bool val) {
 
 
 // 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))));
 }
 
 
@@ -2209,8 +2210,15 @@ void Simulator::DecodeType01(Instruction* instr) {
       }
 
       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;
       }
 
index a16cae5ad33f450e63c7d1e013eb7145fb670ec7..5250638355d8682559b8558f56517883dee6ba83 100644 (file)
@@ -223,13 +223,17 @@ class Simulator {
   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();
index 89153c7444335d1b5dc3543103edf9365609902b..17032035c4c670d99eabf85238e5f29970268437 100644 (file)
@@ -945,4 +945,69 @@ TEST(10) {
   }
 }
 
+
+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 __