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 |