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 #include "vm/aot_optimizer.h" | 5 #include "vm/aot_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 1198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 } | 1209 } |
1210 InvokeMathCFunctionInstr* invoke = | 1210 InvokeMathCFunctionInstr* invoke = |
1211 new(Z) InvokeMathCFunctionInstr(args, | 1211 new(Z) InvokeMathCFunctionInstr(args, |
1212 call->deopt_id(), | 1212 call->deopt_id(), |
1213 recognized_kind, | 1213 recognized_kind, |
1214 call->token_pos()); | 1214 call->token_pos()); |
1215 ReplaceCall(call, invoke); | 1215 ReplaceCall(call, invoke); |
1216 } | 1216 } |
1217 | 1217 |
1218 | 1218 |
1219 static bool IsSupportedByteArrayViewCid(intptr_t cid) { | |
1220 switch (cid) { | |
1221 case kTypedDataInt8ArrayCid: | |
1222 case kTypedDataUint8ArrayCid: | |
1223 case kExternalTypedDataUint8ArrayCid: | |
1224 case kTypedDataUint8ClampedArrayCid: | |
1225 case kExternalTypedDataUint8ClampedArrayCid: | |
1226 case kTypedDataInt16ArrayCid: | |
1227 case kTypedDataUint16ArrayCid: | |
1228 case kTypedDataInt32ArrayCid: | |
1229 case kTypedDataUint32ArrayCid: | |
1230 case kTypedDataFloat32ArrayCid: | |
1231 case kTypedDataFloat64ArrayCid: | |
1232 case kTypedDataFloat32x4ArrayCid: | |
1233 case kTypedDataInt32x4ArrayCid: | |
1234 return true; | |
1235 default: | |
1236 return false; | |
1237 } | |
1238 } | |
1239 | |
1240 | |
1241 // Inline only simple, frequently called core library methods. | 1219 // Inline only simple, frequently called core library methods. |
1242 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1220 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
1243 ASSERT(call->HasICData()); | 1221 ASSERT(call->HasICData()); |
1244 const ICData& ic_data = *call->ic_data(); | 1222 const ICData& ic_data = *call->ic_data(); |
1245 if (ic_data.NumberOfUsedChecks() != 1) { | 1223 if (ic_data.NumberOfUsedChecks() != 1) { |
1246 // No type feedback collected or multiple receivers/targets found. | 1224 // No type feedback collected or multiple receivers/targets found. |
1247 return false; | 1225 return false; |
1248 } | 1226 } |
1249 | 1227 |
1250 Function& target = Function::Handle(Z); | 1228 Function& target = Function::Handle(Z); |
1251 GrowableArray<intptr_t> class_ids; | 1229 GrowableArray<intptr_t> class_ids; |
1252 ic_data.GetCheckAt(0, &class_ids, &target); | 1230 ic_data.GetCheckAt(0, &class_ids, &target); |
1253 MethodRecognizer::Kind recognized_kind = | 1231 MethodRecognizer::Kind recognized_kind = |
1254 MethodRecognizer::RecognizeKind(target); | 1232 MethodRecognizer::RecognizeKind(target); |
1255 | 1233 |
1256 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) || | |
1257 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) || | |
1258 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) || | |
1259 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) || | |
1260 (recognized_kind == MethodRecognizer::kGrowableArraySetData) || | |
1261 (recognized_kind == MethodRecognizer::kGrowableArraySetLength) || | |
1262 (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) { | |
1263 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1264 flow_graph_, current_iterator(), call); | |
1265 } | |
1266 | |
1267 if (recognized_kind == MethodRecognizer::kStringBaseCharAt) { | |
1268 ASSERT((class_ids[0] == kOneByteStringCid) || | |
1269 (class_ids[0] == kTwoByteStringCid) || | |
1270 (class_ids[0] == kExternalOneByteStringCid) || | |
1271 (class_ids[0] == kExternalTwoByteStringCid)); | |
1272 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1273 flow_graph_, current_iterator(), call); | |
1274 } | |
1275 | |
1276 if (class_ids[0] == kOneByteStringCid) { | |
1277 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | |
1278 // This is an internal method, no need to check argument types nor | |
1279 // range. | |
1280 Definition* str = call->ArgumentAt(0); | |
1281 Definition* index = call->ArgumentAt(1); | |
1282 Definition* value = call->ArgumentAt(2); | |
1283 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr( | |
1284 new(Z) Value(str), | |
1285 new(Z) Value(index), | |
1286 new(Z) Value(value), | |
1287 kNoStoreBarrier, | |
1288 1, // Index scale | |
1289 kOneByteStringCid, | |
1290 call->deopt_id(), | |
1291 call->token_pos()); | |
1292 ReplaceCall(call, store_op); | |
1293 return true; | |
1294 } | |
1295 return false; | |
1296 } | |
1297 | |
1298 if (CanUnboxDouble() && | 1234 if (CanUnboxDouble() && |
1299 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { | 1235 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { |
1300 if (class_ids[0] == kSmiCid) { | 1236 if (class_ids[0] == kSmiCid) { |
1301 AddReceiverCheck(call); | 1237 AddReceiverCheck(call); |
1302 ReplaceCall(call, | 1238 ReplaceCall(call, |
1303 new(Z) SmiToDoubleInstr( | 1239 new(Z) SmiToDoubleInstr( |
1304 new(Z) Value(call->ArgumentAt(0)), | 1240 new(Z) Value(call->ArgumentAt(0)), |
1305 call->token_pos())); | 1241 call->token_pos())); |
1306 return true; | 1242 return true; |
1307 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { | 1243 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1346 if (!TargetCPUFeatures::double_truncate_round_supported()) { | 1282 if (!TargetCPUFeatures::double_truncate_round_supported()) { |
1347 ReplaceWithMathCFunction(call, recognized_kind); | 1283 ReplaceWithMathCFunction(call, recognized_kind); |
1348 } else { | 1284 } else { |
1349 AddReceiverCheck(call); | 1285 AddReceiverCheck(call); |
1350 DoubleToDoubleInstr* d2d_instr = | 1286 DoubleToDoubleInstr* d2d_instr = |
1351 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), | 1287 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), |
1352 recognized_kind, call->deopt_id()); | 1288 recognized_kind, call->deopt_id()); |
1353 ReplaceCall(call, d2d_instr); | 1289 ReplaceCall(call, d2d_instr); |
1354 } | 1290 } |
1355 return true; | 1291 return true; |
1356 case MethodRecognizer::kDoubleAdd: | |
1357 case MethodRecognizer::kDoubleSub: | |
1358 case MethodRecognizer::kDoubleMul: | |
1359 case MethodRecognizer::kDoubleDiv: | |
1360 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1361 flow_graph_, current_iterator(), call); | |
1362 default: | 1292 default: |
1363 // Unsupported method. | 1293 break; |
1364 return false; | |
1365 } | 1294 } |
1366 } | 1295 } |
1367 | 1296 |
1368 if (IsSupportedByteArrayViewCid(class_ids[0]) || | 1297 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
1369 (class_ids[0] == kFloat32x4Cid) || | 1298 flow_graph_, current_iterator(), call); |
1370 (class_ids[0] == kInt32x4Cid) || | |
1371 (class_ids[0] == kFloat64x2Cid)) { | |
1372 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | |
1373 flow_graph_, current_iterator(), call); | |
1374 } | |
1375 | |
1376 return false; | |
1377 } | 1299 } |
1378 | 1300 |
1379 | 1301 |
1380 // If type tests specified by 'ic_data' do not depend on type arguments, | 1302 // If type tests specified by 'ic_data' do not depend on type arguments, |
1381 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 1303 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
1382 // If all tests yield the same result, return it otherwise return Bool::null. | 1304 // If all tests yield the same result, return it otherwise return Bool::null. |
1383 // If no mapping is possible, 'results' has less than | 1305 // If no mapping is possible, 'results' has less than |
1384 // (ic_data.NumberOfChecks() * 2) entries | 1306 // (ic_data.NumberOfChecks() * 2) entries |
1385 // An instance-of test returning all same results can be converted to a class | 1307 // An instance-of test returning all same results can be converted to a class |
1386 // check. | 1308 // check. |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2023 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 1945 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
2024 /* with_checks = */ true, | 1946 /* with_checks = */ true, |
2025 /* complete = */ false); | 1947 /* complete = */ false); |
2026 instr->ReplaceWith(call, current_iterator()); | 1948 instr->ReplaceWith(call, current_iterator()); |
2027 return; | 1949 return; |
2028 } | 1950 } |
2029 } | 1951 } |
2030 | 1952 |
2031 | 1953 |
2032 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1954 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
2033 if (!CanUnboxDouble()) { | 1955 if (!IsAllowedForInlining(call->deopt_id())) { |
| 1956 // Inlining disabled after a speculative inlining attempt. |
2034 return; | 1957 return; |
2035 } | 1958 } |
2036 MethodRecognizer::Kind recognized_kind = | 1959 MethodRecognizer::Kind recognized_kind = |
2037 MethodRecognizer::RecognizeKind(call->function()); | 1960 MethodRecognizer::RecognizeKind(call->function()); |
2038 MathUnaryInstr::MathUnaryKind unary_kind; | |
2039 switch (recognized_kind) { | 1961 switch (recognized_kind) { |
2040 case MethodRecognizer::kMathSqrt: | 1962 case MethodRecognizer::kObjectConstructor: |
2041 unary_kind = MathUnaryInstr::kSqrt; | 1963 case MethodRecognizer::kObjectArrayAllocate: |
2042 break; | |
2043 case MethodRecognizer::kMathSin: | |
2044 unary_kind = MathUnaryInstr::kSin; | |
2045 break; | |
2046 case MethodRecognizer::kMathCos: | |
2047 unary_kind = MathUnaryInstr::kCos; | |
2048 break; | |
2049 default: | |
2050 unary_kind = MathUnaryInstr::kIllegal; | |
2051 break; | |
2052 } | |
2053 if (unary_kind != MathUnaryInstr::kIllegal) { | |
2054 ASSERT(FLAG_precompiled_mode); | |
2055 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | |
2056 return; | |
2057 } | |
2058 | |
2059 switch (recognized_kind) { | |
2060 case MethodRecognizer::kFloat32x4Zero: | 1964 case MethodRecognizer::kFloat32x4Zero: |
2061 case MethodRecognizer::kFloat32x4Splat: | 1965 case MethodRecognizer::kFloat32x4Splat: |
2062 case MethodRecognizer::kFloat32x4Constructor: | 1966 case MethodRecognizer::kFloat32x4Constructor: |
2063 case MethodRecognizer::kFloat32x4FromFloat64x2: | 1967 case MethodRecognizer::kFloat32x4FromFloat64x2: |
2064 case MethodRecognizer::kFloat64x2Constructor: | 1968 case MethodRecognizer::kFloat64x2Constructor: |
2065 case MethodRecognizer::kFloat64x2Zero: | 1969 case MethodRecognizer::kFloat64x2Zero: |
2066 case MethodRecognizer::kFloat64x2Splat: | 1970 case MethodRecognizer::kFloat64x2Splat: |
2067 case MethodRecognizer::kFloat64x2FromFloat32x4: | 1971 case MethodRecognizer::kFloat64x2FromFloat32x4: |
2068 case MethodRecognizer::kInt32x4BoolConstructor: | 1972 case MethodRecognizer::kInt32x4BoolConstructor: |
2069 case MethodRecognizer::kInt32x4Constructor: | 1973 case MethodRecognizer::kInt32x4Constructor: |
2070 if (!ShouldInlineSimd() || !IsAllowedForInlining(call->deopt_id())) { | 1974 case MethodRecognizer::kMathSqrt: |
2071 return; | 1975 case MethodRecognizer::kMathDoublePow: |
2072 } | 1976 case MethodRecognizer::kMathSin: |
| 1977 case MethodRecognizer::kMathCos: |
| 1978 case MethodRecognizer::kMathTan: |
| 1979 case MethodRecognizer::kMathAsin: |
| 1980 case MethodRecognizer::kMathAcos: |
| 1981 case MethodRecognizer::kMathAtan: |
| 1982 case MethodRecognizer::kMathAtan2: |
2073 FlowGraphInliner::TryReplaceStaticCallWithInline( | 1983 FlowGraphInliner::TryReplaceStaticCallWithInline( |
2074 flow_graph_, current_iterator(), call); | 1984 flow_graph_, current_iterator(), call); |
2075 break; | 1985 break; |
2076 case MethodRecognizer::kObjectConstructor: { | |
2077 // Remove the original push arguments. | |
2078 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
2079 PushArgumentInstr* push = call->PushArgumentAt(i); | |
2080 push->ReplaceUsesWith(push->value()->definition()); | |
2081 push->RemoveFromGraph(); | |
2082 } | |
2083 // Manually replace call with global null constant. ReplaceCall can't | |
2084 // be used for definitions that are already in the graph. | |
2085 call->ReplaceUsesWith(flow_graph_->constant_null()); | |
2086 ASSERT(current_iterator()->Current() == call); | |
2087 current_iterator()->RemoveCurrentFromGraph(); | |
2088 break; | |
2089 } | |
2090 case MethodRecognizer::kMathMin: | 1986 case MethodRecognizer::kMathMin: |
2091 case MethodRecognizer::kMathMax: { | 1987 case MethodRecognizer::kMathMax: { |
2092 // We can handle only monomorphic min/max call sites with both arguments | 1988 // We can handle only monomorphic min/max call sites with both arguments |
2093 // being either doubles or smis. | 1989 // being either doubles or smis. |
2094 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 1990 if (CanUnboxDouble() && |
| 1991 call->HasICData() && |
| 1992 (call->ic_data()->NumberOfChecks() == 1)) { |
2095 const ICData& ic_data = *call->ic_data(); | 1993 const ICData& ic_data = *call->ic_data(); |
2096 intptr_t result_cid = kIllegalCid; | 1994 intptr_t result_cid = kIllegalCid; |
2097 if (ICDataHasReceiverArgumentClassIds(ic_data, | 1995 if (ICDataHasReceiverArgumentClassIds(ic_data, |
2098 kDoubleCid, kDoubleCid)) { | 1996 kDoubleCid, kDoubleCid)) { |
2099 result_cid = kDoubleCid; | 1997 result_cid = kDoubleCid; |
2100 } else if (ICDataHasReceiverArgumentClassIds(ic_data, | 1998 } else if (ICDataHasReceiverArgumentClassIds(ic_data, |
2101 kSmiCid, kSmiCid)) { | 1999 kSmiCid, kSmiCid)) { |
2102 result_cid = kSmiCid; | 2000 result_cid = kSmiCid; |
2103 } | 2001 } |
2104 if (result_cid != kIllegalCid) { | 2002 if (result_cid != kIllegalCid) { |
(...skipping 13 matching lines...) Expand all Loading... |
2118 AddCheckClass(min_max->right()->definition(), | 2016 AddCheckClass(min_max->right()->definition(), |
2119 unary_checks, | 2017 unary_checks, |
2120 call->deopt_id(), | 2018 call->deopt_id(), |
2121 call->env(), | 2019 call->env(), |
2122 call); | 2020 call); |
2123 ReplaceCall(call, min_max); | 2021 ReplaceCall(call, min_max); |
2124 } | 2022 } |
2125 } | 2023 } |
2126 break; | 2024 break; |
2127 } | 2025 } |
2128 case MethodRecognizer::kMathDoublePow: | |
2129 case MethodRecognizer::kMathTan: | |
2130 case MethodRecognizer::kMathAsin: | |
2131 case MethodRecognizer::kMathAcos: | |
2132 case MethodRecognizer::kMathAtan: | |
2133 case MethodRecognizer::kMathAtan2: { | |
2134 ASSERT(FLAG_precompiled_mode); | |
2135 // No UnboxDouble instructions allowed. | |
2136 return; | |
2137 } | |
2138 case MethodRecognizer::kDoubleFromInteger: { | 2026 case MethodRecognizer::kDoubleFromInteger: { |
2139 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 2027 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
2140 const ICData& ic_data = *call->ic_data(); | 2028 const ICData& ic_data = *call->ic_data(); |
2141 if (CanUnboxDouble()) { | 2029 if (CanUnboxDouble()) { |
2142 if (ArgIsAlways(kSmiCid, ic_data, 1)) { | 2030 if (ArgIsAlways(kSmiCid, ic_data, 1)) { |
2143 Definition* arg = call->ArgumentAt(1); | 2031 Definition* arg = call->ArgumentAt(1); |
2144 AddCheckSmi(arg, call->deopt_id(), call->env(), call); | 2032 AddCheckSmi(arg, call->deopt_id(), call->env(), call); |
2145 ReplaceCall(call, | 2033 ReplaceCall(call, |
2146 new(Z) SmiToDoubleInstr(new(Z) Value(arg), | 2034 new(Z) SmiToDoubleInstr(new(Z) Value(arg), |
2147 call->token_pos())); | 2035 call->token_pos())); |
2148 } else if (ArgIsAlways(kMintCid, ic_data, 1) && | 2036 } else if (ArgIsAlways(kMintCid, ic_data, 1) && |
2149 CanConvertUnboxedMintToDouble()) { | 2037 CanConvertUnboxedMintToDouble()) { |
2150 Definition* arg = call->ArgumentAt(1); | 2038 Definition* arg = call->ArgumentAt(1); |
2151 ReplaceCall(call, | 2039 ReplaceCall(call, |
2152 new(Z) MintToDoubleInstr(new(Z) Value(arg), | 2040 new(Z) MintToDoubleInstr(new(Z) Value(arg), |
2153 call->deopt_id())); | 2041 call->deopt_id())); |
2154 } | 2042 } |
2155 } | 2043 } |
2156 } | 2044 } |
2157 break; | 2045 break; |
2158 } | 2046 } |
2159 default: { | 2047 default: |
2160 if (call->function().IsFactory()) { | 2048 break; |
2161 const Class& function_class = | |
2162 Class::Handle(Z, call->function().Owner()); | |
2163 if ((function_class.library() == Library::CoreLibrary()) || | |
2164 (function_class.library() == Library::TypedDataLibrary())) { | |
2165 intptr_t cid = FactoryRecognizer::ResultCid(call->function()); | |
2166 switch (cid) { | |
2167 case kArrayCid: { | |
2168 Value* type = new(Z) Value(call->ArgumentAt(0)); | |
2169 Value* num_elements = new(Z) Value(call->ArgumentAt(1)); | |
2170 if (num_elements->BindsToConstant() && | |
2171 num_elements->BoundConstant().IsSmi()) { | |
2172 intptr_t length = | |
2173 Smi::Cast(num_elements->BoundConstant()).Value(); | |
2174 if (length >= 0 && length <= Array::kMaxElements) { | |
2175 CreateArrayInstr* create_array = | |
2176 new(Z) CreateArrayInstr( | |
2177 call->token_pos(), type, num_elements); | |
2178 ReplaceCall(call, create_array); | |
2179 } | |
2180 } | |
2181 } | |
2182 default: | |
2183 break; | |
2184 } | |
2185 } | |
2186 } | |
2187 } | |
2188 } | 2049 } |
2189 } | 2050 } |
2190 | 2051 |
2191 | 2052 |
2192 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 2053 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
2193 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 2054 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
2194 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 2055 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
2195 if (!instr->can_pack_into_smi()) | 2056 if (!instr->can_pack_into_smi()) |
2196 instr->set_representation(kUnboxedMint); | 2057 instr->set_representation(kUnboxedMint); |
2197 #endif | 2058 #endif |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2272 flow_graph_->InsertBefore(check, new_check, | 2133 flow_graph_->InsertBefore(check, new_check, |
2273 check->env(), FlowGraph::kEffect); | 2134 check->env(), FlowGraph::kEffect); |
2274 current_iterator()->RemoveCurrentFromGraph(); | 2135 current_iterator()->RemoveCurrentFromGraph(); |
2275 } | 2136 } |
2276 } | 2137 } |
2277 } | 2138 } |
2278 } | 2139 } |
2279 | 2140 |
2280 | 2141 |
2281 } // namespace dart | 2142 } // namespace dart |
OLD | NEW |