| 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/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1045 __ sll(T2, T2, 1); // T2 is a Smi. | 1045 __ sll(T2, T2, 1); // T2 is a Smi. |
| 1046 | 1046 |
| 1047 __ Comment("Null arguments loop"); | 1047 __ Comment("Null arguments loop"); |
| 1048 Label null_args_loop, null_args_loop_exit; | 1048 Label null_args_loop, null_args_loop_exit; |
| 1049 __ blez(T2, &null_args_loop_exit); | 1049 __ blez(T2, &null_args_loop_exit); |
| 1050 __ delay_slot()->addiu(T1, FP, | 1050 __ delay_slot()->addiu(T1, FP, |
| 1051 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); | 1051 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); |
| 1052 __ Bind(&null_args_loop); | 1052 __ Bind(&null_args_loop); |
| 1053 __ addiu(T2, T2, Immediate(-kWordSize)); | 1053 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 1054 __ addu(T3, T1, T2); | 1054 __ addu(T3, T1, T2); |
| 1055 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); | 1055 __ LoadImmediate(T5, reinterpret_cast<int32_t>(Object::null())); |
| 1056 __ bgtz(T2, &null_args_loop); | 1056 __ bgtz(T2, &null_args_loop); |
| 1057 __ delay_slot()->sw(TMP, Address(T3)); | 1057 __ delay_slot()->sw(T5, Address(T3)); |
| 1058 __ Bind(&null_args_loop_exit); | 1058 __ Bind(&null_args_loop_exit); |
| 1059 } | 1059 } |
| 1060 | 1060 |
| 1061 | 1061 |
| 1062 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 1062 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 1063 // RA: return address. | 1063 // RA: return address. |
| 1064 // SP: receiver. | 1064 // SP: receiver. |
| 1065 // Sequence node has one return node, its input is load field node. | 1065 // Sequence node has one return node, its input is load field node. |
| 1066 __ lw(V0, Address(SP, 0 * kWordSize)); | 1066 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 1067 __ lw(V0, Address(V0, offset - kHeapObjectTag)); | 1067 __ lw(V0, Address(V0, offset - kHeapObjectTag)); |
| 1068 __ Ret(); | 1068 __ Ret(); |
| 1069 } | 1069 } |
| 1070 | 1070 |
| 1071 | 1071 |
| 1072 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 1072 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 1073 // RA: return address. | 1073 // RA: return address. |
| 1074 // SP+1: receiver. | 1074 // SP+1: receiver. |
| 1075 // SP+0: value. | 1075 // SP+0: value. |
| 1076 // Sequence node has one store node and one return NULL node. | 1076 // Sequence node has one store node and one return NULL node. |
| 1077 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 1077 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 1078 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 1078 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 1079 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); | 1079 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 1080 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); | 1080 __ LoadImmediate(V0, reinterpret_cast<int32_t>(Object::null())); |
| 1081 __ Ret(); | 1081 __ Ret(); |
| 1082 __ delay_slot()->mov(V0, TMP); | |
| 1083 } | 1082 } |
| 1084 | 1083 |
| 1085 | 1084 |
| 1086 void FlowGraphCompiler::EmitFrameEntry() { | 1085 void FlowGraphCompiler::EmitFrameEntry() { |
| 1087 const Function& function = parsed_function().function(); | 1086 const Function& function = parsed_function().function(); |
| 1088 if (CanOptimizeFunction() && | 1087 if (CanOptimizeFunction() && |
| 1089 function.is_optimizable() && | 1088 function.is_optimizable() && |
| 1090 (!is_optimizing() || may_reoptimize())) { | 1089 (!is_optimizing() || may_reoptimize())) { |
| 1091 const Register function_reg = T0; | 1090 const Register function_reg = T0; |
| 1092 | 1091 |
| 1093 Label next; | 1092 __ GetNextPC(T2, TMP); |
| 1094 // The pool pointer is not setup before entering the Dart frame. | 1093 |
| 1095 __ mov(TMP1, RA); // Save RA. | |
| 1096 __ bal(&next); // Branch and link to next instruction to get PC in RA. | |
| 1097 __ delay_slot()->mov(T2, RA); // Save PC of the following mov. | |
| 1098 // Calculate offset of pool pointer from the PC. | 1094 // Calculate offset of pool pointer from the PC. |
| 1099 const intptr_t object_pool_pc_dist = | 1095 const intptr_t object_pool_pc_dist = |
| 1100 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 1096 Instructions::HeaderSize() - Instructions::object_pool_offset() + |
| 1101 assembler()->CodeSize(); | 1097 assembler()->CodeSize() - 1 * Instr::kInstrSize; |
| 1102 __ Bind(&next); | 1098 |
| 1103 __ mov(RA, TMP1); // Restore RA. | |
| 1104 // Preserve PP of caller. | 1099 // Preserve PP of caller. |
| 1105 __ mov(T1, PP); | 1100 __ mov(T1, PP); |
| 1106 // Temporarily setup pool pointer for this dart function. | 1101 // Temporarily setup pool pointer for this dart function. |
| 1107 __ lw(PP, Address(T2, -object_pool_pc_dist)); | 1102 __ lw(PP, Address(T2, -object_pool_pc_dist)); |
| 1108 // Load function object from object pool. | 1103 // Load function object from object pool. |
| 1109 __ LoadObject(function_reg, function); // Uses PP. | 1104 __ LoadObject(function_reg, function); // Uses PP. |
| 1110 // Restore PP of caller. | 1105 // Restore PP of caller. |
| 1111 __ mov(PP, T1); | 1106 __ mov(PP, T1); |
| 1112 | 1107 |
| 1113 // Patch point is after the eventually inlined function object. | 1108 // Patch point is after the eventually inlined function object. |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1479 __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1474 __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); |
| 1480 } | 1475 } |
| 1481 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1476 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1482 Isolate::kNoDeoptId, | 1477 Isolate::kNoDeoptId, |
| 1483 token_pos); | 1478 token_pos); |
| 1484 __ TraceSimMsg("EqualityRegConstCompare return"); | 1479 __ TraceSimMsg("EqualityRegConstCompare return"); |
| 1485 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. | 1480 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. |
| 1486 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. | 1481 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. |
| 1487 return; | 1482 return; |
| 1488 } | 1483 } |
| 1489 __ CompareObject(CMPRES, TMP1, reg, obj); | 1484 __ CompareObject(CMPRES1, CMPRES2, reg, obj); |
| 1490 } | 1485 } |
| 1491 | 1486 |
| 1492 | 1487 |
| 1493 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1488 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1494 Register right, | 1489 Register right, |
| 1495 bool needs_number_check, | 1490 bool needs_number_check, |
| 1496 intptr_t token_pos) { | 1491 intptr_t token_pos) { |
| 1497 __ TraceSimMsg("EqualityRegRegCompare"); | 1492 __ TraceSimMsg("EqualityRegRegCompare"); |
| 1498 __ Comment("EqualityRegRegCompare"); | 1493 __ Comment("EqualityRegRegCompare"); |
| 1499 if (needs_number_check) { | 1494 if (needs_number_check) { |
| 1500 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1495 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1501 __ sw(left, Address(SP, 1 * kWordSize)); | 1496 __ sw(left, Address(SP, 1 * kWordSize)); |
| 1502 __ sw(right, Address(SP, 0 * kWordSize)); | 1497 __ sw(right, Address(SP, 0 * kWordSize)); |
| 1503 if (is_optimizing()) { | 1498 if (is_optimizing()) { |
| 1504 __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); | 1499 __ BranchLink(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); |
| 1505 } else { | 1500 } else { |
| 1506 __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1501 __ BranchLink(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); |
| 1507 } | 1502 } |
| 1508 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1503 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1509 Isolate::kNoDeoptId, | 1504 Isolate::kNoDeoptId, |
| 1510 token_pos); | 1505 token_pos); |
| 1511 __ TraceSimMsg("EqualityRegRegCompare return"); | 1506 __ TraceSimMsg("EqualityRegRegCompare return"); |
| 1512 // Stub returns result in CMPRES. If it is 0, then left and right are equal. | 1507 // Stub returns result in CMPRES. If it is 0, then left and right are equal. |
| 1513 __ lw(right, Address(SP, 0 * kWordSize)); | 1508 __ lw(right, Address(SP, 0 * kWordSize)); |
| 1514 __ lw(left, Address(SP, 1 * kWordSize)); | 1509 __ lw(left, Address(SP, 1 * kWordSize)); |
| 1515 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1510 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1516 } else { | 1511 } else { |
| 1517 __ slt(CMPRES, left, right); | 1512 __ slt(CMPRES1, left, right); |
| 1518 __ slt(TMP1, right, left); | 1513 __ slt(CMPRES2, right, left); |
| 1519 } | 1514 } |
| 1520 } | 1515 } |
| 1521 | 1516 |
| 1522 | 1517 |
| 1523 // Implement equality spec: if any of the arguments is null do identity check. | 1518 // Implement equality spec: if any of the arguments is null do identity check. |
| 1524 // Fallthrough calls super equality. | 1519 // Fallthrough calls super equality. |
| 1525 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, | 1520 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, |
| 1526 Label* skip_call) { | 1521 Label* skip_call) { |
| 1527 Label check_identity, is_false, fall_through; | 1522 Label check_identity, is_false, fall_through; |
| 1528 __ TraceSimMsg("SuperEqualityCallPrologue"); | 1523 __ TraceSimMsg("SuperEqualityCallPrologue"); |
| 1529 __ lw(result, Address(SP, 0 * kWordSize)); // Load right operand. | 1524 __ lw(result, Address(SP, 0 * kWordSize)); // Load right operand. |
| 1530 __ lw(TMP1, Address(SP, 1 * kWordSize)); // Load left operand. | 1525 __ lw(CMPRES1, Address(SP, 1 * kWordSize)); // Load left operand. |
| 1531 __ LoadImmediate(CMPRES, reinterpret_cast<int32_t>(Object::null())); | 1526 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); |
| 1532 __ beq(result, CMPRES, &check_identity); // Is right null? | 1527 __ beq(result, TMP, &check_identity); // Is right null? |
| 1533 __ bne(TMP1, CMPRES, &fall_through); // If right is non-null, check left. | 1528 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); |
| 1529 __ bne(TMP, CMPRES1, &fall_through); // If right is non-null, check left. |
| 1534 | 1530 |
| 1535 __ Bind(&check_identity); | 1531 __ Bind(&check_identity); |
| 1536 __ bne(result, TMP1, &is_false); | 1532 __ bne(result, CMPRES1, &is_false); |
| 1537 __ LoadObject(result, Bool::True()); | 1533 __ LoadObject(result, Bool::True()); |
| 1538 __ Drop(2); | 1534 __ Drop(2); |
| 1539 __ b(skip_call); | 1535 __ b(skip_call); |
| 1540 __ Bind(&is_false); | 1536 __ Bind(&is_false); |
| 1541 __ LoadObject(result, Bool::False()); | 1537 __ LoadObject(result, Bool::False()); |
| 1542 __ Drop(2); | 1538 __ Drop(2); |
| 1543 __ b(skip_call); | 1539 __ b(skip_call); |
| 1544 __ Bind(&fall_through); | 1540 __ Bind(&fall_through); |
| 1545 } | 1541 } |
| 1546 | 1542 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1686 case GE: assembler()->coled(right, left); break; | 1682 case GE: assembler()->coled(right, left); break; |
| 1687 default: { | 1683 default: { |
| 1688 // Should only passing the above conditions to this function. | 1684 // Should only passing the above conditions to this function. |
| 1689 UNREACHABLE(); | 1685 UNREACHABLE(); |
| 1690 break; | 1686 break; |
| 1691 } | 1687 } |
| 1692 } | 1688 } |
| 1693 | 1689 |
| 1694 assembler()->LoadImmediate(TMP, 1); | 1690 assembler()->LoadImmediate(TMP, 1); |
| 1695 if (true_condition == NE) { | 1691 if (true_condition == NE) { |
| 1696 assembler()->movf(CMPRES, ZR); | 1692 assembler()->movf(CMPRES1, ZR); |
| 1697 assembler()->movt(CMPRES, TMP); | 1693 assembler()->movt(CMPRES1, TMP); |
| 1698 } else { | 1694 } else { |
| 1699 assembler()->movf(CMPRES, TMP); | 1695 assembler()->movf(CMPRES1, TMP); |
| 1700 assembler()->movt(CMPRES, ZR); | 1696 assembler()->movt(CMPRES1, ZR); |
| 1701 } | 1697 } |
| 1702 assembler()->mov(TMP, ZR); | 1698 assembler()->mov(CMPRES2, ZR); |
| 1703 | 1699 |
| 1704 // EmitBranchOnCondition expects ordering to be described by CMPRES, TMP1. | 1700 // EmitBranchOnCondition expects ordering to be described by CMPRES, CMPRES2. |
| 1705 branch->EmitBranchOnCondition(this, EQ); | 1701 branch->EmitBranchOnCondition(this, EQ); |
| 1706 } | 1702 } |
| 1707 | 1703 |
| 1708 | 1704 |
| 1709 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, | 1705 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, |
| 1710 FpuRegister left, | 1706 FpuRegister left, |
| 1711 FpuRegister right, | 1707 FpuRegister right, |
| 1712 Register result) { | 1708 Register result) { |
| 1713 Label done; | 1709 Label done; |
| 1714 __ Comment("DoubleCompareBool"); | 1710 __ Comment("DoubleCompareBool"); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1999 __ AddImmediate(SP, kDoubleSize); | 1995 __ AddImmediate(SP, kDoubleSize); |
| 2000 } | 1996 } |
| 2001 | 1997 |
| 2002 | 1998 |
| 2003 #undef __ | 1999 #undef __ |
| 2004 | 2000 |
| 2005 | 2001 |
| 2006 } // namespace dart | 2002 } // namespace dart |
| 2007 | 2003 |
| 2008 #endif // defined TARGET_ARCH_MIPS | 2004 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |