Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stdlib.h> | 5 #include <stdlib.h> |
| 6 #include <cmath> | 6 #include <cmath> |
| 7 #include <cstdarg> | 7 #include <cstdarg> |
| 8 #include "v8.h" | 8 #include "v8.h" |
| 9 | 9 |
| 10 #if V8_TARGET_ARCH_ARM64 | 10 #if V8_TARGET_ARCH_ARM64 |
| (...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 871 if (set_flags) { | 871 if (set_flags) { |
| 872 nzcv().SetN(N); | 872 nzcv().SetN(N); |
| 873 nzcv().SetZ(Z); | 873 nzcv().SetZ(Z); |
| 874 nzcv().SetC(C); | 874 nzcv().SetC(C); |
| 875 nzcv().SetV(V); | 875 nzcv().SetV(V); |
| 876 } | 876 } |
| 877 return result; | 877 return result; |
| 878 } | 878 } |
| 879 | 879 |
| 880 | 880 |
| 881 int64_t Simulator::ShiftOperand(unsigned reg_size, | 881 template<> struct make_unsigned<int32_t> { |
| 882 int64_t value, | 882 public: |
| 883 Shift shift_type, | 883 typedef uint32_t type; |
| 884 unsigned amount) { | 884 }; |
| 885 | |
| 886 | |
| 887 template<> struct make_unsigned<int64_t> { | |
| 888 public: | |
|
jbramley
2014/05/16 14:05:50
Is 'public' necessary here?
Fritz
2014/05/16 18:11:46
Yes. Below it is accessed make_unsigned<T>::type
Sven Panne
2014/05/19 08:12:26
Huh? struct = class + public, so this shouldn't be
Fritz
2014/05/20 19:44:24
Your correct. My mistake.
Done.
| |
| 889 typedef uint64_t type; | |
| 890 }; | |
| 891 | |
| 892 | |
| 893 template <typename T> | |
| 894 T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) { | |
| 895 typedef typename make_unsigned<T>::type unsignedT; | |
|
jbramley
2014/05/16 14:05:50
I don't like this mechanism I'm afraid; it's not a
Fritz
2014/05/16 18:11:46
I haven't found away around this yet.
Propagating
| |
| 896 | |
| 885 if (amount == 0) { | 897 if (amount == 0) { |
| 886 return value; | 898 return value; |
| 887 } | 899 } |
| 888 int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask; | 900 |
| 889 switch (shift_type) { | 901 switch (shift_type) { |
| 890 case LSL: | 902 case LSL: |
| 891 return (value << amount) & mask; | 903 return value << amount; |
| 892 case LSR: | 904 case LSR: |
| 893 return static_cast<uint64_t>(value) >> amount; | 905 return static_cast<unsignedT>(value) >> amount; |
| 894 case ASR: { | 906 case ASR: { |
| 895 // Shift used to restore the sign. | 907 return value >> amount; |
| 896 unsigned s_shift = kXRegSizeInBits - reg_size; | |
| 897 // Value with its sign restored. | |
| 898 int64_t s_value = (value << s_shift) >> s_shift; | |
| 899 return (s_value >> amount) & mask; | |
| 900 } | 908 } |
| 901 case ROR: { | 909 case ROR: { |
| 902 if (reg_size == kWRegSizeInBits) { | 910 return (static_cast<unsignedT>(value) >> amount) | |
| 903 value &= kWRegMask; | 911 ((value & ((1L << amount) - 1L)) << |
| 904 } | 912 (sizeof(unsignedT) * 8 - amount)); |
| 905 return (static_cast<uint64_t>(value) >> amount) | | |
| 906 ((value & ((1L << amount) - 1L)) << (reg_size - amount)); | |
| 907 } | 913 } |
| 908 default: | 914 default: |
| 909 UNIMPLEMENTED(); | 915 UNIMPLEMENTED(); |
| 910 return 0; | 916 return 0; |
| 911 } | 917 } |
| 912 } | 918 } |
| 913 | 919 |
| 914 | 920 |
| 915 int64_t Simulator::ExtendValue(unsigned reg_size, | 921 int64_t Simulator::ExtendValue(unsigned reg_size, |
| 916 int64_t value, | 922 int64_t value, |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1282 break; | 1288 break; |
| 1283 } | 1289 } |
| 1284 default: UNREACHABLE(); | 1290 default: UNREACHABLE(); |
| 1285 } | 1291 } |
| 1286 | 1292 |
| 1287 set_reg(reg_size, instr->Rd(), new_val, instr->RdMode()); | 1293 set_reg(reg_size, instr->Rd(), new_val, instr->RdMode()); |
| 1288 } | 1294 } |
| 1289 | 1295 |
| 1290 | 1296 |
| 1291 void Simulator::VisitAddSubShifted(Instruction* instr) { | 1297 void Simulator::VisitAddSubShifted(Instruction* instr) { |
| 1292 unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits | 1298 int64_t op2 = 0; |
| 1293 : kWRegSizeInBits; | 1299 if (instr->SixtyFourBits()) { |
| 1294 int64_t op2 = ShiftOperand(reg_size, | 1300 op2 = ShiftOperand(xreg(instr->Rm()), |
| 1295 reg(reg_size, instr->Rm()), | 1301 static_cast<Shift>(instr->ShiftDP()), |
| 1296 static_cast<Shift>(instr->ShiftDP()), | 1302 instr->ImmDPShift()); |
| 1297 instr->ImmDPShift()); | 1303 } else { |
| 1304 op2 = ShiftOperand(wreg(instr->Rm()), | |
| 1305 static_cast<Shift>(instr->ShiftDP()), | |
| 1306 instr->ImmDPShift()); | |
|
jbramley
2014/05/16 14:05:50
This would be clearer (and fit on one line) if it
Fritz
2014/05/16 18:11:46
Done.
| |
| 1307 op2 &= kWRegMask; | |
| 1308 } | |
| 1298 AddSubHelper(instr, op2); | 1309 AddSubHelper(instr, op2); |
| 1299 } | 1310 } |
| 1300 | 1311 |
| 1301 | 1312 |
| 1302 void Simulator::VisitAddSubImmediate(Instruction* instr) { | 1313 void Simulator::VisitAddSubImmediate(Instruction* instr) { |
| 1303 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); | 1314 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); |
| 1304 AddSubHelper(instr, op2); | 1315 AddSubHelper(instr, op2); |
| 1305 } | 1316 } |
| 1306 | 1317 |
| 1307 | 1318 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1330 instr->FlagsUpdate(), | 1341 instr->FlagsUpdate(), |
| 1331 reg(reg_size, instr->Rn()), | 1342 reg(reg_size, instr->Rn()), |
| 1332 op2, | 1343 op2, |
| 1333 nzcv().C()); | 1344 nzcv().C()); |
| 1334 | 1345 |
| 1335 set_reg(reg_size, instr->Rd(), new_val); | 1346 set_reg(reg_size, instr->Rd(), new_val); |
| 1336 } | 1347 } |
| 1337 | 1348 |
| 1338 | 1349 |
| 1339 void Simulator::VisitLogicalShifted(Instruction* instr) { | 1350 void Simulator::VisitLogicalShifted(Instruction* instr) { |
| 1340 unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits | |
| 1341 : kWRegSizeInBits; | |
| 1342 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); | 1351 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); |
| 1343 unsigned shift_amount = instr->ImmDPShift(); | 1352 unsigned shift_amount = instr->ImmDPShift(); |
| 1344 int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type, | 1353 int64_t op2 = 0; |
| 1345 shift_amount); | 1354 |
| 1355 if (instr->SixtyFourBits()) { | |
| 1356 op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); | |
| 1357 } else { | |
| 1358 op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); | |
| 1359 op2 &= kWRegMask; | |
|
jbramley
2014/05/16 14:05:50
Doesn't the new ShiftOperand apply that mask? If s
Fritz
2014/05/16 18:11:46
ShiftOperand was returning a signed int64_t. It's
| |
| 1360 } | |
| 1361 | |
| 1346 if (instr->Mask(NOT) == NOT) { | 1362 if (instr->Mask(NOT) == NOT) { |
| 1347 op2 = ~op2; | 1363 op2 = ~op2; |
| 1348 } | 1364 } |
| 1349 LogicalHelper(instr, op2); | 1365 LogicalHelper(instr, op2); |
| 1350 } | 1366 } |
| 1351 | 1367 |
| 1352 | 1368 |
| 1353 void Simulator::VisitLogicalImmediate(Instruction* instr) { | 1369 void Simulator::VisitLogicalImmediate(Instruction* instr) { |
| 1354 LogicalHelper(instr, instr->ImmLogical()); | 1370 LogicalHelper(instr, instr->ImmLogical()); |
| 1355 } | 1371 } |
| (...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1903 {4, 5, 6, 7, 0, 1, 2, 3}, | 1919 {4, 5, 6, 7, 0, 1, 2, 3}, |
| 1904 {0, 1, 2, 3, 4, 5, 6, 7} }; | 1920 {0, 1, 2, 3, 4, 5, 6, 7} }; |
| 1905 uint64_t result = 0; | 1921 uint64_t result = 0; |
| 1906 for (int i = 0; i < 8; i++) { | 1922 for (int i = 0; i < 8; i++) { |
| 1907 result <<= 8; | 1923 result <<= 8; |
| 1908 result |= bytes[permute_table[mode][i]]; | 1924 result |= bytes[permute_table[mode][i]]; |
| 1909 } | 1925 } |
| 1910 return result; | 1926 return result; |
| 1911 } | 1927 } |
| 1912 | 1928 |
| 1913 | 1929 template <typename T> |
| 1914 void Simulator::VisitDataProcessing2Source(Instruction* instr) { | 1930 void Simulator::DataProcessing2Source(Instruction* instr) { |
| 1931 typedef typename make_unsigned<T>::type unsignedT; | |
| 1915 Shift shift_op = NO_SHIFT; | 1932 Shift shift_op = NO_SHIFT; |
| 1916 int64_t result = 0; | 1933 T result = 0; |
| 1934 const T kMinimumInteger = static_cast<T>(1) << (sizeof(T) * 8 - 1); | |
|
jbramley
2014/05/16 14:05:50
Consider adding a helper function to do this (perh
Fritz
2014/05/16 18:11:46
Thanks, great idea.
Sven Panne
2014/05/19 08:12:26
Even better idea: Use <limits>: http://www.cpluspl
Fritz
2014/05/20 19:44:24
Done.
| |
| 1917 switch (instr->Mask(DataProcessing2SourceMask)) { | 1935 switch (instr->Mask(DataProcessing2SourceMask)) { |
| 1918 case SDIV_w: { | 1936 case SDIV_w: |
| 1919 int32_t rn = wreg(instr->Rn()); | 1937 case SDIV_x: { |
| 1920 int32_t rm = wreg(instr->Rm()); | 1938 T rn = reg<T>(instr->Rn()); |
| 1921 if ((rn == kWMinInt) && (rm == -1)) { | 1939 T rm = reg<T>(instr->Rm()); |
| 1922 result = kWMinInt; | 1940 if ((rn == kMinimumInteger) && (rm == -1)) { |
| 1941 result = kMinimumInteger; | |
| 1923 } else if (rm == 0) { | 1942 } else if (rm == 0) { |
| 1924 // Division by zero can be trapped, but not on A-class processors. | 1943 // Division by zero can be trapped, but not on A-class processors. |
| 1925 result = 0; | 1944 result = 0; |
| 1926 } else { | |
| 1927 result = rn / rm; | |
| 1928 } | |
| 1929 break; | |
| 1930 } | |
| 1931 case SDIV_x: { | |
| 1932 int64_t rn = xreg(instr->Rn()); | |
| 1933 int64_t rm = xreg(instr->Rm()); | |
| 1934 if ((rn == kXMinInt) && (rm == -1)) { | |
| 1935 result = kXMinInt; | |
| 1936 } else if (rm == 0) { | |
| 1937 // Division by zero can be trapped, but not on A-class processors. | |
| 1938 result = 0; | |
| 1939 } else { | 1945 } else { |
| 1940 result = rn / rm; | 1946 result = rn / rm; |
| 1941 } | 1947 } |
| 1942 break; | 1948 break; |
| 1943 } | 1949 } |
| 1944 case UDIV_w: { | 1950 case UDIV_w: |
| 1945 uint32_t rn = static_cast<uint32_t>(wreg(instr->Rn())); | 1951 case UDIV_x: { |
| 1946 uint32_t rm = static_cast<uint32_t>(wreg(instr->Rm())); | 1952 unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn())); |
| 1953 unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm())); | |
| 1947 if (rm == 0) { | 1954 if (rm == 0) { |
| 1948 // Division by zero can be trapped, but not on A-class processors. | 1955 // Division by zero can be trapped, but not on A-class processors. |
| 1949 result = 0; | 1956 result = 0; |
| 1950 } else { | |
| 1951 result = rn / rm; | |
| 1952 } | |
| 1953 break; | |
| 1954 } | |
| 1955 case UDIV_x: { | |
| 1956 uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn())); | |
| 1957 uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm())); | |
| 1958 if (rm == 0) { | |
| 1959 // Division by zero can be trapped, but not on A-class processors. | |
| 1960 result = 0; | |
| 1961 } else { | 1957 } else { |
| 1962 result = rn / rm; | 1958 result = rn / rm; |
| 1963 } | 1959 } |
| 1964 break; | 1960 break; |
| 1965 } | 1961 } |
| 1966 case LSLV_w: | 1962 case LSLV_w: |
| 1967 case LSLV_x: shift_op = LSL; break; | 1963 case LSLV_x: shift_op = LSL; break; |
| 1968 case LSRV_w: | 1964 case LSRV_w: |
| 1969 case LSRV_x: shift_op = LSR; break; | 1965 case LSRV_x: shift_op = LSR; break; |
| 1970 case ASRV_w: | 1966 case ASRV_w: |
| 1971 case ASRV_x: shift_op = ASR; break; | 1967 case ASRV_x: shift_op = ASR; break; |
| 1972 case RORV_w: | 1968 case RORV_w: |
| 1973 case RORV_x: shift_op = ROR; break; | 1969 case RORV_x: shift_op = ROR; break; |
| 1974 default: UNIMPLEMENTED(); | 1970 default: UNIMPLEMENTED(); |
| 1975 } | 1971 } |
| 1976 | 1972 |
| 1977 unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits | |
| 1978 : kWRegSizeInBits; | |
| 1979 if (shift_op != NO_SHIFT) { | 1973 if (shift_op != NO_SHIFT) { |
| 1980 // Shift distance encoded in the least-significant five/six bits of the | 1974 // Shift distance encoded in the least-significant five/six bits of the |
| 1981 // register. | 1975 // register. |
| 1982 int mask = (instr->SixtyFourBits() == 1) ? kShiftAmountXRegMask | 1976 unsigned shift = wreg(instr->Rm()); |
| 1983 : kShiftAmountWRegMask; | 1977 if (sizeof(T) == kWRegSize) { |
| 1984 unsigned shift = wreg(instr->Rm()) & mask; | 1978 shift &= kShiftAmountWRegMask; |
| 1985 result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op, | 1979 } else { |
| 1986 shift); | 1980 shift &= kShiftAmountXRegMask; |
| 1981 } | |
| 1982 result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift); | |
| 1987 } | 1983 } |
| 1988 set_reg(reg_size, instr->Rd(), result); | 1984 set_reg<T>(instr->Rd(), result); |
| 1989 } | 1985 } |
| 1990 | 1986 |
| 1991 | 1987 |
| 1988 void Simulator::VisitDataProcessing2Source(Instruction* instr) { | |
| 1989 if (instr->SixtyFourBits()) { | |
| 1990 DataProcessing2Source<int64_t>(instr); | |
| 1991 } else { | |
| 1992 DataProcessing2Source<int32_t>(instr); | |
| 1993 } | |
| 1994 } | |
| 1995 | |
| 1996 | |
| 1992 // The algorithm used is described in section 8.2 of | 1997 // The algorithm used is described in section 8.2 of |
| 1993 // Hacker's Delight, by Henry S. Warren, Jr. | 1998 // Hacker's Delight, by Henry S. Warren, Jr. |
| 1994 // It assumes that a right shift on a signed integer is an arithmetic shift. | 1999 // It assumes that a right shift on a signed integer is an arithmetic shift. |
| 1995 static int64_t MultiplyHighSigned(int64_t u, int64_t v) { | 2000 static int64_t MultiplyHighSigned(int64_t u, int64_t v) { |
| 1996 uint64_t u0, v0, w0; | 2001 uint64_t u0, v0, w0; |
| 1997 int64_t u1, v1, w1, w2, t; | 2002 int64_t u1, v1, w1, w2, t; |
| 1998 | 2003 |
| 1999 u0 = u & 0xffffffffL; | 2004 u0 = u & 0xffffffffL; |
| 2000 u1 = u >> 32; | 2005 u1 = u >> 32; |
| 2001 v0 = v & 0xffffffffL; | 2006 v0 = v & 0xffffffffL; |
| (...skipping 1722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3724 | 3729 |
| 3725 delete[] format; | 3730 delete[] format; |
| 3726 } | 3731 } |
| 3727 | 3732 |
| 3728 | 3733 |
| 3729 #endif // USE_SIMULATOR | 3734 #endif // USE_SIMULATOR |
| 3730 | 3735 |
| 3731 } } // namespace v8::internal | 3736 } } // namespace v8::internal |
| 3732 | 3737 |
| 3733 #endif // V8_TARGET_ARCH_ARM64 | 3738 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |