OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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/globals.h" // Needed here to get TARGET_ARCH_DBC. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_DBC. |
6 #if defined(TARGET_ARCH_DBC) | 6 #if defined(TARGET_ARCH_DBC) |
7 | 7 |
8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
9 | 9 |
10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 | 27 |
28 DECLARE_FLAG(bool, emit_edge_counters); | 28 DECLARE_FLAG(bool, emit_edge_counters); |
29 DECLARE_FLAG(int, optimization_counter_threshold); | 29 DECLARE_FLAG(int, optimization_counter_threshold); |
30 | 30 |
31 // List of instructions that are still unimplemented by DBC backend. | 31 // List of instructions that are still unimplemented by DBC backend. |
32 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ | 32 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ |
33 M(LoadCodeUnits) \ | 33 M(LoadCodeUnits) \ |
34 M(LoadUntagged) \ | 34 M(LoadUntagged) \ |
35 M(AllocateUninitializedContext) \ | 35 M(AllocateUninitializedContext) \ |
36 M(BinaryInt32Op) \ | 36 M(BinaryInt32Op) \ |
37 M(UnaryDoubleOp) \ | |
38 M(SmiToDouble) \ | |
39 M(Int32ToDouble) \ | 37 M(Int32ToDouble) \ |
40 M(MintToDouble) \ | |
41 M(DoubleToInteger) \ | 38 M(DoubleToInteger) \ |
42 M(DoubleToSmi) \ | 39 M(DoubleToSmi) \ |
43 M(DoubleToDouble) \ | 40 M(DoubleToDouble) \ |
44 M(DoubleToFloat) \ | 41 M(DoubleToFloat) \ |
45 M(FloatToDouble) \ | 42 M(FloatToDouble) \ |
46 M(UnboxedConstant) \ | 43 M(UnboxedConstant) \ |
47 M(BinaryDoubleOp) \ | |
48 M(MathUnary) \ | 44 M(MathUnary) \ |
49 M(MathMinMax) \ | 45 M(MathMinMax) \ |
50 M(Box) \ | |
51 M(Unbox) \ | |
52 M(BoxInt64) \ | 46 M(BoxInt64) \ |
53 M(BinaryMintOp) \ | |
54 M(ShiftMintOp) \ | |
55 M(UnaryMintOp) \ | |
56 M(InvokeMathCFunction) \ | 47 M(InvokeMathCFunction) \ |
57 M(MergedMath) \ | 48 M(MergedMath) \ |
58 M(GuardFieldClass) \ | 49 M(GuardFieldClass) \ |
59 M(GuardFieldLength) \ | 50 M(GuardFieldLength) \ |
60 M(IfThenElse) \ | 51 M(IfThenElse) \ |
| 52 M(ExtractNthOutput) \ |
| 53 M(BinaryUint32Op) \ |
| 54 M(ShiftUint32Op) \ |
| 55 M(UnaryUint32Op) \ |
| 56 M(UnboxedIntConverter) \ |
| 57 M(BoxInteger32) \ |
| 58 M(UnboxInteger32) \ |
| 59 |
| 60 // List of instructions that are not used by DBC. |
| 61 // Things we aren't planning to implement for DBC: |
| 62 // - Unboxed SIMD, |
| 63 // - Unboxed Mint, |
| 64 // - Optimized RegExps, |
| 65 // - Precompilation. |
| 66 #define FOR_EACH_UNREACHABLE_INSTRUCTION(M) \ |
| 67 M(CaseInsensitiveCompareUC16) \ |
| 68 M(GrowRegExpStack) \ |
| 69 M(IndirectGoto) \ |
| 70 M(MintToDouble) \ |
| 71 M(BinaryMintOp) \ |
| 72 M(ShiftMintOp) \ |
| 73 M(UnaryMintOp) \ |
61 M(BinaryFloat32x4Op) \ | 74 M(BinaryFloat32x4Op) \ |
62 M(Simd32x4Shuffle) \ | 75 M(Simd32x4Shuffle) \ |
63 M(Simd32x4ShuffleMix) \ | 76 M(Simd32x4ShuffleMix) \ |
64 M(Simd32x4GetSignMask) \ | 77 M(Simd32x4GetSignMask) \ |
65 M(Float32x4Constructor) \ | 78 M(Float32x4Constructor) \ |
66 M(Float32x4Zero) \ | 79 M(Float32x4Zero) \ |
67 M(Float32x4Splat) \ | 80 M(Float32x4Splat) \ |
68 M(Float32x4Comparison) \ | 81 M(Float32x4Comparison) \ |
69 M(Float32x4MinMax) \ | 82 M(Float32x4MinMax) \ |
70 M(Float32x4Scale) \ | 83 M(Float32x4Scale) \ |
(...skipping 11 matching lines...) Expand all Loading... |
82 M(BinaryInt32x4Op) \ | 95 M(BinaryInt32x4Op) \ |
83 M(BinaryFloat64x2Op) \ | 96 M(BinaryFloat64x2Op) \ |
84 M(Float64x2Zero) \ | 97 M(Float64x2Zero) \ |
85 M(Float64x2Constructor) \ | 98 M(Float64x2Constructor) \ |
86 M(Float64x2Splat) \ | 99 M(Float64x2Splat) \ |
87 M(Float32x4ToFloat64x2) \ | 100 M(Float32x4ToFloat64x2) \ |
88 M(Float64x2ToFloat32x4) \ | 101 M(Float64x2ToFloat32x4) \ |
89 M(Simd64x2Shuffle) \ | 102 M(Simd64x2Shuffle) \ |
90 M(Float64x2ZeroArg) \ | 103 M(Float64x2ZeroArg) \ |
91 M(Float64x2OneArg) \ | 104 M(Float64x2OneArg) \ |
92 M(ExtractNthOutput) \ | |
93 M(BinaryUint32Op) \ | |
94 M(ShiftUint32Op) \ | |
95 M(UnaryUint32Op) \ | |
96 M(UnboxedIntConverter) \ | |
97 M(BoxInteger32) \ | |
98 M(UnboxInteger32) \ | |
99 M(CheckedSmiOp) \ | 105 M(CheckedSmiOp) \ |
100 | 106 |
101 // List of instructions that are not used by DBC. | |
102 #define FOR_EACH_UNREACHABLE_INSTRUCTION(M) \ | |
103 M(CaseInsensitiveCompareUC16) \ | |
104 M(GrowRegExpStack) \ | |
105 M(IndirectGoto) | |
106 | |
107 // Location summaries actually are not used by the unoptimizing DBC compiler | 107 // Location summaries actually are not used by the unoptimizing DBC compiler |
108 // because we don't allocate any registers. | 108 // because we don't allocate any registers. |
109 static LocationSummary* CreateLocationSummary( | 109 static LocationSummary* CreateLocationSummary( |
110 Zone* zone, | 110 Zone* zone, |
111 intptr_t num_inputs, | 111 intptr_t num_inputs, |
112 Location output = Location::NoLocation(), | 112 Location output = Location::NoLocation(), |
113 LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall) { | 113 LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall) { |
114 const intptr_t kNumTemps = 0; | 114 const intptr_t kNumTemps = 0; |
115 LocationSummary* locs = new(zone) LocationSummary( | 115 LocationSummary* locs = new(zone) LocationSummary( |
116 zone, num_inputs, kNumTemps, contains_call); | 116 zone, num_inputs, kNumTemps, contains_call); |
(...skipping 1097 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 case Token::kNEGATE: { | 1214 case Token::kNEGATE: { |
1215 __ Neg(locs()->out(0).reg(), locs()->in(0).reg()); | 1215 __ Neg(locs()->out(0).reg(), locs()->in(0).reg()); |
1216 compiler->EmitDeopt(deopt_id(), ICData::kDeoptUnaryOp); | 1216 compiler->EmitDeopt(deopt_id(), ICData::kDeoptUnaryOp); |
1217 break; | 1217 break; |
1218 } | 1218 } |
1219 case Token::kBIT_NOT: | 1219 case Token::kBIT_NOT: |
1220 __ BitNot(locs()->out(0).reg(), locs()->in(0).reg()); | 1220 __ BitNot(locs()->out(0).reg(), locs()->in(0).reg()); |
1221 break; | 1221 break; |
1222 default: | 1222 default: |
1223 UNREACHABLE(); | 1223 UNREACHABLE(); |
| 1224 break; |
1224 } | 1225 } |
1225 } | 1226 } |
1226 | 1227 |
1227 | 1228 |
| 1229 EMIT_NATIVE_CODE(Box, 1, Location::RequiresRegister(), LocationSummary::kCall) { |
| 1230 ASSERT(from_representation() == kUnboxedDouble); |
| 1231 const Register value = locs()->in(0).reg(); |
| 1232 const Register out = locs()->out(0).reg(); |
| 1233 const intptr_t kidx = __ AddConstant(compiler->double_class()); |
| 1234 __ Allocate(kidx); |
| 1235 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, |
| 1236 Thread::kNoDeoptId, |
| 1237 token_pos()); |
| 1238 compiler->RecordSafepoint(locs()); |
| 1239 // __ Allocate puts the box at the top of the stack. |
| 1240 __ BoxDouble(out, value); |
| 1241 } |
| 1242 |
| 1243 |
| 1244 EMIT_NATIVE_CODE(Unbox, 1, Location::RequiresRegister()) { |
| 1245 ASSERT(representation() == kUnboxedDouble); |
| 1246 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1247 const intptr_t box_cid = BoxCid(); |
| 1248 const Register box = locs()->in(0).reg(); |
| 1249 const Register result = locs()->out(0).reg(); |
| 1250 if (value_cid == box_cid) { |
| 1251 __ UnboxDouble(result, box); |
| 1252 } else if (CanConvertSmi() && (value_cid == kSmiCid)) { |
| 1253 __ SmiToDouble(result, box); |
| 1254 } else if ((value()->Type()->ToNullableCid() == box_cid) && |
| 1255 value()->Type()->is_nullable()) { |
| 1256 __ IfEqNull(box); |
| 1257 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); |
| 1258 __ UnboxDouble(result, box); |
| 1259 } else { |
| 1260 __ CheckedUnboxDouble(result, box); |
| 1261 compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass); |
| 1262 } |
| 1263 } |
| 1264 |
| 1265 |
| 1266 EMIT_NATIVE_CODE(SmiToDouble, 1, Location::RequiresRegister()) { |
| 1267 const Register value = locs()->in(0).reg(); |
| 1268 const Register result = locs()->out(0).reg(); |
| 1269 __ SmiToDouble(result, value); |
| 1270 } |
| 1271 |
| 1272 |
| 1273 EMIT_NATIVE_CODE(BinaryDoubleOp, 2, Location::RequiresRegister()) { |
| 1274 const Register left = locs()->in(0).reg(); |
| 1275 const Register right = locs()->in(1).reg(); |
| 1276 const Register result = locs()->out(0).reg(); |
| 1277 switch (op_kind()) { |
| 1278 case Token::kADD: __ DAdd(result, left, right); break; |
| 1279 case Token::kSUB: __ DSub(result, left, right); break; |
| 1280 case Token::kMUL: __ DMul(result, left, right); break; |
| 1281 case Token::kDIV: __ DDiv(result, left, right); break; |
| 1282 default: UNREACHABLE(); |
| 1283 } |
| 1284 } |
| 1285 |
| 1286 |
| 1287 EMIT_NATIVE_CODE(UnaryDoubleOp, 1, Location::RequiresRegister()) { |
| 1288 const Register value = locs()->in(0).reg(); |
| 1289 const Register result = locs()->out(0).reg(); |
| 1290 __ DNeg(result, value); |
| 1291 } |
| 1292 |
| 1293 |
1228 static Token::Kind FlipCondition(Token::Kind kind) { | 1294 static Token::Kind FlipCondition(Token::Kind kind) { |
1229 switch (kind) { | 1295 switch (kind) { |
1230 case Token::kEQ: return Token::kNE; | 1296 case Token::kEQ: return Token::kNE; |
1231 case Token::kNE: return Token::kEQ; | 1297 case Token::kNE: return Token::kEQ; |
1232 case Token::kLT: return Token::kGTE; | 1298 case Token::kLT: return Token::kGTE; |
1233 case Token::kGT: return Token::kLTE; | 1299 case Token::kGT: return Token::kLTE; |
1234 case Token::kLTE: return Token::kGT; | 1300 case Token::kLTE: return Token::kGT; |
1235 case Token::kGTE: return Token::kLT; | 1301 case Token::kGTE: return Token::kLT; |
1236 default: | 1302 default: |
1237 UNREACHABLE(); | 1303 UNREACHABLE(); |
1238 return Token::kNE; | 1304 return Token::kNE; |
1239 } | 1305 } |
1240 } | 1306 } |
1241 | 1307 |
1242 | 1308 |
1243 static Bytecode::Opcode OpcodeForCondition(Token::Kind kind) { | 1309 static Bytecode::Opcode OpcodeForSmiCondition(Token::Kind kind) { |
1244 switch (kind) { | 1310 switch (kind) { |
1245 case Token::kEQ: return Bytecode::kIfEqStrict; | 1311 case Token::kEQ: return Bytecode::kIfEqStrict; |
1246 case Token::kNE: return Bytecode::kIfNeStrict; | 1312 case Token::kNE: return Bytecode::kIfNeStrict; |
1247 case Token::kLT: return Bytecode::kIfLt; | 1313 case Token::kLT: return Bytecode::kIfLt; |
1248 case Token::kGT: return Bytecode::kIfGt; | 1314 case Token::kGT: return Bytecode::kIfGt; |
1249 case Token::kLTE: return Bytecode::kIfLe; | 1315 case Token::kLTE: return Bytecode::kIfLe; |
1250 case Token::kGTE: return Bytecode::kIfGe; | 1316 case Token::kGTE: return Bytecode::kIfGe; |
1251 default: | 1317 default: |
1252 UNREACHABLE(); | 1318 UNREACHABLE(); |
1253 return Bytecode::kTrap; | 1319 return Bytecode::kTrap; |
1254 } | 1320 } |
1255 } | 1321 } |
1256 | 1322 |
1257 | 1323 |
| 1324 static Bytecode::Opcode OpcodeForDoubleCondition(Token::Kind kind) { |
| 1325 switch (kind) { |
| 1326 case Token::kEQ: return Bytecode::kIfDEq; |
| 1327 case Token::kNE: return Bytecode::kIfDNe; |
| 1328 case Token::kLT: return Bytecode::kIfDLt; |
| 1329 case Token::kGT: return Bytecode::kIfDGt; |
| 1330 case Token::kLTE: return Bytecode::kIfDLe; |
| 1331 case Token::kGTE: return Bytecode::kIfDGe; |
| 1332 default: |
| 1333 UNREACHABLE(); |
| 1334 return Bytecode::kTrap; |
| 1335 } |
| 1336 } |
| 1337 |
| 1338 |
1258 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, | 1339 static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler, |
1259 LocationSummary* locs, | 1340 LocationSummary* locs, |
1260 Token::Kind kind, | 1341 Token::Kind kind, |
1261 BranchLabels labels) { | 1342 BranchLabels labels) { |
1262 const Register left = locs->in(0).reg(); | 1343 const Register left = locs->in(0).reg(); |
1263 const Register right = locs->in(1).reg(); | 1344 const Register right = locs->in(1).reg(); |
1264 Token::Kind comparison = kind; | 1345 Token::Kind comparison = kind; |
1265 Condition condition = NEXT_IS_TRUE; | 1346 Condition condition = NEXT_IS_TRUE; |
1266 if (labels.fall_through != labels.false_label) { | 1347 if (labels.fall_through != labels.false_label) { |
1267 // If we aren't falling through to the false label, we can save a Jump | 1348 // If we aren't falling through to the false label, we can save a Jump |
1268 // instruction in the case that the true case is the fall through by | 1349 // instruction in the case that the true case is the fall through by |
1269 // flipping the sense of the test such that the instruction following the | 1350 // flipping the sense of the test such that the instruction following the |
1270 // test is the Jump to the false label. | 1351 // test is the Jump to the false label. |
1271 condition = NEXT_IS_FALSE; | 1352 condition = NEXT_IS_FALSE; |
1272 comparison = FlipCondition(kind); | 1353 comparison = FlipCondition(kind); |
1273 } | 1354 } |
1274 __ Emit(Bytecode::Encode(OpcodeForCondition(comparison), left, right)); | 1355 __ Emit(Bytecode::Encode(OpcodeForSmiCondition(comparison), left, right)); |
1275 return condition; | 1356 return condition; |
1276 } | 1357 } |
1277 | 1358 |
| 1359 |
| 1360 static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 1361 LocationSummary* locs, |
| 1362 Token::Kind kind, |
| 1363 BranchLabels labels) { |
| 1364 const Register left = locs->in(0).reg(); |
| 1365 const Register right = locs->in(1).reg(); |
| 1366 Token::Kind comparison = kind; |
| 1367 Condition condition = NEXT_IS_TRUE; |
| 1368 if (labels.fall_through != labels.false_label) { |
| 1369 // If we aren't falling through to the false label, we can save a Jump |
| 1370 // instruction in the case that the true case is the fall through by |
| 1371 // flipping the sense of the test such that the instruction following the |
| 1372 // test is the Jump to the false label. |
| 1373 condition = NEXT_IS_FALSE; |
| 1374 comparison = FlipCondition(kind); |
| 1375 } |
| 1376 __ Emit(Bytecode::Encode(OpcodeForDoubleCondition(comparison), left, right)); |
| 1377 return condition; |
| 1378 } |
| 1379 |
1278 | 1380 |
1279 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 1381 Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
1280 BranchLabels labels) { | 1382 BranchLabels labels) { |
1281 if (operation_cid() == kSmiCid) { | 1383 if (operation_cid() == kSmiCid) { |
1282 return EmitSmiComparisonOp(compiler, locs(), kind(), labels); | 1384 return EmitSmiComparisonOp(compiler, locs(), kind(), labels); |
1283 } else { | 1385 } else { |
1284 ASSERT(operation_cid() == kDoubleCid); | 1386 ASSERT(operation_cid() == kDoubleCid); |
1285 Unsupported(compiler); | 1387 return EmitDoubleComparisonOp(compiler, locs(), kind(), labels); |
1286 UNREACHABLE(); | |
1287 return NEXT_IS_FALSE; | |
1288 } | 1388 } |
1289 } | 1389 } |
1290 | 1390 |
1291 | 1391 |
1292 EMIT_NATIVE_CODE(EqualityCompare, 2, Location::RequiresRegister()) { | 1392 EMIT_NATIVE_CODE(EqualityCompare, 2, Location::RequiresRegister()) { |
1293 ASSERT(compiler->is_optimizing()); | 1393 ASSERT(compiler->is_optimizing()); |
1294 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); | 1394 ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE)); |
1295 Label is_true, is_false; | 1395 Label is_true, is_false; |
1296 // These labels are not used. They are arranged so that EmitComparisonCode | 1396 // These labels are not used. They are arranged so that EmitComparisonCode |
1297 // emits a test that executes the following instruction when the test | 1397 // emits a test that executes the following instruction when the test |
(...skipping 15 matching lines...) Expand all Loading... |
1313 EmitBranchOnCondition(compiler, true_condition, labels); | 1413 EmitBranchOnCondition(compiler, true_condition, labels); |
1314 } | 1414 } |
1315 | 1415 |
1316 | 1416 |
1317 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, | 1417 Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler, |
1318 BranchLabels labels) { | 1418 BranchLabels labels) { |
1319 if (operation_cid() == kSmiCid) { | 1419 if (operation_cid() == kSmiCid) { |
1320 return EmitSmiComparisonOp(compiler, locs(), kind(), labels); | 1420 return EmitSmiComparisonOp(compiler, locs(), kind(), labels); |
1321 } else { | 1421 } else { |
1322 ASSERT(operation_cid() == kDoubleCid); | 1422 ASSERT(operation_cid() == kDoubleCid); |
1323 Unsupported(compiler); | 1423 return EmitDoubleComparisonOp(compiler, locs(), kind(), labels); |
1324 UNREACHABLE(); | |
1325 return NEXT_IS_FALSE; | |
1326 } | 1424 } |
1327 } | 1425 } |
1328 | 1426 |
1329 | 1427 |
1330 EMIT_NATIVE_CODE(RelationalOp, 2, Location::RequiresRegister()) { | 1428 EMIT_NATIVE_CODE(RelationalOp, 2, Location::RequiresRegister()) { |
1331 ASSERT(compiler->is_optimizing()); | 1429 ASSERT(compiler->is_optimizing()); |
1332 Label is_true, is_false; | 1430 Label is_true, is_false; |
1333 BranchLabels labels = { &is_true, &is_false, &is_false }; | 1431 BranchLabels labels = { &is_true, &is_false, &is_false }; |
1334 const Register result = locs()->out(0).reg(); | 1432 const Register result = locs()->out(0).reg(); |
1335 __ LoadConstant(result, Bool::False()); | 1433 __ LoadConstant(result, Bool::False()); |
(...skipping 17 matching lines...) Expand all Loading... |
1353 __ IfULe(length, index); | 1451 __ IfULe(length, index); |
1354 compiler->EmitDeopt(deopt_id(), | 1452 compiler->EmitDeopt(deopt_id(), |
1355 ICData::kDeoptCheckArrayBound, | 1453 ICData::kDeoptCheckArrayBound, |
1356 (generalized_ ? ICData::kGeneralized : 0) | | 1454 (generalized_ ? ICData::kGeneralized : 0) | |
1357 (licm_hoisted_ ? ICData::kHoisted : 0)); | 1455 (licm_hoisted_ ? ICData::kHoisted : 0)); |
1358 } | 1456 } |
1359 | 1457 |
1360 } // namespace dart | 1458 } // namespace dart |
1361 | 1459 |
1362 #endif // defined TARGET_ARCH_DBC | 1460 #endif // defined TARGET_ARCH_DBC |
OLD | NEW |