Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(468)

Side by Side Diff: runtime/vm/jit_optimizer.cc

Issue 2273943002: VM: More refactoring of recognized methods inlining. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/intermediate_language_x64.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "vm/jit_optimizer.h" 5 #include "vm/jit_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after
1215 } 1215 }
1216 InvokeMathCFunctionInstr* invoke = 1216 InvokeMathCFunctionInstr* invoke =
1217 new(Z) InvokeMathCFunctionInstr(args, 1217 new(Z) InvokeMathCFunctionInstr(args,
1218 call->deopt_id(), 1218 call->deopt_id(),
1219 recognized_kind, 1219 recognized_kind,
1220 call->token_pos()); 1220 call->token_pos());
1221 ReplaceCall(call, invoke); 1221 ReplaceCall(call, invoke);
1222 } 1222 }
1223 1223
1224 1224
1225 static bool IsSupportedByteArrayViewCid(intptr_t cid) {
1226 switch (cid) {
1227 case kTypedDataInt8ArrayCid:
1228 case kTypedDataUint8ArrayCid:
1229 case kExternalTypedDataUint8ArrayCid:
1230 case kTypedDataUint8ClampedArrayCid:
1231 case kExternalTypedDataUint8ClampedArrayCid:
1232 case kTypedDataInt16ArrayCid:
1233 case kTypedDataUint16ArrayCid:
1234 case kTypedDataInt32ArrayCid:
1235 case kTypedDataUint32ArrayCid:
1236 case kTypedDataFloat32ArrayCid:
1237 case kTypedDataFloat64ArrayCid:
1238 case kTypedDataFloat32x4ArrayCid:
1239 case kTypedDataInt32x4ArrayCid:
1240 return true;
1241 default:
1242 return false;
1243 }
1244 }
1245
1246
1247 // Inline only simple, frequently called core library methods. 1225 // Inline only simple, frequently called core library methods.
1248 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1226 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1249 ASSERT(call->HasICData()); 1227 ASSERT(call->HasICData());
1250 const ICData& ic_data = *call->ic_data(); 1228 const ICData& ic_data = *call->ic_data();
1251 if (ic_data.NumberOfUsedChecks() != 1) { 1229 if (ic_data.NumberOfUsedChecks() != 1) {
1252 // No type feedback collected or multiple targets found. 1230 // No type feedback collected or multiple targets found.
1253 return false; 1231 return false;
1254 } 1232 }
1255 1233
1256 Function& target = Function::Handle(Z); 1234 Function& target = Function::Handle(Z);
1257 GrowableArray<intptr_t> class_ids; 1235 GrowableArray<intptr_t> class_ids;
1258 ic_data.GetCheckAt(0, &class_ids, &target); 1236 ic_data.GetCheckAt(0, &class_ids, &target);
1259 MethodRecognizer::Kind recognized_kind = 1237 MethodRecognizer::Kind recognized_kind =
1260 MethodRecognizer::RecognizeKind(target); 1238 MethodRecognizer::RecognizeKind(target);
1261 1239
1262 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) ||
1263 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) ||
1264 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
1265 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
1266 (recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
1267 (recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
1268 (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
1269 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1270 flow_graph_, current_iterator(), call);
1271 }
1272
1273 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
1274 ASSERT((class_ids[0] == kOneByteStringCid) ||
1275 (class_ids[0] == kTwoByteStringCid) ||
1276 (class_ids[0] == kExternalOneByteStringCid) ||
1277 (class_ids[0] == kExternalTwoByteStringCid));
1278 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1279 flow_graph_, current_iterator(), call);
1280 }
1281
1282 if (class_ids[0] == kOneByteStringCid) {
1283 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
1284 // This is an internal method, no need to check argument types nor
1285 // range.
1286 Definition* str = call->ArgumentAt(0);
1287 Definition* index = call->ArgumentAt(1);
1288 Definition* value = call->ArgumentAt(2);
1289 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
1290 new(Z) Value(str),
1291 new(Z) Value(index),
1292 new(Z) Value(value),
1293 kNoStoreBarrier,
1294 1, // Index scale
1295 kOneByteStringCid,
1296 call->deopt_id(),
1297 call->token_pos());
1298 ReplaceCall(call, store_op);
1299 return true;
1300 }
1301 return false;
1302 }
1303
1304 if (CanUnboxDouble() && 1240 if (CanUnboxDouble() &&
1305 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { 1241 (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
1306 if (class_ids[0] == kSmiCid) { 1242 if (class_ids[0] == kSmiCid) {
1307 AddReceiverCheck(call); 1243 AddReceiverCheck(call);
1308 ReplaceCall(call, 1244 ReplaceCall(call,
1309 new(Z) SmiToDoubleInstr( 1245 new(Z) SmiToDoubleInstr(
1310 new(Z) Value(call->ArgumentAt(0)), 1246 new(Z) Value(call->ArgumentAt(0)),
1311 call->token_pos())); 1247 call->token_pos()));
1312 return true; 1248 return true;
1313 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { 1249 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 if (!TargetCPUFeatures::double_truncate_round_supported()) { 1288 if (!TargetCPUFeatures::double_truncate_round_supported()) {
1353 ReplaceWithMathCFunction(call, recognized_kind); 1289 ReplaceWithMathCFunction(call, recognized_kind);
1354 } else { 1290 } else {
1355 AddReceiverCheck(call); 1291 AddReceiverCheck(call);
1356 DoubleToDoubleInstr* d2d_instr = 1292 DoubleToDoubleInstr* d2d_instr =
1357 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), 1293 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
1358 recognized_kind, call->deopt_id()); 1294 recognized_kind, call->deopt_id());
1359 ReplaceCall(call, d2d_instr); 1295 ReplaceCall(call, d2d_instr);
1360 } 1296 }
1361 return true; 1297 return true;
1362 case MethodRecognizer::kDoubleAdd:
1363 case MethodRecognizer::kDoubleSub:
1364 case MethodRecognizer::kDoubleMul:
1365 case MethodRecognizer::kDoubleDiv:
1366 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1367 flow_graph_, current_iterator(), call);
1368 default: 1298 default:
1369 // Unsupported method. 1299 break;
1370 return false;
1371 } 1300 }
1372 } 1301 }
1373 1302
1374 if (IsSupportedByteArrayViewCid(class_ids[0]) || 1303 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1375 (class_ids[0] == kFloat32x4Cid) || 1304 flow_graph_, current_iterator(), call);
1376 (class_ids[0] == kInt32x4Cid) ||
1377 (class_ids[0] == kFloat64x2Cid)) {
1378 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1379 flow_graph_, current_iterator(), call);
1380 }
1381
1382 return false;
1383 } 1305 }
1384 1306
1385 1307
1386 // If type tests specified by 'ic_data' do not depend on type arguments, 1308 // If type tests specified by 'ic_data' do not depend on type arguments,
1387 // return mapping cid->result in 'results' (i : cid; i + 1: result). 1309 // return mapping cid->result in 'results' (i : cid; i + 1: result).
1388 // If all tests yield the same result, return it otherwise return Bool::null. 1310 // If all tests yield the same result, return it otherwise return Bool::null.
1389 // If no mapping is possible, 'results' is empty. 1311 // If no mapping is possible, 'results' is empty.
1390 // An instance-of test returning all same results can be converted to a class 1312 // An instance-of test returning all same results can be converted to a class
1391 // check. 1313 // check.
1392 RawBool* JitOptimizer::InstanceOfAsBool( 1314 RawBool* JitOptimizer::InstanceOfAsBool(
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
1816 PolymorphicInstanceCallInstr* call = 1738 PolymorphicInstanceCallInstr* call =
1817 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1739 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1818 call_with_checks, 1740 call_with_checks,
1819 /* complete = */ false); 1741 /* complete = */ false);
1820 instr->ReplaceWith(call, current_iterator()); 1742 instr->ReplaceWith(call, current_iterator());
1821 } 1743 }
1822 } 1744 }
1823 1745
1824 1746
1825 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { 1747 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
1826 if (!CanUnboxDouble()) {
1827 return;
1828 }
1829 MethodRecognizer::Kind recognized_kind = 1748 MethodRecognizer::Kind recognized_kind =
1830 MethodRecognizer::RecognizeKind(call->function()); 1749 MethodRecognizer::RecognizeKind(call->function());
1831 MathUnaryInstr::MathUnaryKind unary_kind;
1832 switch (recognized_kind) { 1750 switch (recognized_kind) {
1833 case MethodRecognizer::kMathSqrt: 1751 case MethodRecognizer::kObjectConstructor:
1834 unary_kind = MathUnaryInstr::kSqrt; 1752 case MethodRecognizer::kObjectArrayAllocate:
1835 break;
1836 case MethodRecognizer::kMathSin:
1837 unary_kind = MathUnaryInstr::kSin;
1838 break;
1839 case MethodRecognizer::kMathCos:
1840 unary_kind = MathUnaryInstr::kCos;
1841 break;
1842 default:
1843 unary_kind = MathUnaryInstr::kIllegal;
1844 break;
1845 }
1846 if (unary_kind != MathUnaryInstr::kIllegal) {
1847 MathUnaryInstr* math_unary =
1848 new(Z) MathUnaryInstr(unary_kind,
1849 new(Z) Value(call->ArgumentAt(0)),
1850 call->deopt_id());
1851 ReplaceCall(call, math_unary);
1852 return;
1853 }
1854 switch (recognized_kind) {
1855 case MethodRecognizer::kFloat32x4Zero: 1753 case MethodRecognizer::kFloat32x4Zero:
1856 case MethodRecognizer::kFloat32x4Splat: 1754 case MethodRecognizer::kFloat32x4Splat:
1857 case MethodRecognizer::kFloat32x4Constructor: 1755 case MethodRecognizer::kFloat32x4Constructor:
1858 case MethodRecognizer::kFloat32x4FromFloat64x2: 1756 case MethodRecognizer::kFloat32x4FromFloat64x2:
1859 case MethodRecognizer::kFloat64x2Constructor: 1757 case MethodRecognizer::kFloat64x2Constructor:
1860 case MethodRecognizer::kFloat64x2Zero: 1758 case MethodRecognizer::kFloat64x2Zero:
1861 case MethodRecognizer::kFloat64x2Splat: 1759 case MethodRecognizer::kFloat64x2Splat:
1862 case MethodRecognizer::kFloat64x2FromFloat32x4: 1760 case MethodRecognizer::kFloat64x2FromFloat32x4:
1863 case MethodRecognizer::kInt32x4BoolConstructor: 1761 case MethodRecognizer::kInt32x4BoolConstructor:
1864 case MethodRecognizer::kInt32x4Constructor: 1762 case MethodRecognizer::kInt32x4Constructor:
1763 case MethodRecognizer::kMathSqrt:
1764 case MethodRecognizer::kMathDoublePow:
1765 case MethodRecognizer::kMathSin:
1766 case MethodRecognizer::kMathCos:
1767 case MethodRecognizer::kMathTan:
1768 case MethodRecognizer::kMathAsin:
1769 case MethodRecognizer::kMathAcos:
1770 case MethodRecognizer::kMathAtan:
1771 case MethodRecognizer::kMathAtan2:
1865 FlowGraphInliner::TryReplaceStaticCallWithInline( 1772 FlowGraphInliner::TryReplaceStaticCallWithInline(
1866 flow_graph_, current_iterator(), call); 1773 flow_graph_, current_iterator(), call);
1867 break; 1774 break;
1868 case MethodRecognizer::kObjectConstructor: {
1869 // Remove the original push arguments.
1870 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1871 PushArgumentInstr* push = call->PushArgumentAt(i);
1872 push->ReplaceUsesWith(push->value()->definition());
1873 push->RemoveFromGraph();
1874 }
1875 // Manually replace call with global null constant. ReplaceCall can't
1876 // be used for definitions that are already in the graph.
1877 call->ReplaceUsesWith(flow_graph_->constant_null());
1878 ASSERT(current_iterator()->Current() == call);
1879 current_iterator()->RemoveCurrentFromGraph();
1880 break;
1881 }
1882 case MethodRecognizer::kMathMin: 1775 case MethodRecognizer::kMathMin:
1883 case MethodRecognizer::kMathMax: { 1776 case MethodRecognizer::kMathMax: {
1884 // We can handle only monomorphic min/max call sites with both arguments 1777 // We can handle only monomorphic min/max call sites with both arguments
1885 // being either doubles or smis. 1778 // being either doubles or smis.
1886 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 1779 if (CanUnboxDouble() &&
1780 call->HasICData() &&
1781 (call->ic_data()->NumberOfChecks() == 1)) {
1887 const ICData& ic_data = *call->ic_data(); 1782 const ICData& ic_data = *call->ic_data();
1888 intptr_t result_cid = kIllegalCid; 1783 intptr_t result_cid = kIllegalCid;
1889 if (ICDataHasReceiverArgumentClassIds(ic_data, 1784 if (ICDataHasReceiverArgumentClassIds(ic_data,
1890 kDoubleCid, kDoubleCid)) { 1785 kDoubleCid, kDoubleCid)) {
1891 result_cid = kDoubleCid; 1786 result_cid = kDoubleCid;
1892 } else if (ICDataHasReceiverArgumentClassIds(ic_data, 1787 } else if (ICDataHasReceiverArgumentClassIds(ic_data,
1893 kSmiCid, kSmiCid)) { 1788 kSmiCid, kSmiCid)) {
1894 result_cid = kSmiCid; 1789 result_cid = kSmiCid;
1895 } 1790 }
1896 if (result_cid != kIllegalCid) { 1791 if (result_cid != kIllegalCid) {
(...skipping 13 matching lines...) Expand all
1910 AddCheckClass(min_max->right()->definition(), 1805 AddCheckClass(min_max->right()->definition(),
1911 unary_checks, 1806 unary_checks,
1912 call->deopt_id(), 1807 call->deopt_id(),
1913 call->env(), 1808 call->env(),
1914 call); 1809 call);
1915 ReplaceCall(call, min_max); 1810 ReplaceCall(call, min_max);
1916 } 1811 }
1917 } 1812 }
1918 break; 1813 break;
1919 } 1814 }
1920 case MethodRecognizer::kMathDoublePow: 1815
1921 case MethodRecognizer::kMathTan:
1922 case MethodRecognizer::kMathAsin:
1923 case MethodRecognizer::kMathAcos:
1924 case MethodRecognizer::kMathAtan:
1925 case MethodRecognizer::kMathAtan2: {
1926 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
1927 // instructions contain type checks and conversions to double.
1928 ZoneGrowableArray<Value*>* args =
1929 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1930 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1931 args->Add(new(Z) Value(call->ArgumentAt(i)));
1932 }
1933 InvokeMathCFunctionInstr* invoke =
1934 new(Z) InvokeMathCFunctionInstr(args,
1935 call->deopt_id(),
1936 recognized_kind,
1937 call->token_pos());
1938 ReplaceCall(call, invoke);
1939 break;
1940 }
1941 case MethodRecognizer::kDoubleFromInteger: { 1816 case MethodRecognizer::kDoubleFromInteger: {
1942 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 1817 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
1943 const ICData& ic_data = *call->ic_data(); 1818 const ICData& ic_data = *call->ic_data();
1944 if (CanUnboxDouble()) { 1819 if (CanUnboxDouble()) {
1945 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 1820 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
1946 Definition* arg = call->ArgumentAt(1); 1821 Definition* arg = call->ArgumentAt(1);
1947 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 1822 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
1948 ReplaceCall(call, 1823 ReplaceCall(call,
1949 new(Z) SmiToDoubleInstr(new(Z) Value(arg), 1824 new(Z) SmiToDoubleInstr(new(Z) Value(arg),
1950 call->token_pos())); 1825 call->token_pos()));
1951 } else if (ArgIsAlways(kMintCid, ic_data, 1) && 1826 } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
1952 CanConvertUnboxedMintToDouble()) { 1827 CanConvertUnboxedMintToDouble()) {
1953 Definition* arg = call->ArgumentAt(1); 1828 Definition* arg = call->ArgumentAt(1);
1954 ReplaceCall(call, 1829 ReplaceCall(call,
1955 new(Z) MintToDoubleInstr(new(Z) Value(arg), 1830 new(Z) MintToDoubleInstr(new(Z) Value(arg),
1956 call->deopt_id())); 1831 call->deopt_id()));
1957 } 1832 }
1958 } 1833 }
1959 } 1834 }
1960 break; 1835 break;
1961 } 1836 }
1962 default: { 1837 default:
1963 if (call->function().IsFactory()) { 1838 break;
1964 const Class& function_class =
1965 Class::Handle(Z, call->function().Owner());
1966 if ((function_class.library() == Library::CoreLibrary()) ||
1967 (function_class.library() == Library::TypedDataLibrary())) {
1968 intptr_t cid = FactoryRecognizer::ResultCid(call->function());
1969 switch (cid) {
1970 case kArrayCid: {
1971 Value* type = new(Z) Value(call->ArgumentAt(0));
1972 Value* num_elements = new(Z) Value(call->ArgumentAt(1));
1973 if (num_elements->BindsToConstant() &&
1974 num_elements->BoundConstant().IsSmi()) {
1975 intptr_t length =
1976 Smi::Cast(num_elements->BoundConstant()).Value();
1977 if (length >= 0 && length <= Array::kMaxElements) {
1978 CreateArrayInstr* create_array =
1979 new(Z) CreateArrayInstr(
1980 call->token_pos(), type, num_elements);
1981 ReplaceCall(call, create_array);
1982 }
1983 }
1984 }
1985 default:
1986 break;
1987 }
1988 }
1989 }
1990 }
1991 } 1839 }
1992 } 1840 }
1993 1841
1994 1842
1995 void JitOptimizer::VisitStoreInstanceField( 1843 void JitOptimizer::VisitStoreInstanceField(
1996 StoreInstanceFieldInstr* instr) { 1844 StoreInstanceFieldInstr* instr) {
1997 if (instr->IsUnboxedStore()) { 1845 if (instr->IsUnboxedStore()) {
1998 // Determine if this field should be unboxed based on the usage of getter 1846 // Determine if this field should be unboxed based on the usage of getter
1999 // and setter functions: The heuristic requires that the setter has a 1847 // and setter functions: The heuristic requires that the setter has a
2000 // usage count of at least 1/kGetterSetterRatio of the getter usage count. 1848 // usage count of at least 1/kGetterSetterRatio of the getter usage count.
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
2165 2013
2166 // Discard the environment from the original instruction because the store 2014 // Discard the environment from the original instruction because the store
2167 // can't deoptimize. 2015 // can't deoptimize.
2168 instr->RemoveEnvironment(); 2016 instr->RemoveEnvironment();
2169 ReplaceCall(instr, store); 2017 ReplaceCall(instr, store);
2170 return true; 2018 return true;
2171 } 2019 }
2172 2020
2173 2021
2174 } // namespace dart 2022 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_x64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698