Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 // | 4 // |
| 5 // The intrinsic code below is executed before a method has built its frame. | 5 // The intrinsic code below is executed before a method has built its frame. |
| 6 // The return address is on the stack and the arguments below it. | 6 // The return address is on the stack and the arguments below it. |
| 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. | 7 // Registers EDX (arguments descriptor) and ECX (function) must be preserved. |
| 8 // Each intrinsification method returns true if the corresponding | 8 // Each intrinsification method returns true if the corresponding |
| 9 // Dart method was intrinsified. | 9 // Dart method was intrinsified. |
| 10 | 10 |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 907 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 908 __ movl(ECX, Address(ESP, + 2 * kWordSize)); | 908 __ movl(ECX, Address(ESP, + 2 * kWordSize)); |
| 909 __ StoreIntoObject(ECX, | 909 __ StoreIntoObject(ECX, |
| 910 FieldAddress(ECX, Bigint::digits_offset()), EAX, false); | 910 FieldAddress(ECX, Bigint::digits_offset()), EAX, false); |
| 911 __ ret(); | 911 __ ret(); |
| 912 } | 912 } |
| 913 | 913 |
| 914 | 914 |
| 915 // TODO(regis): Once this intrinsic is implemented on all architectures, the | 915 // TODO(regis): Once this intrinsic is implemented on all architectures, the |
| 916 // corresponding Dart method will be untested. Add a test with --no-intrinsify. | 916 // corresponding Dart method will be untested. Add a test with --no-intrinsify. |
| 917 void Intrinsifier::Bigint_add(Assembler* assembler) { | |
| 918 // static void _add(Uint32List digits, int used, | |
| 919 // Uint32List a_digits, int a_used, | |
| 920 // Uint32List r_digits) | |
| 921 | |
| 922 // Preserve CTX to free ESI. | |
| 923 __ pushl(CTX); | |
| 924 ASSERT(CTX == ESI); | |
| 925 | |
| 926 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits | |
| 927 __ movl(EAX, Address(ESP, 5 * kWordSize)); // used is Smi | |
| 928 __ SmiUntag(EAX); // used > 0. | |
| 929 __ movl(ESI, Address(ESP, 4 * kWordSize)); // a_digits | |
| 930 __ movl(ECX, Address(ESP, 3 * kWordSize)); // a_used is Smi | |
| 931 __ SmiUntag(ECX); // a_used > 0. | |
| 932 __ movl(EBX, Address(ESP, 2 * kWordSize)); // r_digits | |
| 933 | |
| 934 // Precompute 'used - a_used' now so that CF is not lost later. | |
| 935 __ subl(EAX, ECX); | |
| 936 __ incl(EAX); // To account for the extra test between loops. | |
| 937 __ pushl(EAX); | |
| 938 | |
| 939 __ xorl(EDX, EDX); // EDX = 0, CF = 0. | |
| 940 Label add_loop; | |
| 941 __ Bind(&add_loop); | |
| 942 __ movl(EAX, FieldAddress(EDI, EDX, TIMES_4, TypedData::data_offset())); | |
| 943 __ adcl(EAX, FieldAddress(ESI, EDX, TIMES_4, TypedData::data_offset())); | |
| 944 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | |
| 945 __ incl(EDX); // Does not affect CF. | |
| 946 __ decl(ECX); // Does not affect CF. | |
| 947 __ j(NOT_ZERO, &add_loop, Assembler::kNearJump); | |
| 948 | |
| 949 Label last_carry; | |
| 950 __ popl(ECX); | |
| 951 __ decl(ECX); // Does not affect CF. | |
| 952 __ j(ZERO, &last_carry, Assembler::kNearJump); | |
| 953 | |
| 954 Label carry_loop; | |
| 955 __ Bind(&carry_loop); | |
| 956 __ movl(EAX, FieldAddress(EDI, EDX, TIMES_4, TypedData::data_offset())); | |
| 957 __ adcl(EAX, Immediate(0)); | |
| 958 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | |
| 959 __ incl(EDX); // Does not affect CF. | |
| 960 __ decl(ECX); // Does not affect CF. | |
| 961 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); | |
| 962 | |
| 963 __ Bind(&last_carry); | |
| 964 __ movl(EAX, Immediate(0)); | |
| 965 __ adcl(EAX, Immediate(0)); | |
| 966 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | |
| 967 | |
| 968 // Restore CTX and return. | |
| 969 __ popl(CTX); | |
| 970 // TODO(regis): Confirm that returning Object::null() is not required. | |
| 971 __ ret(); | |
| 972 } | |
| 973 | |
| 974 | |
| 975 // TODO(regis): Once this intrinsic is implemented on all architectures, the | |
| 976 // corresponding Dart method will be untested. Add a test with --no-intrinsify. | |
| 977 void Intrinsifier::Bigint_sub(Assembler* assembler) { | |
| 978 // static void _sub(Uint32List digits, int used, | |
| 979 // Uint32List a_digits, int a_used, | |
| 980 // Uint32List r_digits) | |
| 981 | |
| 982 // Preserve CTX to free ESI. | |
| 983 __ pushl(CTX); | |
| 984 ASSERT(CTX == ESI); | |
| 985 | |
| 986 __ movl(EDI, Address(ESP, 6 * kWordSize)); // digits | |
| 987 __ movl(EAX, Address(ESP, 5 * kWordSize)); // used is Smi | |
| 988 __ SmiUntag(EAX); // used > 0. | |
| 989 __ movl(ESI, Address(ESP, 4 * kWordSize)); // a_digits | |
| 990 __ movl(ECX, Address(ESP, 3 * kWordSize)); // a_used is Smi | |
| 991 __ SmiUntag(ECX); // a_used > 0. | |
| 992 __ movl(EBX, Address(ESP, 2 * kWordSize)); // r_digits | |
| 993 | |
| 994 // Precompute 'used - a_used' now so that CF is not lost later. | |
| 995 __ subl(EAX, ECX); | |
| 996 __ incl(EAX); // To account for the extra test between loops. | |
| 997 __ pushl(EAX); | |
| 998 | |
| 999 __ xorl(EDX, EDX); // EDX = 0, CF = 0. | |
| 1000 Label add_loop; | |
|
Cutch
2014/09/30 17:52:54
sub_loop?
regis
2014/09/30 18:35:58
Done.
| |
| 1001 __ Bind(&add_loop); | |
| 1002 __ movl(EAX, FieldAddress(EDI, EDX, TIMES_4, TypedData::data_offset())); | |
| 1003 __ sbbl(EAX, FieldAddress(ESI, EDX, TIMES_4, TypedData::data_offset())); | |
| 1004 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | |
| 1005 __ incl(EDX); // Does not affect CF. | |
| 1006 __ decl(ECX); // Does not affect CF. | |
| 1007 __ j(NOT_ZERO, &add_loop, Assembler::kNearJump); | |
| 1008 | |
| 1009 Label done; | |
| 1010 __ popl(ECX); | |
| 1011 __ decl(ECX); // Does not affect CF. | |
| 1012 __ j(ZERO, &done, Assembler::kNearJump); | |
| 1013 | |
| 1014 Label carry_loop; | |
| 1015 __ Bind(&carry_loop); | |
| 1016 __ movl(EAX, FieldAddress(EDI, EDX, TIMES_4, TypedData::data_offset())); | |
| 1017 __ sbbl(EAX, Immediate(0)); | |
| 1018 __ movl(FieldAddress(EBX, EDX, TIMES_4, TypedData::data_offset()), EAX); | |
| 1019 __ incl(EDX); // Does not affect CF. | |
| 1020 __ decl(ECX); // Does not affect CF. | |
| 1021 __ j(NOT_ZERO, &carry_loop, Assembler::kNearJump); | |
| 1022 | |
| 1023 __ Bind(&done); | |
| 1024 // Restore CTX and return. | |
| 1025 __ popl(CTX); | |
| 1026 // TODO(regis): Confirm that returning Object::null() is not required. | |
| 1027 __ ret(); | |
| 1028 } | |
| 1029 | |
| 1030 | |
| 1031 // TODO(regis): Once this intrinsic is implemented on all architectures, the | |
| 1032 // corresponding Dart method will be untested. Add a test with --no-intrinsify. | |
| 917 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { | 1033 void Intrinsifier::Bigint_mulAdd(Assembler* assembler) { |
| 918 // Pseudo code: | 1034 // Pseudo code: |
| 919 // static void _mulAdd(Uint32List x_digits, int xi, | 1035 // static void _mulAdd(Uint32List x_digits, int xi, |
| 920 // Uint32List m_digits, int i, | 1036 // Uint32List m_digits, int i, |
| 921 // Uint32List a_digits, int j, int n) { | 1037 // Uint32List a_digits, int j, int n) { |
| 922 // uint32_t x = x_digits[xi]; | 1038 // uint32_t x = x_digits[xi >> 1]; // xi is Smi. |
| 923 // if (x == 0 || n == 0) { | 1039 // if (x == 0 || n == 0) { |
| 924 // return; | 1040 // return; |
| 925 // } | 1041 // } |
| 926 // uint32_t* mip = &m_digits[i >> 1]; // i is Smi. | 1042 // uint32_t* mip = &m_digits[i >> 1]; // i is Smi. |
| 927 // uint32_t* ajp = &a_digits[j >> 1]; // j is Smi. | 1043 // uint32_t* ajp = &a_digits[j >> 1]; // j is Smi. |
| 928 // uint32_t c = 0; | 1044 // uint32_t c = 0; |
| 929 // SmiUntag(n); | 1045 // SmiUntag(n); |
| 930 // do { | 1046 // do { |
| 931 // uint32_t mi = *mip++; | 1047 // uint32_t mi = *mip++; |
| 932 // uint32_t aj = *ajp; | 1048 // uint32_t aj = *ajp; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1052 // uint32_t xi = *xip++; | 1168 // uint32_t xi = *xip++; |
| 1053 // uint32_t aj = *ajp; | 1169 // uint32_t aj = *ajp; |
| 1054 // uint96_t t = 2*x*xi + aj + c; // 2-bit * 32-bit * 32-bit -> 65-bit. | 1170 // uint96_t t = 2*x*xi + aj + c; // 2-bit * 32-bit * 32-bit -> 65-bit. |
| 1055 // *ajp++ = low32(t); | 1171 // *ajp++ = low32(t); |
| 1056 // c = high64(t); // 33-bit. | 1172 // c = high64(t); // 33-bit. |
| 1057 // } | 1173 // } |
| 1058 // uint32_t aj = *ajp; | 1174 // uint32_t aj = *ajp; |
| 1059 // uint64_t t = aj + c; // 32-bit + 33-bit -> 34-bit. | 1175 // uint64_t t = aj + c; // 32-bit + 33-bit -> 34-bit. |
| 1060 // *ajp++ = low32(t); | 1176 // *ajp++ = low32(t); |
| 1061 // *ajp = high32(t); | 1177 // *ajp = high32(t); |
| 1178 // } | |
| 1062 | 1179 |
| 1063 // EDI = xip = &x_digits[i >> 1] | 1180 // EDI = xip = &x_digits[i >> 1] |
| 1064 __ movl(EDI, Address(ESP, 4 * kWordSize)); // m_digits | 1181 __ movl(EDI, Address(ESP, 4 * kWordSize)); // m_digits |
| 1065 __ movl(EAX, Address(ESP, 3 * kWordSize)); // i is Smi | 1182 __ movl(EAX, Address(ESP, 3 * kWordSize)); // i is Smi |
| 1066 __ leal(EDI, FieldAddress(EDI, EAX, TIMES_2, TypedData::data_offset())); | 1183 __ leal(EDI, FieldAddress(EDI, EAX, TIMES_2, TypedData::data_offset())); |
| 1067 | 1184 |
| 1068 // EBX = x = *xip++, return if x == 0 | 1185 // EBX = x = *xip++, return if x == 0 |
| 1069 Label x_zero; | 1186 Label x_zero; |
| 1070 __ movl(EBX, Address(EDI, 0)); | 1187 __ movl(EBX, Address(EDI, 0)); |
| 1071 __ cmpl(EBX, Immediate(0)); | 1188 __ cmpl(EBX, Immediate(0)); |
| 1072 __ j(EQUAL, &x_zero); | 1189 __ j(EQUAL, &x_zero); |
| 1073 __ addl(EDI, Immediate(kWordSize)); | 1190 __ addl(EDI, Immediate(kWordSize)); |
| 1074 | 1191 |
| 1075 // Preserve CTX to free ESI. | 1192 // Preserve CTX to free ESI. |
| 1076 __ pushl(CTX); | 1193 __ pushl(CTX); |
| 1077 ASSERT(CTX == ESI); | 1194 ASSERT(CTX == ESI); |
| 1078 | 1195 |
| 1079 // ESI = ajp = &a_digits[i] | 1196 // ESI = ajp = &a_digits[i] |
| 1080 __ movl(ESI, Address(ESP, 3 * kWordSize)); // a_digits | 1197 __ movl(ESI, Address(ESP, 3 * kWordSize)); // a_digits |
| 1081 __ leal(ESI, FieldAddress(ESI, EAX, TIMES_4, TypedData::data_offset())); | 1198 __ leal(ESI, FieldAddress(ESI, EAX, TIMES_4, TypedData::data_offset())); |
| 1082 | 1199 |
| 1083 // EAX:EDX = t = x*x + *ajp | 1200 // EDX:EAX = t = x*x + *ajp |
| 1084 __ movl(EAX, EBX); | 1201 __ movl(EAX, EBX); |
| 1085 __ mull(EBX); | 1202 __ mull(EBX); |
| 1086 __ addl(EAX, Address(ESI, 0)); | 1203 __ addl(EAX, Address(ESI, 0)); |
| 1087 __ adcl(EDX, Immediate(0)); | 1204 __ adcl(EDX, Immediate(0)); |
| 1088 | 1205 |
| 1089 // *ajp++ = low32(t) | 1206 // *ajp++ = low32(t) |
| 1090 __ movl(Address(ESI, 0), EAX); | 1207 __ movl(Address(ESI, 0), EAX); |
| 1091 __ addl(ESI, Immediate(kWordSize)); | 1208 __ addl(ESI, Immediate(kWordSize)); |
| 1092 | 1209 |
| 1093 // int n = used - i - 1; // All Smi. | 1210 // int n = used - i - 1; // All Smi. |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1164 | 1281 |
| 1165 // Restore CTX and return. | 1282 // Restore CTX and return. |
| 1166 __ Drop(3); | 1283 __ Drop(3); |
| 1167 __ popl(CTX); | 1284 __ popl(CTX); |
| 1168 __ Bind(&x_zero); | 1285 __ Bind(&x_zero); |
| 1169 // TODO(regis): Confirm that returning Object::null() is not required. | 1286 // TODO(regis): Confirm that returning Object::null() is not required. |
| 1170 __ ret(); | 1287 __ ret(); |
| 1171 } | 1288 } |
| 1172 | 1289 |
| 1173 | 1290 |
| 1291 // TODO(regis): Once this intrinsic is implemented on all architectures, the | |
| 1292 // corresponding Dart method will be untested. Add a test with --no-intrinsify. | |
| 1293 void Intrinsifier::Bigint_estQuotientDigit(Assembler* assembler) { | |
| 1294 // Pseudo code: | |
| 1295 // static void _estQuotientDigit(Uint32List args, Uint32List digits, int i) { | |
| 1296 // uint32_t yt = args[_YT]; // _YT == 0. | |
| 1297 // uint32_t* dp = &digits[i >> 1]; // i is Smi. | |
| 1298 // uint32_t dh = dp[0]; // dh == digits[i >> 1]. | |
| 1299 // uint32_t qd; | |
| 1300 // if (dh == yt) { | |
| 1301 // qd = DIGIT_MASK; | |
| 1302 // } else { | |
| 1303 // dl = dp[-1]; // dl == digits[(i - 1) >> 1]. | |
| 1304 // qd = dh:dl / yt; // No overflow possible, because dh < yt. | |
| 1305 // } | |
| 1306 // args[_QD] = qd; // _QD == 1; | |
| 1307 // } | |
| 1308 | |
| 1309 // EDI = args | |
| 1310 __ movl(EDI, Address(ESP, 3 * kWordSize)); // args | |
| 1311 | |
| 1312 // ECX = yt = args[0] | |
| 1313 __ movl(ECX, FieldAddress(EDI, TypedData::data_offset())); | |
| 1314 | |
| 1315 // EBX = dp = &digits[i >> 1] | |
| 1316 __ movl(EBX, Address(ESP, 2 * kWordSize)); // digits | |
| 1317 __ movl(EAX, Address(ESP, 1 * kWordSize)); // i is Smi | |
| 1318 __ leal(EBX, FieldAddress(EBX, EAX, TIMES_2, TypedData::data_offset())); | |
| 1319 | |
| 1320 // EDX = dh = dp[0] | |
| 1321 __ movl(EDX, Address(EBX, 0)); | |
| 1322 | |
| 1323 // EAX = qd = DIGIT_MASK = -1 | |
| 1324 __ movl(EAX, Immediate(-1)); | |
| 1325 | |
| 1326 // Return qd if dh == yt | |
| 1327 Label return_qd; | |
| 1328 __ cmpl(EDX, ECX); | |
| 1329 __ j(EQUAL, &return_qd, Assembler::kNearJump); | |
| 1330 | |
| 1331 // EAX = dl = dp[-1] | |
| 1332 __ movl(EAX, Address(EBX, -kWordSize)); | |
| 1333 | |
| 1334 // EAX = qd = dh:dl / yt = EDX:EAX / ECX | |
| 1335 __ divl(ECX); | |
| 1336 | |
| 1337 __ Bind(&return_qd); | |
| 1338 // args[1] = qd | |
| 1339 __ movl(FieldAddress(EDI, TypedData::data_offset() + kWordSize), EAX); | |
| 1340 | |
| 1341 // TODO(regis): Confirm that returning Object::null() is not required. | |
| 1342 __ ret(); | |
| 1343 } | |
| 1344 | |
| 1345 | |
| 1346 // TODO(regis): Once this intrinsic is implemented on all architectures, the | |
| 1347 // corresponding Dart method will be untested. Add a test with --no-intrinsify. | |
| 1348 void Intrinsifier::Montgomery_mulMod(Assembler* assembler) { | |
| 1349 // Pseudo code: | |
| 1350 // static void _mulMod(Uint32List args, Uint32List digits, int i) { | |
| 1351 // uint32_t rho = args[_RHO]; // _RHO == 0. | |
| 1352 // uint32_t d = digits[i >> 1]; // i is Smi. | |
| 1353 // uint64_t t = rho*d; | |
| 1354 // args[_MU] = t mod DIGIT_BASE; // _MU == 1. | |
| 1355 // } | |
| 1356 | |
| 1357 // EDI = args | |
| 1358 __ movl(EDI, Address(ESP, 3 * kWordSize)); // args | |
| 1359 | |
| 1360 // ECX = rho = args[0] | |
| 1361 __ movl(ECX, FieldAddress(EDI, TypedData::data_offset())); | |
| 1362 | |
| 1363 // EAX = digits[i >> 1] | |
| 1364 __ movl(EBX, Address(ESP, 2 * kWordSize)); // digits | |
| 1365 __ movl(EAX, Address(ESP, 1 * kWordSize)); // i is Smi | |
| 1366 __ movl(EAX, FieldAddress(EBX, EAX, TIMES_2, TypedData::data_offset())); | |
| 1367 | |
| 1368 // EDX:EAX = t = rho*d | |
| 1369 __ mull(ECX); | |
| 1370 | |
| 1371 // args[1] = t mod DIGIT_BASE = low32(t) | |
| 1372 __ movl(FieldAddress(EDI, TypedData::data_offset() + kWordSize), EAX); | |
| 1373 | |
| 1374 // TODO(regis): Confirm that returning Object::null() is not required. | |
| 1375 __ ret(); | |
| 1376 } | |
| 1377 | |
| 1378 | |
| 1174 // Check if the last argument is a double, jump to label 'is_smi' if smi | 1379 // Check if the last argument is a double, jump to label 'is_smi' if smi |
| 1175 // (easy to convert to double), otherwise jump to label 'not_double_smi', | 1380 // (easy to convert to double), otherwise jump to label 'not_double_smi', |
| 1176 // Returns the last argument in EAX. | 1381 // Returns the last argument in EAX. |
| 1177 static void TestLastArgumentIsDouble(Assembler* assembler, | 1382 static void TestLastArgumentIsDouble(Assembler* assembler, |
| 1178 Label* is_smi, | 1383 Label* is_smi, |
| 1179 Label* not_double_smi) { | 1384 Label* not_double_smi) { |
| 1180 __ movl(EAX, Address(ESP, + 1 * kWordSize)); | 1385 __ movl(EAX, Address(ESP, + 1 * kWordSize)); |
| 1181 __ testl(EAX, Immediate(kSmiTagMask)); | 1386 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1182 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. | 1387 __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi. |
| 1183 __ CompareClassId(EAX, kDoubleCid, EBX); | 1388 __ CompareClassId(EAX, kDoubleCid, EBX); |
| (...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1899 Isolate::current_tag_offset()); | 2104 Isolate::current_tag_offset()); |
| 1900 // Set return value to Isolate::current_tag_. | 2105 // Set return value to Isolate::current_tag_. |
| 1901 __ movl(EAX, current_tag_addr); | 2106 __ movl(EAX, current_tag_addr); |
| 1902 __ ret(); | 2107 __ ret(); |
| 1903 } | 2108 } |
| 1904 | 2109 |
| 1905 #undef __ | 2110 #undef __ |
| 1906 } // namespace dart | 2111 } // namespace dart |
| 1907 | 2112 |
| 1908 #endif // defined TARGET_ARCH_IA32 | 2113 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |