Revision: 20545
Author:   [email protected]
Date:     Mon Apr  7 12:33:03 2014 UTC
Log:      ARM64: Introduce a version of ADR handling distant targets.

This fixes an out-of-range label error for an ADR instruction in the
mozilla/data/js1_5/Regress/regress-280769-2.js test.

[email protected]

Review URL: https://codereview.chromium.org/222433002
http://code.google.com/p/v8/source/detail?r=20545

Modified:
 /branches/bleeding_edge/src/arm64/assembler-arm64.cc
 /branches/bleeding_edge/src/arm64/assembler-arm64.h
 /branches/bleeding_edge/src/arm64/instructions-arm64.cc
 /branches/bleeding_edge/src/arm64/instructions-arm64.h
 /branches/bleeding_edge/src/arm64/macro-assembler-arm64-inl.h
 /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc
 /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h
 /branches/bleeding_edge/src/arm64/regexp-macro-assembler-arm64.cc
 /branches/bleeding_edge/test/cctest/test-assembler-arm64.cc

=======================================
--- /branches/bleeding_edge/src/arm64/assembler-arm64.cc Fri Apr 4 12:54:12 2014 UTC +++ /branches/bleeding_edge/src/arm64/assembler-arm64.cc Mon Apr 7 12:33:03 2014 UTC
@@ -2815,6 +2815,76 @@
   // No out-of-line constant pool support.
   UNREACHABLE();
 }
+
+
+void PatchingAssembler::MovInt64(const Register& rd, int64_t imm) {
+  Label start;
+  bind(&start);
+
+  ASSERT(rd.Is64Bits());
+  ASSERT(!rd.IsSP());
+
+  for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) {
+    uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
+    movk(rd, imm16, 16 * i);
+  }
+
+  ASSERT(SizeOfCodeGeneratedSince(&start) ==
+         kMovInt64NInstrs * kInstructionSize);
+}
+
+
+void PatchingAssembler::PatchAdrFar(Instruction* target) {
+  // The code at the current instruction should be:
+  //   adr  rd, 0
+  //   nop  (adr_far)
+  //   nop  (adr_far)
+  //   nop  (adr_far)
+  //   movz scratch, 0
+  //   add  rd, rd, scratch
+
+  // Verify the expected code.
+  Instruction* expected_adr = InstructionAt(0);
+  CHECK(expected_adr->IsAdr() && (expected_adr->ImmPCRel() == 0));
+  int rd_code = expected_adr->Rd();
+  for (int i = 0; i < kAdrFarPatchableNNops; ++i) {
+    CHECK(InstructionAt((i + 1) * kInstructionSize)->IsNop(ADR_FAR_NOP));
+  }
+  Instruction* expected_movz =
+      InstructionAt((kAdrFarPatchableNInstrs - 2) * kInstructionSize);
+  CHECK(expected_movz->IsMovz() &&
+        (expected_movz->ImmMoveWide() == 0) &&
+        (expected_movz->ShiftMoveWide() == 0));
+  int scratch_code = expected_movz->Rd();
+  Instruction* expected_add =
+      InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize);
+  CHECK(expected_add->IsAddSubShifted() &&
+        (expected_add->Mask(AddSubOpMask) == ADD) &&
+        expected_add->SixtyFourBits() &&
+ (expected_add->Rd() == rd_code) && (expected_add->Rn() == rd_code) &&
+        (expected_add->Rm() == scratch_code) &&
+        (static_cast<Shift>(expected_add->ShiftDP()) == LSL) &&
+        (expected_add->ImmDPShift() == 0));
+
+  // Patch to load the correct address.
+  Label start;
+  bind(&start);
+  Register rd = Register::XRegFromCode(rd_code);
+ // If the target is in range, we only patch the adr. Otherwise we patch the
+  // nops with fixup instructions.
+  int target_offset = expected_adr->DistanceTo(target);
+  if (Instruction::IsValidPCRelOffset(target_offset)) {
+    adr(rd, target_offset);
+    for (int i = 0; i < kAdrFarPatchableNInstrs - 2; ++i) {
+      nop(ADR_FAR_NOP);
+    }
+  } else {
+    Register scratch = Register::XRegFromCode(scratch_code);
+    adr(rd, 0);
+    MovInt64(scratch, target_offset);
+    add(rd, rd, scratch);
+  }
+}


 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/arm64/assembler-arm64.h Thu Apr 3 14:30:44 2014 UTC +++ /branches/bleeding_edge/src/arm64/assembler-arm64.h Mon Apr 7 12:33:03 2014 UTC
@@ -1501,8 +1501,9 @@
   enum NopMarkerTypes {
     DEBUG_BREAK_NOP,
     INTERRUPT_CODE_NOP,
+    ADR_FAR_NOP,
     FIRST_NOP_MARKER = DEBUG_BREAK_NOP,
-    LAST_NOP_MARKER = INTERRUPT_CODE_NOP
+    LAST_NOP_MARKER = ADR_FAR_NOP
   };

   void nop(NopMarkerTypes n) {
@@ -2223,6 +2224,14 @@
     size_t length = buffer_size_ - kGap;
     CPU::FlushICache(buffer_, length);
   }
+
+  static const int kMovInt64NInstrs = 4;
+  void MovInt64(const Register& rd, int64_t imm);
+
+  // See definition of PatchAdrFar() for details.
+  static const int kAdrFarPatchableNNops = kMovInt64NInstrs - 1;
+  static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 3;
+  void PatchAdrFar(Instruction* target);
 };


=======================================
--- /branches/bleeding_edge/src/arm64/instructions-arm64.cc Fri Mar 21 09:28:26 2014 UTC +++ /branches/bleeding_edge/src/arm64/instructions-arm64.cc Mon Apr 7 12:33:03 2014 UTC
@@ -254,11 +254,18 @@

 void Instruction::SetPCRelImmTarget(Instruction* target) {
   // ADRP is not supported, so 'this' must point to an ADR instruction.
-  ASSERT(Mask(PCRelAddressingMask) == ADR);
+  ASSERT(IsAdr());

-  Instr imm = Assembler::ImmPCRelAddress(DistanceTo(target));
-
-  SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
+  int target_offset = DistanceTo(target);
+  Instr imm;
+  if (Instruction::IsValidPCRelOffset(target_offset)) {
+    imm = Assembler::ImmPCRelAddress(target_offset);
+    SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
+  } else {
+    PatchingAssembler patcher(this,
+                              PatchingAssembler::kAdrFarPatchableNInstrs);
+    patcher.PatchAdrFar(target);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/arm64/instructions-arm64.h Fri Mar 21 09:28:26 2014 UTC +++ /branches/bleeding_edge/src/arm64/instructions-arm64.h Mon Apr 7 12:33:03 2014 UTC
@@ -160,9 +160,10 @@
   // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
   // formed from ImmPCRelLo and ImmPCRelHi.
   int ImmPCRel() const {
+    ASSERT(IsPCRelAddressing());
     int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
     int const width = ImmPCRelLo_width + ImmPCRelHi_width;
-    return signed_bitextract_32(width-1, 0, offset);
+    return signed_bitextract_32(width - 1, 0, offset);
   }

   uint64_t ImmLogical();
@@ -202,6 +203,10 @@
   bool IsPCRelAddressing() const {
     return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
   }
+
+  bool IsAdr() const {
+    return Mask(PCRelAddressingMask) == ADR;
+  }

   bool IsLogicalImmediate() const {
     return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
@@ -210,6 +215,10 @@
   bool IsAddSubImmediate() const {
     return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
   }
+
+  bool IsAddSubShifted() const {
+    return Mask(AddSubShiftedFMask) == AddSubShiftedFixed;
+  }

   bool IsAddSubExtended() const {
     return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
@@ -387,6 +396,10 @@
   }


+  static const int ImmPCRelRangeBitwidth = 21;
+  static bool IsValidPCRelOffset(int offset) {
+    return is_int21(offset);
+  }
   void SetPCRelImmTarget(Instruction* target);
   void SetBranchImmTarget(Instruction* target);
 };
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64-inl.h Thu Apr 3 14:30:44 2014 UTC +++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64-inl.h Mon Apr 7 12:33:03 2014 UTC
@@ -319,13 +319,6 @@
 #undef DEFINE_FUNCTION


-void MacroAssembler::Adr(const Register& rd, Label* label) {
-  ASSERT(allow_macro_instructions_);
-  ASSERT(!rd.IsZero());
-  adr(rd, label);
-}
-
-
 void MacroAssembler::Asr(const Register& rd,
                          const Register& rn,
                          unsigned shift) {
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Mon Mar 31 14:06:42 2014 UTC +++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Mon Apr 7 12:33:03 2014 UTC
@@ -597,6 +597,43 @@
   }
   return need_longer_range;
 }
+
+
+void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) {
+  ASSERT(allow_macro_instructions_);
+  ASSERT(!rd.IsZero());
+
+  if (hint == kAdrNear) {
+    adr(rd, label);
+    return;
+  }
+
+  ASSERT(hint == kAdrFar);
+  UseScratchRegisterScope temps(this);
+  Register scratch = temps.AcquireX();
+  ASSERT(!AreAliased(rd, scratch));
+
+  if (label->is_bound()) {
+    int label_offset = label->pos() - pc_offset();
+    if (Instruction::IsValidPCRelOffset(label_offset)) {
+      adr(rd, label);
+    } else {
+      ASSERT(label_offset <= 0);
+ int min_adr_offset = -(1 << (Instruction::ImmPCRelRangeBitwidth - 1));
+      adr(rd, min_adr_offset);
+      Add(rd, rd, label_offset - min_adr_offset);
+    }
+  } else {
+    InstructionAccurateScope scope(
+        this, PatchingAssembler::kAdrFarPatchableNInstrs);
+    adr(rd, label);
+    for (int i = 0; i < PatchingAssembler::kAdrFarPatchableNNops; ++i) {
+      nop(ADR_FAR_NOP);
+    }
+    movz(scratch, 0);
+    add(rd, rd, scratch);
+  }
+}


void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Fri Apr 4 13:41:12 2014 UTC +++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Mon Apr 7 12:33:03 2014 UTC
@@ -255,8 +255,16 @@
   void Load(const Register& rt, const MemOperand& addr, Representation r);
   void Store(const Register& rt, const MemOperand& addr, Representation r);

+  enum AdrHint {
+    // The target must be within the immediate range of adr.
+    kAdrNear,
+    // The target may be outside of the immediate range of adr. Additional
+    // instructions may be emitted.
+    kAdrFar
+  };
+  void Adr(const Register& rd, Label* label, AdrHint = kAdrNear);
+
   // Remaining instructions are simple pass-through calls to the assembler.
-  inline void Adr(const Register& rd, Label* label);
   inline void Asr(const Register& rd, const Register& rn, unsigned shift);
inline void Asr(const Register& rd, const Register& rn, const Register& rm);

=======================================
--- /branches/bleeding_edge/src/arm64/regexp-macro-assembler-arm64.cc Mon Mar 24 10:41:33 2014 UTC +++ /branches/bleeding_edge/src/arm64/regexp-macro-assembler-arm64.cc Mon Apr 7 12:33:03 2014 UTC
@@ -1128,7 +1128,7 @@
     int target = label->pos();
     __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
   } else {
-    __ Adr(x10, label);
+    __ Adr(x10, label, MacroAssembler::kAdrFar);
     __ Sub(x10, x10, code_pointer());
     if (masm_->emit_debug_code()) {
       __ Cmp(x10, kWRegMask);
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-arm64.cc Thu Apr 3 14:30:44 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-assembler-arm64.cc Mon Apr 7 12:33:03 2014 UTC
@@ -1684,6 +1684,71 @@

   TEARDOWN();
 }
+
+
+TEST(adr_far) {
+  INIT_V8();
+
+  int max_range = 1 << (Instruction::ImmPCRelRangeBitwidth - 1);
+  SETUP_SIZE(max_range + 1000 * kInstructionSize);
+
+  Label done, fail;
+  Label test_near, near_forward, near_backward;
+  Label test_far, far_forward, far_backward;
+
+  START();
+  __ Mov(x0, 0x0);
+
+  __ Bind(&test_near);
+  __ Adr(x10, &near_forward, MacroAssembler::kAdrFar);
+  __ Br(x10);
+  __ B(&fail);
+  __ Bind(&near_backward);
+  __ Orr(x0, x0, 1 << 1);
+  __ B(&test_far);
+
+  __ Bind(&near_forward);
+  __ Orr(x0, x0, 1 << 0);
+  __ Adr(x10, &near_backward, MacroAssembler::kAdrFar);
+  __ Br(x10);
+
+  __ Bind(&test_far);
+  __ Adr(x10, &far_forward, MacroAssembler::kAdrFar);
+  __ Br(x10);
+  __ B(&fail);
+  __ Bind(&far_backward);
+  __ Orr(x0, x0, 1 << 3);
+  __ B(&done);
+
+  for (unsigned i = 0; i < max_range / kInstructionSize + 1; ++i) {
+    if (i % 100 == 0) {
+      // If we do land in this code, we do not want to execute so many nops
+ // before reaching the end of test (especially if tracing is activated).
+      __ b(&fail);
+    } else {
+      __ nop();
+    }
+  }
+
+
+  __ Bind(&far_forward);
+  __ Orr(x0, x0, 1 << 2);
+  __ Adr(x10, &far_backward, MacroAssembler::kAdrFar);
+  __ Br(x10);
+
+  __ B(&done);
+  __ Bind(&fail);
+  __ Orr(x0, x0, 1 << 4);
+  __ Bind(&done);
+
+  END();
+
+  RUN();
+
+  ASSERT_EQUAL_64(0xf, x0);
+
+  TEARDOWN();
+}


 TEST(branch_cond) {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to