Do away with variable length memcpy to Set/Get registers in simulator
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 11:20:31 +0000 (11:20 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 12 Jun 2014 11:20:31 +0000 (11:20 +0000)
About a 32% boost.

Before - 5:31

Richards: 84.5
DeltaBlue: 128
Crypto: 65.3
RayTrace: 203
EarleyBoyer: 149
RegExp: 23.4
Splay: 121
NavierStokes: 98.9
----
Score (version 7): 93.8

After - 4:10

Richards: 107
DeltaBlue: 175
Crypto: 93.9
RayTrace: 258
EarleyBoyer: 186
RegExp: 32.7
Splay: 165
NavierStokes: 124
----
Score (version 7): 124

R=jacob.bramley@arm.com, svenpanne@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=21448

Review URL: https://codereview.chromium.org/213943002

Patch from Fritz Koenig <frkoenig@google.com>.

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

src/arm64/simulator-arm64.cc
src/arm64/simulator-arm64.h
src/utils.h

index 8fbbf9c..488b91e 100644 (file)
@@ -823,49 +823,30 @@ int Simulator::CodeFromName(const char* name) {
 
 
 // Helpers ---------------------------------------------------------------------
-int64_t Simulator::AddWithCarry(unsigned reg_size,
-                                bool set_flags,
-                                int64_t src1,
-                                int64_t src2,
-                                int64_t carry_in) {
+template <typename T>
+T Simulator::AddWithCarry(bool set_flags,
+                          T src1,
+                          T src2,
+                          T carry_in) {
+  typedef typename make_unsigned<T>::type unsignedT;
   ASSERT((carry_in == 0) || (carry_in == 1));
-  ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits));
 
-  uint64_t u1, u2;
-  int64_t result;
-  int64_t signed_sum = src1 + src2 + carry_in;
+  T signed_sum = src1 + src2 + carry_in;
+  T result = signed_sum;
 
   bool N, Z, C, V;
 
-  if (reg_size == kWRegSizeInBits) {
-    u1 = static_cast<uint64_t>(src1) & kWRegMask;
-    u2 = static_cast<uint64_t>(src2) & kWRegMask;
-
-    result = signed_sum & kWRegMask;
-    // Compute the C flag by comparing the sum to the max unsigned integer.
-    C = ((kWMaxUInt - u1) < (u2 + carry_in)) ||
-        ((kWMaxUInt - u1 - carry_in) < u2);
-    // Overflow iff the sign bit is the same for the two inputs and different
-    // for the result.
-    int64_t s_src1 = src1 << (kXRegSizeInBits - kWRegSizeInBits);
-    int64_t s_src2 = src2 << (kXRegSizeInBits - kWRegSizeInBits);
-    int64_t s_result = result << (kXRegSizeInBits - kWRegSizeInBits);
-    V = ((s_src1 ^ s_src2) >= 0) && ((s_src1 ^ s_result) < 0);
-
-  } else {
-    u1 = static_cast<uint64_t>(src1);
-    u2 = static_cast<uint64_t>(src2);
+  // Compute the C flag
+  unsignedT u1 = static_cast<unsignedT>(src1);
+  unsignedT u2 = static_cast<unsignedT>(src2);
+  unsignedT urest = std::numeric_limits<unsignedT>::max() - u1;
+  C = (u2 > urest) || (carry_in && (((u2 + 1) > urest) || (u2 > (urest - 1))));
 
-    result = signed_sum;
-    // Compute the C flag by comparing the sum to the max unsigned integer.
-    C = ((kXMaxUInt - u1) < (u2 + carry_in)) ||
-        ((kXMaxUInt - u1 - carry_in) < u2);
-    // Overflow iff the sign bit is the same for the two inputs and different
-    // for the result.
-    V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
-  }
+  // Overflow iff the sign bit is the same for the two inputs and different
+  // for the result.
+  V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
 
-  N = CalcNFlag(result, reg_size);
+  N = CalcNFlag(result);
   Z = CalcZFlag(result);
 
   if (set_flags) {
@@ -878,33 +859,42 @@ int64_t Simulator::AddWithCarry(unsigned reg_size,
 }
 
 
-int64_t Simulator::ShiftOperand(unsigned reg_size,
-                                int64_t value,
-                                Shift shift_type,
-                                unsigned amount) {
+template<typename T>
+void Simulator::AddSubWithCarry(Instruction* instr) {
+  T op2 = reg<T>(instr->Rm());
+  T new_val;
+
+  if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
+    op2 = ~op2;
+  }
+
+  new_val = AddWithCarry<T>(instr->FlagsUpdate(),
+                            reg<T>(instr->Rn()),
+                            op2,
+                            nzcv().C());
+
+  set_reg<T>(instr->Rd(), new_val);
+}
+
+template <typename T>
+T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
+  typedef typename make_unsigned<T>::type unsignedT;
+
   if (amount == 0) {
     return value;
   }
-  int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask;
+
   switch (shift_type) {
     case LSL:
-      return (value << amount) & mask;
+      return value << amount;
     case LSR:
-      return static_cast<uint64_t>(value) >> amount;
-    case ASR: {
-      // Shift used to restore the sign.
-      unsigned s_shift = kXRegSizeInBits - reg_size;
-      // Value with its sign restored.
-      int64_t s_value = (value << s_shift) >> s_shift;
-      return (s_value >> amount) & mask;
-    }
-    case ROR: {
-      if (reg_size == kWRegSizeInBits) {
-        value &= kWRegMask;
-      }
-      return (static_cast<uint64_t>(value) >> amount) |
-             ((value & ((1L << amount) - 1L)) << (reg_size - amount));
-    }
+      return static_cast<unsignedT>(value) >> amount;
+    case ASR:
+      return value >> amount;
+    case ROR:
+      return (static_cast<unsignedT>(value) >> amount) |
+              ((value & ((1L << amount) - 1L)) <<
+                  (sizeof(unsignedT) * 8 - amount));
     default:
       UNIMPLEMENTED();
       return 0;
@@ -912,10 +902,12 @@ int64_t Simulator::ShiftOperand(unsigned reg_size,
 }
 
 
-int64_t Simulator::ExtendValue(unsigned reg_size,
-                               int64_t value,
-                               Extend extend_type,
-                               unsigned left_shift) {
+template <typename T>
+T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
+  const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8;
+  const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8;
+  const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;
+
   switch (extend_type) {
     case UXTB:
       value &= kByteMask;
@@ -927,13 +919,13 @@ int64_t Simulator::ExtendValue(unsigned reg_size,
       value &= kWordMask;
       break;
     case SXTB:
-      value = (value << 56) >> 56;
+      value = (value << kSignExtendBShift) >> kSignExtendBShift;
       break;
     case SXTH:
-      value = (value << 48) >> 48;
+      value = (value << kSignExtendHShift) >> kSignExtendHShift;
       break;
     case SXTW:
-      value = (value << 32) >> 32;
+      value = (value << kSignExtendWShift) >> kSignExtendWShift;
       break;
     case UXTX:
     case SXTX:
@@ -941,8 +933,21 @@ int64_t Simulator::ExtendValue(unsigned reg_size,
     default:
       UNREACHABLE();
   }
-  int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask;
-  return (value << left_shift) & mask;
+  return value << left_shift;
+}
+
+
+template <typename T>
+void Simulator::Extract(Instruction* instr) {
+  unsigned lsb = instr->ImmS();
+  T op2 = reg<T>(instr->Rm());
+  T result = op2;
+
+  if (lsb) {
+    T op1 = reg<T>(instr->Rn());
+    result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb));
+  }
+  set_reg<T>(instr->Rd(), result);
 }
 
 
@@ -1256,110 +1261,110 @@ void Simulator::VisitCompareBranch(Instruction* instr) {
 }
 
 
-void Simulator::AddSubHelper(Instruction* instr, int64_t op2) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
+template<typename T>
+void Simulator::AddSubHelper(Instruction* instr, T op2) {
   bool set_flags = instr->FlagsUpdate();
-  int64_t new_val = 0;
+  T new_val = 0;
   Instr operation = instr->Mask(AddSubOpMask);
 
   switch (operation) {
     case ADD:
     case ADDS: {
-      new_val = AddWithCarry(reg_size,
-                             set_flags,
-                             reg(reg_size, instr->Rn(), instr->RnMode()),
-                             op2);
+      new_val = AddWithCarry<T>(set_flags,
+                                reg<T>(instr->Rn(), instr->RnMode()),
+                                op2);
       break;
     }
     case SUB:
     case SUBS: {
-      new_val = AddWithCarry(reg_size,
-                             set_flags,
-                             reg(reg_size, instr->Rn(), instr->RnMode()),
-                             ~op2,
-                             1);
+      new_val = AddWithCarry<T>(set_flags,
+                                reg<T>(instr->Rn(), instr->RnMode()),
+                                ~op2,
+                                1);
       break;
     }
     default: UNREACHABLE();
   }
 
-  set_reg(reg_size, instr->Rd(), new_val, instr->RdMode());
+  set_reg<T>(instr->Rd(), new_val, instr->RdMode());
 }
 
 
 void Simulator::VisitAddSubShifted(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t op2 = ShiftOperand(reg_size,
-                             reg(reg_size, instr->Rm()),
-                             static_cast<Shift>(instr->ShiftDP()),
-                             instr->ImmDPShift());
-  AddSubHelper(instr, op2);
+  Shift shift_type = static_cast<Shift>(instr->ShiftDP());
+  unsigned shift_amount = instr->ImmDPShift();
+
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
+    AddSubHelper(instr, op2);
+  } else {
+    int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
+    AddSubHelper(instr, op2);
+  }
 }
 
 
 void Simulator::VisitAddSubImmediate(Instruction* instr) {
   int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
-  AddSubHelper(instr, op2);
+  if (instr->SixtyFourBits()) {
+    AddSubHelper<int64_t>(instr, op2);
+  } else {
+    AddSubHelper<int32_t>(instr, op2);
+  }
 }
 
 
 void Simulator::VisitAddSubExtended(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t op2 = ExtendValue(reg_size,
-                            reg(reg_size, instr->Rm()),
-                            static_cast<Extend>(instr->ExtendMode()),
-                            instr->ImmExtendShift());
-  AddSubHelper(instr, op2);
+  Extend ext = static_cast<Extend>(instr->ExtendMode());
+  unsigned left_shift = instr->ImmExtendShift();
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
+    AddSubHelper(instr, op2);
+  } else {
+    int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
+    AddSubHelper(instr, op2);
+  }
 }
 
 
 void Simulator::VisitAddSubWithCarry(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t op2 = reg(reg_size, instr->Rm());
-  int64_t new_val;
-
-  if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
-    op2 = ~op2;
+  if (instr->SixtyFourBits()) {
+    AddSubWithCarry<int64_t>(instr);
+  } else {
+    AddSubWithCarry<int32_t>(instr);
   }
-
-  new_val = AddWithCarry(reg_size,
-                         instr->FlagsUpdate(),
-                         reg(reg_size, instr->Rn()),
-                         op2,
-                         nzcv().C());
-
-  set_reg(reg_size, instr->Rd(), new_val);
 }
 
 
 void Simulator::VisitLogicalShifted(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
   Shift shift_type = static_cast<Shift>(instr->ShiftDP());
   unsigned shift_amount = instr->ImmDPShift();
-  int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type,
-                             shift_amount);
-  if (instr->Mask(NOT) == NOT) {
-    op2 = ~op2;
+
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
+    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
+    LogicalHelper<int64_t>(instr, op2);
+  } else {
+    int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
+    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
+    LogicalHelper<int32_t>(instr, op2);
   }
-  LogicalHelper(instr, op2);
 }
 
 
 void Simulator::VisitLogicalImmediate(Instruction* instr) {
-  LogicalHelper(instr, instr->ImmLogical());
+  if (instr->SixtyFourBits()) {
+    LogicalHelper<int64_t>(instr, instr->ImmLogical());
+  } else {
+    LogicalHelper<int32_t>(instr, instr->ImmLogical());
+  }
 }
 
 
-void Simulator::LogicalHelper(Instruction* instr, int64_t op2) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t op1 = reg(reg_size, instr->Rn());
-  int64_t result = 0;
+template<typename T>
+void Simulator::LogicalHelper(Instruction* instr, T op2) {
+  T op1 = reg<T>(instr->Rn());
+  T result = 0;
   bool update_flags = false;
 
   // Switch on the logical operation, stripping out the NOT bit, as it has a
@@ -1374,41 +1379,46 @@ void Simulator::LogicalHelper(Instruction* instr, int64_t op2) {
   }
 
   if (update_flags) {
-    nzcv().SetN(CalcNFlag(result, reg_size));
+    nzcv().SetN(CalcNFlag(result));
     nzcv().SetZ(CalcZFlag(result));
     nzcv().SetC(0);
     nzcv().SetV(0);
   }
 
-  set_reg(reg_size, instr->Rd(), result, instr->RdMode());
+  set_reg<T>(instr->Rd(), result, instr->RdMode());
 }
 
 
 void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  ConditionalCompareHelper(instr, reg(reg_size, instr->Rm()));
+  if (instr->SixtyFourBits()) {
+    ConditionalCompareHelper(instr, xreg(instr->Rm()));
+  } else {
+    ConditionalCompareHelper(instr, wreg(instr->Rm()));
+  }
 }
 
 
 void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
-  ConditionalCompareHelper(instr, instr->ImmCondCmp());
+  if (instr->SixtyFourBits()) {
+    ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp());
+  } else {
+    ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp());
+  }
 }
 
 
-void Simulator::ConditionalCompareHelper(Instruction* instr, int64_t op2) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t op1 = reg(reg_size, instr->Rn());
+template<typename T>
+void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
+  T op1 = reg<T>(instr->Rn());
 
   if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
     // If the condition passes, set the status flags to the result of comparing
     // the operands.
     if (instr->Mask(ConditionalCompareMask) == CCMP) {
-      AddWithCarry(reg_size, true, op1, ~op2, 1);
+      AddWithCarry<T>(true, op1, ~op2, 1);
     } else {
       ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
-      AddWithCarry(reg_size, true, op1, op2, 0);
+      AddWithCarry<T>(true, op1, op2, 0);
     }
   } else {
     // If the condition fails, set the status flags to the nzcv immediate.
@@ -1443,8 +1453,7 @@ void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
   ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
   unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
 
-  int64_t offset = ExtendValue(kXRegSizeInBits, xreg(instr->Rm()), ext,
-                               shift_amount);
+  int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount);
   LoadStoreHelper(instr, offset, Offset);
 }
 
@@ -1484,28 +1493,23 @@ void Simulator::LoadStoreHelper(Instruction* instr,
     case STR_w:
     case STR_x: MemoryWrite(address, xreg(srcdst), num_bytes); break;
     case LDRSB_w: {
-      set_wreg(srcdst,
-               ExtendValue(kWRegSizeInBits, MemoryRead8(address), SXTB));
+      set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead8(address), SXTB));
       break;
     }
     case LDRSB_x: {
-      set_xreg(srcdst,
-               ExtendValue(kXRegSizeInBits, MemoryRead8(address), SXTB));
+      set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead8(address), SXTB));
       break;
     }
     case LDRSH_w: {
-      set_wreg(srcdst,
-               ExtendValue(kWRegSizeInBits, MemoryRead16(address), SXTH));
+      set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead16(address), SXTH));
       break;
     }
     case LDRSH_x: {
-      set_xreg(srcdst,
-               ExtendValue(kXRegSizeInBits, MemoryRead16(address), SXTH));
+      set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead16(address), SXTH));
       break;
     }
     case LDRSW_x: {
-      set_xreg(srcdst,
-               ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW));
+      set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead32(address), SXTW));
       break;
     }
     case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break;
@@ -1605,8 +1609,8 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
       break;
     }
     case LDPSW_x: {
-      set_xreg(rt, ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW));
-      set_xreg(rt2, ExtendValue(kXRegSizeInBits,
+      set_xreg(rt, ExtendValue<int64_t>(MemoryRead32(address), SXTW));
+      set_xreg(rt2, ExtendValue<int64_t>(
                MemoryRead32(address + kWRegSize), SXTW));
       break;
     }
@@ -1822,25 +1826,26 @@ void Simulator::VisitMoveWideImmediate(Instruction* instr) {
 
 
 void Simulator::VisitConditionalSelect(Instruction* instr) {
-  uint64_t new_val = xreg(instr->Rn());
-
   if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
-    new_val = xreg(instr->Rm());
+    uint64_t new_val = xreg(instr->Rm());
     switch (instr->Mask(ConditionalSelectMask)) {
-      case CSEL_w:
-      case CSEL_x: break;
-      case CSINC_w:
-      case CSINC_x: new_val++; break;
-      case CSINV_w:
-      case CSINV_x: new_val = ~new_val; break;
-      case CSNEG_w:
-      case CSNEG_x: new_val = -new_val; break;
+      case CSEL_w: set_wreg(instr->Rd(), new_val); break;
+      case CSEL_x: set_xreg(instr->Rd(), new_val); break;
+      case CSINC_w: set_wreg(instr->Rd(), new_val + 1); break;
+      case CSINC_x: set_xreg(instr->Rd(), new_val + 1); break;
+      case CSINV_w: set_wreg(instr->Rd(), ~new_val); break;
+      case CSINV_x: set_xreg(instr->Rd(), ~new_val); break;
+      case CSNEG_w: set_wreg(instr->Rd(), -new_val); break;
+      case CSNEG_x: set_xreg(instr->Rd(), -new_val); break;
       default: UNIMPLEMENTED();
     }
+  } else {
+    if (instr->SixtyFourBits()) {
+      set_xreg(instr->Rd(), xreg(instr->Rn()));
+    } else {
+      set_wreg(instr->Rd(), wreg(instr->Rn()));
+    }
   }
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  set_reg(reg_size, instr->Rd(), new_val);
 }
 
 
@@ -1911,28 +1916,17 @@ uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) {
 }
 
 
-void Simulator::VisitDataProcessing2Source(Instruction* instr) {
+template <typename T>
+void Simulator::DataProcessing2Source(Instruction* instr) {
   Shift shift_op = NO_SHIFT;
-  int64_t result = 0;
+  T result = 0;
   switch (instr->Mask(DataProcessing2SourceMask)) {
-    case SDIV_w: {
-      int32_t rn = wreg(instr->Rn());
-      int32_t rm = wreg(instr->Rm());
-      if ((rn == kWMinInt) && (rm == -1)) {
-        result = kWMinInt;
-      } else if (rm == 0) {
-        // Division by zero can be trapped, but not on A-class processors.
-        result = 0;
-      } else {
-        result = rn / rm;
-      }
-      break;
-    }
+    case SDIV_w:
     case SDIV_x: {
-      int64_t rn = xreg(instr->Rn());
-      int64_t rm = xreg(instr->Rm());
-      if ((rn == kXMinInt) && (rm == -1)) {
-        result = kXMinInt;
+      T rn = reg<T>(instr->Rn());
+      T rm = reg<T>(instr->Rm());
+      if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) {
+        result = std::numeric_limits<T>::min();
       } else if (rm == 0) {
         // Division by zero can be trapped, but not on A-class processors.
         result = 0;
@@ -1941,20 +1935,11 @@ void Simulator::VisitDataProcessing2Source(Instruction* instr) {
       }
       break;
     }
-    case UDIV_w: {
-      uint32_t rn = static_cast<uint32_t>(wreg(instr->Rn()));
-      uint32_t rm = static_cast<uint32_t>(wreg(instr->Rm()));
-      if (rm == 0) {
-        // Division by zero can be trapped, but not on A-class processors.
-        result = 0;
-      } else {
-        result = rn / rm;
-      }
-      break;
-    }
+    case UDIV_w:
     case UDIV_x: {
-      uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn()));
-      uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm()));
+      typedef typename make_unsigned<T>::type unsignedT;
+      unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn()));
+      unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm()));
       if (rm == 0) {
         // Division by zero can be trapped, but not on A-class processors.
         result = 0;
@@ -1974,18 +1959,27 @@ void Simulator::VisitDataProcessing2Source(Instruction* instr) {
     default: UNIMPLEMENTED();
   }
 
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
   if (shift_op != NO_SHIFT) {
     // Shift distance encoded in the least-significant five/six bits of the
     // register.
-    int mask = (instr->SixtyFourBits() == 1) ? kShiftAmountXRegMask
-                                             : kShiftAmountWRegMask;
-    unsigned shift = wreg(instr->Rm()) & mask;
-    result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op,
-                          shift);
+    unsigned shift = wreg(instr->Rm());
+    if (sizeof(T) == kWRegSize) {
+      shift &= kShiftAmountWRegMask;
+    } else {
+      shift &= kShiftAmountXRegMask;
+    }
+    result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift);
+  }
+  set_reg<T>(instr->Rd(), result);
+}
+
+
+void Simulator::VisitDataProcessing2Source(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    DataProcessing2Source<int64_t>(instr);
+  } else {
+    DataProcessing2Source<int32_t>(instr);
   }
-  set_reg(reg_size, instr->Rd(), result);
 }
 
 
@@ -2012,9 +2006,6 @@ static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
 
 
 void Simulator::VisitDataProcessing3Source(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-
   int64_t result = 0;
   // Extract and sign- or zero-extend 32-bit arguments for widening operations.
   uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
@@ -2040,21 +2031,26 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) {
       break;
     default: UNIMPLEMENTED();
   }
-  set_reg(reg_size, instr->Rd(), result);
+
+  if (instr->SixtyFourBits()) {
+    set_xreg(instr->Rd(), result);
+  } else {
+    set_wreg(instr->Rd(), result);
+  }
 }
 
 
-void Simulator::VisitBitfield(Instruction* instr) {
-  unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
-                                             : kWRegSizeInBits;
-  int64_t reg_mask = instr->SixtyFourBits() ? kXRegMask : kWRegMask;
-  int64_t R = instr->ImmR();
-  int64_t S = instr->ImmS();
-  int64_t diff = S - R;
-  int64_t mask;
+template <typename T>
+void Simulator::BitfieldHelper(Instruction* instr) {
+  typedef typename make_unsigned<T>::type unsignedT;
+  T reg_size = sizeof(T) * 8;
+  T R = instr->ImmR();
+  T S = instr->ImmS();
+  T diff = S - R;
+  T mask;
   if (diff >= 0) {
-    mask = diff < reg_size - 1 ? (1L << (diff + 1)) - 1
-                               : reg_mask;
+    mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1
+                               : static_cast<T>(-1);
   } else {
     mask = ((1L << (S + 1)) - 1);
     mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R));
@@ -2083,32 +2079,37 @@ void Simulator::VisitBitfield(Instruction* instr) {
       UNIMPLEMENTED();
   }
 
-  int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd());
-  int64_t src = reg(reg_size, instr->Rn());
+  T dst = inzero ? 0 : reg<T>(instr->Rd());
+  T src = reg<T>(instr->Rn());
   // Rotate source bitfield into place.
-  int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R));
+  T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R));
   // Determine the sign extension.
-  int64_t topbits_preshift = (1L << (reg_size - diff - 1)) - 1;
-  int64_t signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
-                     << (diff + 1);
+  T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1;
+  T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
+               << (diff + 1);
 
   // Merge sign extension, dest/zero and bitfield.
   result = signbits | (result & mask) | (dst & ~mask);
 
-  set_reg(reg_size, instr->Rd(), result);
+  set_reg<T>(instr->Rd(), result);
 }
 
 
-void Simulator::VisitExtract(Instruction* instr) {
-  unsigned lsb = instr->ImmS();
-  unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
-                                                    : kWRegSizeInBits;
-  uint64_t result = reg(reg_size, instr->Rm());
-  if (lsb) {
-    result = (result >> lsb) | (reg(reg_size, instr->Rn()) << (reg_size - lsb));
+void Simulator::VisitBitfield(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    BitfieldHelper<int64_t>(instr);
+  } else {
+    BitfieldHelper<int32_t>(instr);
   }
+}
+
 
-  set_reg(reg_size, instr->Rd(), result);
+void Simulator::VisitExtract(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    Extract<uint64_t>(instr);
+  } else {
+    Extract<uint32_t>(instr);
+  }
 }
 
 
index 0ac1a90..bf74de8 100644 (file)
@@ -133,35 +133,28 @@ class SimSystemRegister {
 
 
 // Represent a register (r0-r31, v0-v31).
-template<int kSizeInBytes>
 class SimRegisterBase {
  public:
   template<typename T>
-  void Set(T new_value, unsigned size = sizeof(T)) {
-    ASSERT(size <= kSizeInBytes);
-    ASSERT(size <= sizeof(new_value));
-    // All AArch64 registers are zero-extending; Writing a W register clears the
-    // top bits of the corresponding X register.
-    memset(value_, 0, kSizeInBytes);
-    memcpy(value_, &new_value, size);
+  void Set(T new_value) {
+    value_ = 0;
+    memcpy(&value_, &new_value, sizeof(T));
   }
 
-  // Copy 'size' bytes of the register to the result, and zero-extend to fill
-  // the result.
   template<typename T>
-  T Get(unsigned size = sizeof(T)) const {
-    ASSERT(size <= kSizeInBytes);
+  T Get() const {
     T result;
-    memset(&result, 0, sizeof(result));
-    memcpy(&result, value_, size);
+    memcpy(&result, &value_, sizeof(T));
     return result;
   }
 
  protected:
-  uint8_t value_[kSizeInBytes];
+  int64_t value_;
 };
-typedef SimRegisterBase<kXRegSize> SimRegister;      // r0-r31
-typedef SimRegisterBase<kDRegSize> SimFPRegister;    // v0-v31
+
+
+typedef SimRegisterBase SimRegister;      // r0-r31
+typedef SimRegisterBase SimFPRegister;    // v0-v31
 
 
 class Simulator : public DecoderVisitor {
@@ -328,86 +321,53 @@ class Simulator : public DecoderVisitor {
   VISITOR_LIST(DECLARE)
   #undef DECLARE
 
-  // Register accessors.
+  bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const {
+    return ((code == 31) && (r31mode == Reg31IsZeroRegister));
+  }
 
+  // Register accessors.
   // Return 'size' bits of the value of an integer register, as the specified
   // type. The value is zero-extended to fill the result.
   //
-  // The only supported values of 'size' are kXRegSizeInBits and
-  // kWRegSizeInBits.
   template<typename T>
-  T reg(unsigned size, unsigned code,
-        Reg31Mode r31mode = Reg31IsZeroRegister) const {
-    unsigned size_in_bytes = size / 8;
-    ASSERT(size_in_bytes <= sizeof(T));
-    ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits));
+  T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
     ASSERT(code < kNumberOfRegisters);
-
-    if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
-      T result;
-      memset(&result, 0, sizeof(result));
-      return result;
+    if (IsZeroRegister(code, r31mode)) {
+      return 0;
     }
-    return registers_[code].Get<T>(size_in_bytes);
-  }
-
-  // Like reg(), but infer the access size from the template type.
-  template<typename T>
-  T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
-    return reg<T>(sizeof(T) * 8, code, r31mode);
+    return registers_[code].Get<T>();
   }
 
   // Common specialized accessors for the reg() template.
-  int32_t wreg(unsigned code,
-               Reg31Mode r31mode = Reg31IsZeroRegister) const {
+  int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
     return reg<int32_t>(code, r31mode);
   }
 
-  int64_t xreg(unsigned code,
-               Reg31Mode r31mode = Reg31IsZeroRegister) const {
+  int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
     return reg<int64_t>(code, r31mode);
   }
 
-  int64_t reg(unsigned size, unsigned code,
-              Reg31Mode r31mode = Reg31IsZeroRegister) const {
-    return reg<int64_t>(size, code, r31mode);
-  }
-
   // Write 'size' bits of 'value' into an integer register. The value is
   // zero-extended. This behaviour matches AArch64 register writes.
-  //
-  // The only supported values of 'size' are kXRegSizeInBits and
-  // kWRegSizeInBits.
-  template<typename T>
-  void set_reg(unsigned size, unsigned code, T value,
-               Reg31Mode r31mode = Reg31IsZeroRegister) {
-    unsigned size_in_bytes = size / 8;
-    ASSERT(size_in_bytes <= sizeof(T));
-    ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits));
-    ASSERT(code < kNumberOfRegisters);
-
-    if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
-      return;
-    }
-    return registers_[code].Set(value, size_in_bytes);
-  }
 
   // Like set_reg(), but infer the access size from the template type.
   template<typename T>
   void set_reg(unsigned code, T value,
                Reg31Mode r31mode = Reg31IsZeroRegister) {
-    set_reg(sizeof(value) * 8, code, value, r31mode);
+    ASSERT(code < kNumberOfRegisters);
+    if (!IsZeroRegister(code, r31mode))
+      registers_[code].Set(value);
   }
 
   // Common specialized accessors for the set_reg() template.
   void set_wreg(unsigned code, int32_t value,
                 Reg31Mode r31mode = Reg31IsZeroRegister) {
-    set_reg(kWRegSizeInBits, code, value, r31mode);
+    set_reg(code, value, r31mode);
   }
 
   void set_xreg(unsigned code, int64_t value,
                 Reg31Mode r31mode = Reg31IsZeroRegister) {
-    set_reg(kXRegSizeInBits, code, value, r31mode);
+    set_reg(code, value, r31mode);
   }
 
   // Commonly-used special cases.
@@ -432,24 +392,10 @@ class Simulator : public DecoderVisitor {
 
   Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); }
 
-  // Return 'size' bits of the value of a floating-point register, as the
-  // specified type. The value is zero-extended to fill the result.
-  //
-  // The only supported values of 'size' are kDRegSizeInBits and
-  // kSRegSizeInBits.
-  template<typename T>
-  T fpreg(unsigned size, unsigned code) const {
-    unsigned size_in_bytes = size / 8;
-    ASSERT(size_in_bytes <= sizeof(T));
-    ASSERT((size == kDRegSizeInBits) || (size == kSRegSizeInBits));
-    ASSERT(code < kNumberOfFPRegisters);
-    return fpregisters_[code].Get<T>(size_in_bytes);
-  }
-
-  // Like fpreg(), but infer the access size from the template type.
   template<typename T>
   T fpreg(unsigned code) const {
-    return fpreg<T>(sizeof(T) * 8, code);
+    ASSERT(code < kNumberOfRegisters);
+    return fpregisters_[code].Get<T>();
   }
 
   // Common specialized accessors for the fpreg() template.
@@ -485,7 +431,7 @@ class Simulator : public DecoderVisitor {
   void set_fpreg(unsigned code, T value) {
     ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
     ASSERT(code < kNumberOfFPRegisters);
-    fpregisters_[code].Set(value, sizeof(value));
+    fpregisters_[code].Set(value);
   }
 
   // Common specialized accessors for the set_fpreg() template.
@@ -625,14 +571,19 @@ class Simulator : public DecoderVisitor {
     return !ConditionPassed(cond);
   }
 
-  void AddSubHelper(Instruction* instr, int64_t op2);
-  int64_t AddWithCarry(unsigned reg_size,
-                       bool set_flags,
-                       int64_t src1,
-                       int64_t src2,
-                       int64_t carry_in = 0);
-  void LogicalHelper(Instruction* instr, int64_t op2);
-  void ConditionalCompareHelper(Instruction* instr, int64_t op2);
+  template<typename T>
+  void AddSubHelper(Instruction* instr, T op2);
+  template<typename T>
+  T AddWithCarry(bool set_flags,
+                 T src1,
+                 T src2,
+                 T carry_in = 0);
+  template<typename T>
+  void AddSubWithCarry(Instruction* instr);
+  template<typename T>
+  void LogicalHelper(Instruction* instr, T op2);
+  template<typename T>
+  void ConditionalCompareHelper(Instruction* instr, T op2);
   void LoadStoreHelper(Instruction* instr,
                        int64_t offset,
                        AddrMode addrmode);
@@ -659,18 +610,21 @@ class Simulator : public DecoderVisitor {
   void MemoryWrite64(uint8_t* address, uint64_t value);
   void MemoryWriteFP64(uint8_t* address, double value);
 
-  int64_t ShiftOperand(unsigned reg_size,
-                       int64_t value,
-                       Shift shift_type,
-                       unsigned amount);
-  int64_t Rotate(unsigned reg_width,
-                 int64_t value,
+
+  template <typename T>
+  T ShiftOperand(T value,
                  Shift shift_type,
                  unsigned amount);
-  int64_t ExtendValue(unsigned reg_width,
-                      int64_t value,
-                      Extend extend_type,
-                      unsigned left_shift = 0);
+  template <typename T>
+  T ExtendValue(T value,
+                Extend extend_type,
+                unsigned left_shift = 0);
+  template <typename T>
+  void Extract(Instruction* instr);
+  template <typename T>
+  void DataProcessing2Source(Instruction* instr);
+  template <typename T>
+  void BitfieldHelper(Instruction* instr);
 
   uint64_t ReverseBits(uint64_t value, unsigned num_bits);
   uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
@@ -796,8 +750,9 @@ class Simulator : public DecoderVisitor {
     // is irrelevant, and is not checked here.
   }
 
-  static int CalcNFlag(uint64_t result, unsigned reg_size) {
-    return (result >> (reg_size - 1)) & 1;
+  template <typename T>
+  static int CalcNFlag(T result) {
+    return (result >> (sizeof(T) * 8 - 1)) & 1;
   }
 
   static int CalcZFlag(uint64_t result) {
index 8f07ab3..a2e3be5 100644 (file)
@@ -234,6 +234,25 @@ inline int32_t WhichPowerOf2Abs(int32_t x) {
 }
 
 
+// Obtains the unsigned type corresponding to T
+// available in C++11 as std::make_unsigned
+template<typename T>
+struct make_unsigned {
+  typedef T type;
+};
+
+
+// Template specializations necessary to have make_unsigned work
+template<> struct make_unsigned<int32_t> {
+  typedef uint32_t type;
+};
+
+
+template<> struct make_unsigned<int64_t> {
+  typedef uint64_t type;
+};
+
+
 // ----------------------------------------------------------------------------
 // BitField is a help template for encoding and decode bitfield with
 // unsigned content.