| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved.7 | 1 // Copyright 2012 the V8 project authors. All rights reserved.7 |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 139 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| 140 __ stop("stop_at"); | 140 __ stop("stop_at"); |
| 141 } | 141 } |
| 142 #endif | 142 #endif |
| 143 | 143 |
| 144 // a1: Callee's JS function. | 144 // a1: Callee's JS function. |
| 145 // cp: Callee's context. | 145 // cp: Callee's context. |
| 146 // fp: Caller's frame pointer. | 146 // fp: Caller's frame pointer. |
| 147 // lr: Caller's pc. | 147 // lr: Caller's pc. |
| 148 | 148 |
| 149 // Classic mode functions and builtins need to replace the receiver with the | 149 // Sloppy mode functions and builtins need to replace the receiver with the |
| 150 // global proxy when called as functions (without an explicit receiver | 150 // global proxy when called as functions (without an explicit receiver |
| 151 // object). | 151 // object). |
| 152 if (info_->this_has_uses() && | 152 if (info_->this_has_uses() && |
| 153 info_->is_classic_mode() && | 153 info_->strict_mode() == SLOPPY && |
| 154 !info_->is_native()) { | 154 !info_->is_native()) { |
| 155 Label ok; | 155 Label ok; |
| 156 int receiver_offset = info_->scope()->num_parameters() * kPointerSize; | 156 int receiver_offset = info_->scope()->num_parameters() * kPointerSize; |
| 157 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 157 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
| 158 __ lw(a2, MemOperand(sp, receiver_offset)); | 158 __ lw(a2, MemOperand(sp, receiver_offset)); |
| 159 __ Branch(&ok, ne, a2, Operand(at)); | 159 __ Branch(&ok, ne, a2, Operand(at)); |
| 160 | 160 |
| 161 __ lw(a2, GlobalObjectOperand()); | 161 __ lw(a2, GlobalObjectOperand()); |
| 162 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); | 162 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset)); |
| 163 | 163 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 osr_pc_offset_ = masm()->pc_offset(); | 252 osr_pc_offset_ = masm()->pc_offset(); |
| 253 | 253 |
| 254 // Adjust the frame size, subsuming the unoptimized frame into the | 254 // Adjust the frame size, subsuming the unoptimized frame into the |
| 255 // optimized frame. | 255 // optimized frame. |
| 256 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); | 256 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); |
| 257 ASSERT(slots >= 0); | 257 ASSERT(slots >= 0); |
| 258 __ Subu(sp, sp, Operand(slots * kPointerSize)); | 258 __ Subu(sp, sp, Operand(slots * kPointerSize)); |
| 259 } | 259 } |
| 260 | 260 |
| 261 | 261 |
| 262 void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) { |
| 263 if (!instr->IsLazyBailout() && !instr->IsGap()) { |
| 264 safepoints_.BumpLastLazySafepointIndex(); |
| 265 } |
| 266 } |
| 267 |
| 268 |
| 262 bool LCodeGen::GenerateDeferredCode() { | 269 bool LCodeGen::GenerateDeferredCode() { |
| 263 ASSERT(is_generating()); | 270 ASSERT(is_generating()); |
| 264 if (deferred_.length() > 0) { | 271 if (deferred_.length() > 0) { |
| 265 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { | 272 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
| 266 LDeferredCode* code = deferred_[i]; | 273 LDeferredCode* code = deferred_[i]; |
| 267 | 274 |
| 268 HValue* value = | 275 HValue* value = |
| 269 instructions_->at(code->instruction_index())->hydrogen_value(); | 276 instructions_->at(code->instruction_index())->hydrogen_value(); |
| 270 RecordAndWritePosition( | 277 RecordAndWritePosition( |
| 271 chunk()->graph()->SourcePositionToScriptPosition(value->position())); | 278 chunk()->graph()->SourcePositionToScriptPosition(value->position())); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 394 } else if (r.IsSmi()) { | 401 } else if (r.IsSmi()) { |
| 395 ASSERT(constant->HasSmiValue()); | 402 ASSERT(constant->HasSmiValue()); |
| 396 __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value()))); | 403 __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value()))); |
| 397 } else if (r.IsDouble()) { | 404 } else if (r.IsDouble()) { |
| 398 Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); | 405 Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); |
| 399 } else { | 406 } else { |
| 400 ASSERT(r.IsSmiOrTagged()); | 407 ASSERT(r.IsSmiOrTagged()); |
| 401 __ li(scratch, literal); | 408 __ li(scratch, literal); |
| 402 } | 409 } |
| 403 return scratch; | 410 return scratch; |
| 404 } else if (op->IsStackSlot() || op->IsArgument()) { | 411 } else if (op->IsStackSlot()) { |
| 405 __ lw(scratch, ToMemOperand(op)); | 412 __ lw(scratch, ToMemOperand(op)); |
| 406 return scratch; | 413 return scratch; |
| 407 } | 414 } |
| 408 UNREACHABLE(); | 415 UNREACHABLE(); |
| 409 return scratch; | 416 return scratch; |
| 410 } | 417 } |
| 411 | 418 |
| 412 | 419 |
| 413 DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const { | 420 DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const { |
| 414 ASSERT(op->IsDoubleRegister()); | 421 ASSERT(op->IsDoubleRegister()); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 430 ASSERT(literal->IsNumber()); | 437 ASSERT(literal->IsNumber()); |
| 431 __ li(at, Operand(static_cast<int32_t>(literal->Number()))); | 438 __ li(at, Operand(static_cast<int32_t>(literal->Number()))); |
| 432 __ mtc1(at, flt_scratch); | 439 __ mtc1(at, flt_scratch); |
| 433 __ cvt_d_w(dbl_scratch, flt_scratch); | 440 __ cvt_d_w(dbl_scratch, flt_scratch); |
| 434 return dbl_scratch; | 441 return dbl_scratch; |
| 435 } else if (r.IsDouble()) { | 442 } else if (r.IsDouble()) { |
| 436 Abort(kUnsupportedDoubleImmediate); | 443 Abort(kUnsupportedDoubleImmediate); |
| 437 } else if (r.IsTagged()) { | 444 } else if (r.IsTagged()) { |
| 438 Abort(kUnsupportedTaggedImmediate); | 445 Abort(kUnsupportedTaggedImmediate); |
| 439 } | 446 } |
| 440 } else if (op->IsStackSlot() || op->IsArgument()) { | 447 } else if (op->IsStackSlot()) { |
| 441 MemOperand mem_op = ToMemOperand(op); | 448 MemOperand mem_op = ToMemOperand(op); |
| 442 __ ldc1(dbl_scratch, mem_op); | 449 __ ldc1(dbl_scratch, mem_op); |
| 443 return dbl_scratch; | 450 return dbl_scratch; |
| 444 } | 451 } |
| 445 UNREACHABLE(); | 452 UNREACHABLE(); |
| 446 return dbl_scratch; | 453 return dbl_scratch; |
| 447 } | 454 } |
| 448 | 455 |
| 449 | 456 |
| 450 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { | 457 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 if (op->IsStackSlot()) { | 655 if (op->IsStackSlot()) { |
| 649 if (is_tagged) { | 656 if (is_tagged) { |
| 650 translation->StoreStackSlot(op->index()); | 657 translation->StoreStackSlot(op->index()); |
| 651 } else if (is_uint32) { | 658 } else if (is_uint32) { |
| 652 translation->StoreUint32StackSlot(op->index()); | 659 translation->StoreUint32StackSlot(op->index()); |
| 653 } else { | 660 } else { |
| 654 translation->StoreInt32StackSlot(op->index()); | 661 translation->StoreInt32StackSlot(op->index()); |
| 655 } | 662 } |
| 656 } else if (op->IsDoubleStackSlot()) { | 663 } else if (op->IsDoubleStackSlot()) { |
| 657 translation->StoreDoubleStackSlot(op->index()); | 664 translation->StoreDoubleStackSlot(op->index()); |
| 658 } else if (op->IsArgument()) { | |
| 659 ASSERT(is_tagged); | |
| 660 int src_index = GetStackSlotCount() + op->index(); | |
| 661 translation->StoreStackSlot(src_index); | |
| 662 } else if (op->IsRegister()) { | 665 } else if (op->IsRegister()) { |
| 663 Register reg = ToRegister(op); | 666 Register reg = ToRegister(op); |
| 664 if (is_tagged) { | 667 if (is_tagged) { |
| 665 translation->StoreRegister(reg); | 668 translation->StoreRegister(reg); |
| 666 } else if (is_uint32) { | 669 } else if (is_uint32) { |
| 667 translation->StoreUint32Register(reg); | 670 translation->StoreUint32Register(reg); |
| 668 } else { | 671 } else { |
| 669 translation->StoreInt32Register(reg); | 672 translation->StoreInt32Register(reg); |
| 670 } | 673 } |
| 671 } else if (op->IsDoubleRegister()) { | 674 } else if (op->IsDoubleRegister()) { |
| (...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 UNREACHABLE(); | 1060 UNREACHABLE(); |
| 1058 } | 1061 } |
| 1059 } | 1062 } |
| 1060 | 1063 |
| 1061 | 1064 |
| 1062 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { | 1065 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { |
| 1063 GenerateOsrPrologue(); | 1066 GenerateOsrPrologue(); |
| 1064 } | 1067 } |
| 1065 | 1068 |
| 1066 | 1069 |
| 1070 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) { |
| 1071 Register dividend = ToRegister(instr->dividend()); |
| 1072 int32_t divisor = instr->divisor(); |
| 1073 ASSERT(dividend.is(ToRegister(instr->result()))); |
| 1074 |
| 1075 // Theoretically, a variation of the branch-free code for integer division by |
| 1076 // a power of 2 (calculating the remainder via an additional multiplication |
| 1077 // (which gets simplified to an 'and') and subtraction) should be faster, and |
| 1078 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to |
| 1079 // indicate that positive dividends are heavily favored, so the branching |
| 1080 // version performs better. |
| 1081 HMod* hmod = instr->hydrogen(); |
| 1082 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1083 Label dividend_is_not_negative, done; |
| 1084 |
| 1085 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { |
| 1086 __ Branch(÷nd_is_not_negative, ge, dividend, Operand(zero_reg)); |
| 1087 // Note: The code below even works when right contains kMinInt. |
| 1088 __ subu(dividend, zero_reg, dividend); |
| 1089 __ And(dividend, dividend, Operand(mask)); |
| 1090 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1091 DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); |
| 1092 } |
| 1093 __ Branch(USE_DELAY_SLOT, &done); |
| 1094 __ subu(dividend, zero_reg, dividend); |
| 1095 } |
| 1096 |
| 1097 __ bind(÷nd_is_not_negative); |
| 1098 __ And(dividend, dividend, Operand(mask)); |
| 1099 __ bind(&done); |
| 1100 } |
| 1101 |
| 1102 |
| 1103 void LCodeGen::DoModByConstI(LModByConstI* instr) { |
| 1104 Register dividend = ToRegister(instr->dividend()); |
| 1105 int32_t divisor = instr->divisor(); |
| 1106 Register result = ToRegister(instr->result()); |
| 1107 ASSERT(!dividend.is(result)); |
| 1108 |
| 1109 if (divisor == 0) { |
| 1110 DeoptimizeIf(al, instr->environment()); |
| 1111 return; |
| 1112 } |
| 1113 |
| 1114 __ FlooringDiv(result, dividend, Abs(divisor)); |
| 1115 __ srl(at, dividend, 31); |
| 1116 __ Addu(result, result, at); |
| 1117 __ Mul(result, result, Operand(Abs(divisor))); |
| 1118 __ Subu(result, dividend, Operand(result)); |
| 1119 |
| 1120 // Check for negative zero. |
| 1121 HMod* hmod = instr->hydrogen(); |
| 1122 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1123 Label remainder_not_zero; |
| 1124 __ Branch(&remainder_not_zero, ne, result, Operand(zero_reg)); |
| 1125 DeoptimizeIf(lt, instr->environment(), dividend, Operand(zero_reg)); |
| 1126 __ bind(&remainder_not_zero); |
| 1127 } |
| 1128 } |
| 1129 |
| 1130 |
| 1067 void LCodeGen::DoModI(LModI* instr) { | 1131 void LCodeGen::DoModI(LModI* instr) { |
| 1068 HMod* hmod = instr->hydrogen(); | 1132 HMod* hmod = instr->hydrogen(); |
| 1069 HValue* left = hmod->left(); | 1133 const Register left_reg = ToRegister(instr->left()); |
| 1070 HValue* right = hmod->right(); | 1134 const Register right_reg = ToRegister(instr->right()); |
| 1071 if (hmod->RightIsPowerOf2()) { | 1135 const Register result_reg = ToRegister(instr->result()); |
| 1072 const Register left_reg = ToRegister(instr->left()); | |
| 1073 const Register result_reg = ToRegister(instr->result()); | |
| 1074 | 1136 |
| 1075 // Note: The code below even works when right contains kMinInt. | 1137 // div runs in the background while we check for special cases. |
| 1076 int32_t divisor = Abs(right->GetInteger32Constant()); | 1138 __ div(left_reg, right_reg); |
| 1077 | 1139 |
| 1078 Label left_is_not_negative, done; | 1140 Label done; |
| 1079 if (left->CanBeNegative()) { | 1141 // Check for x % 0, we have to deopt in this case because we can't return a |
| 1080 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, | 1142 // NaN. |
| 1081 &left_is_not_negative, ge, left_reg, Operand(zero_reg)); | 1143 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1082 __ subu(result_reg, zero_reg, left_reg); | 1144 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); |
| 1083 __ And(result_reg, result_reg, divisor - 1); | 1145 } |
| 1084 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1146 |
| 1085 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | 1147 // Check for kMinInt % -1, div will return kMinInt, which is not what we |
| 1086 } | 1148 // want. We have to deopt if we care about -0, because we can't return that. |
| 1149 if (hmod->CheckFlag(HValue::kCanOverflow)) { |
| 1150 Label no_overflow_possible; |
| 1151 __ Branch(&no_overflow_possible, ne, left_reg, Operand(kMinInt)); |
| 1152 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1153 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1)); |
| 1154 } else { |
| 1155 __ Branch(&no_overflow_possible, ne, right_reg, Operand(-1)); |
| 1087 __ Branch(USE_DELAY_SLOT, &done); | 1156 __ Branch(USE_DELAY_SLOT, &done); |
| 1088 __ subu(result_reg, zero_reg, result_reg); | 1157 __ mov(result_reg, zero_reg); |
| 1089 } | 1158 } |
| 1159 __ bind(&no_overflow_possible); |
| 1160 } |
| 1090 | 1161 |
| 1091 __ bind(&left_is_not_negative); | 1162 // If we care about -0, test if the dividend is <0 and the result is 0. |
| 1092 __ And(result_reg, left_reg, divisor - 1); | 1163 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg)); |
| 1093 __ bind(&done); | 1164 __ mfhi(result_reg); |
| 1094 } else { | 1165 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1095 const Register scratch = scratch0(); | 1166 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); |
| 1096 const Register left_reg = ToRegister(instr->left()); | |
| 1097 const Register result_reg = ToRegister(instr->result()); | |
| 1098 | |
| 1099 // div runs in the background while we check for special cases. | |
| 1100 Register right_reg = EmitLoadRegister(instr->right(), scratch); | |
| 1101 __ div(left_reg, right_reg); | |
| 1102 | |
| 1103 Label done; | |
| 1104 // Check for x % 0, we have to deopt in this case because we can't return a | |
| 1105 // NaN. | |
| 1106 if (right->CanBeZero()) { | |
| 1107 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); | |
| 1108 } | |
| 1109 | |
| 1110 // Check for kMinInt % -1, we have to deopt if we care about -0, because we | |
| 1111 // can't return that. | |
| 1112 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) { | |
| 1113 Label left_not_min_int; | |
| 1114 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt)); | |
| 1115 // TODO(svenpanne) Don't deopt when we don't care about -0. | |
| 1116 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1)); | |
| 1117 __ bind(&left_not_min_int); | |
| 1118 } | |
| 1119 | |
| 1120 // TODO(svenpanne) Only emit the test/deopt if we have to. | |
| 1121 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg)); | |
| 1122 __ mfhi(result_reg); | |
| 1123 | |
| 1124 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 1125 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); | |
| 1126 } | |
| 1127 __ bind(&done); | |
| 1128 } | 1167 } |
| 1168 __ bind(&done); |
| 1129 } | 1169 } |
| 1130 | 1170 |
| 1131 | 1171 |
| 1132 void LCodeGen::EmitSignedIntegerDivisionByConstant( | 1172 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { |
| 1133 Register result, | 1173 Register dividend = ToRegister(instr->dividend()); |
| 1134 Register dividend, | 1174 int32_t divisor = instr->divisor(); |
| 1135 int32_t divisor, | 1175 Register result = ToRegister(instr->result()); |
| 1136 Register remainder, | 1176 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor)))); |
| 1137 Register scratch, | 1177 ASSERT(!result.is(dividend)); |
| 1138 LEnvironment* environment) { | |
| 1139 ASSERT(!AreAliased(dividend, scratch, at, no_reg)); | |
| 1140 | 1178 |
| 1141 uint32_t divisor_abs = abs(divisor); | 1179 // Check for (0 / -x) that will produce negative zero. |
| 1180 HDiv* hdiv = instr->hydrogen(); |
| 1181 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1182 DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); |
| 1183 } |
| 1184 // Check for (kMinInt / -1). |
| 1185 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { |
| 1186 DeoptimizeIf(eq, instr->environment(), dividend, Operand(kMinInt)); |
| 1187 } |
| 1188 // Deoptimize if remainder will not be 0. |
| 1189 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && |
| 1190 divisor != 1 && divisor != -1) { |
| 1191 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1192 __ And(at, dividend, Operand(mask)); |
| 1193 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); |
| 1194 } |
| 1142 | 1195 |
| 1143 int32_t power_of_2_factor = | 1196 if (divisor == -1) { // Nice shortcut, not needed for correctness. |
| 1144 CompilerIntrinsics::CountTrailingZeros(divisor_abs); | 1197 __ Subu(result, zero_reg, dividend); |
| 1198 return; |
| 1199 } |
| 1200 uint16_t shift = WhichPowerOf2Abs(divisor); |
| 1201 if (shift == 0) { |
| 1202 __ Move(result, dividend); |
| 1203 } else if (shift == 1) { |
| 1204 __ srl(result, dividend, 31); |
| 1205 __ Addu(result, dividend, Operand(result)); |
| 1206 } else { |
| 1207 __ sra(result, dividend, 31); |
| 1208 __ srl(result, result, 32 - shift); |
| 1209 __ Addu(result, dividend, Operand(result)); |
| 1210 } |
| 1211 if (shift > 0) __ sra(result, result, shift); |
| 1212 if (divisor < 0) __ Subu(result, zero_reg, result); |
| 1213 } |
| 1145 | 1214 |
| 1146 switch (divisor_abs) { | |
| 1147 case 0: | |
| 1148 DeoptimizeIf(al, environment); | |
| 1149 return; | |
| 1150 | 1215 |
| 1151 case 1: | 1216 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { |
| 1152 if (divisor > 0) { | 1217 Register dividend = ToRegister(instr->dividend()); |
| 1153 __ Move(result, dividend); | 1218 int32_t divisor = instr->divisor(); |
| 1154 } else { | 1219 Register result = ToRegister(instr->result()); |
| 1155 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch); | 1220 ASSERT(!dividend.is(result)); |
| 1156 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg)); | |
| 1157 } | |
| 1158 // Compute the remainder. | |
| 1159 __ Move(remainder, zero_reg); | |
| 1160 return; | |
| 1161 | 1221 |
| 1162 default: | 1222 if (divisor == 0) { |
| 1163 if (IsPowerOf2(divisor_abs)) { | 1223 DeoptimizeIf(al, instr->environment()); |
| 1164 // Branch and condition free code for integer division by a power | 1224 return; |
| 1165 // of two. | 1225 } |
| 1166 int32_t power = WhichPowerOf2(divisor_abs); | |
| 1167 if (power > 1) { | |
| 1168 __ sra(scratch, dividend, power - 1); | |
| 1169 } | |
| 1170 __ srl(scratch, scratch, 32 - power); | |
| 1171 __ Addu(scratch, dividend, Operand(scratch)); | |
| 1172 __ sra(result, scratch, power); | |
| 1173 // Negate if necessary. | |
| 1174 // We don't need to check for overflow because the case '-1' is | |
| 1175 // handled separately. | |
| 1176 if (divisor < 0) { | |
| 1177 ASSERT(divisor != -1); | |
| 1178 __ Subu(result, zero_reg, Operand(result)); | |
| 1179 } | |
| 1180 // Compute the remainder. | |
| 1181 if (divisor > 0) { | |
| 1182 __ sll(scratch, result, power); | |
| 1183 __ Subu(remainder, dividend, Operand(scratch)); | |
| 1184 } else { | |
| 1185 __ sll(scratch, result, power); | |
| 1186 __ Addu(remainder, dividend, Operand(scratch)); | |
| 1187 } | |
| 1188 return; | |
| 1189 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) { | |
| 1190 // Use magic numbers for a few specific divisors. | |
| 1191 // Details and proofs can be found in: | |
| 1192 // - Hacker's Delight, Henry S. Warren, Jr. | |
| 1193 // - The PowerPC Compiler Writer's Guide | |
| 1194 // and probably many others. | |
| 1195 // | |
| 1196 // We handle | |
| 1197 // <divisor with magic numbers> * <power of 2> | |
| 1198 // but not | |
| 1199 // <divisor with magic numbers> * <other divisor with magic numbers> | |
| 1200 DivMagicNumbers magic_numbers = | |
| 1201 DivMagicNumberFor(divisor_abs >> power_of_2_factor); | |
| 1202 // Branch and condition free code for integer division by a power | |
| 1203 // of two. | |
| 1204 const int32_t M = magic_numbers.M; | |
| 1205 const int32_t s = magic_numbers.s + power_of_2_factor; | |
| 1206 | 1226 |
| 1207 __ li(scratch, Operand(M)); | 1227 // Check for (0 / -x) that will produce negative zero. |
| 1208 __ mult(dividend, scratch); | 1228 HDiv* hdiv = instr->hydrogen(); |
| 1209 __ mfhi(scratch); | 1229 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1210 if (M < 0) { | 1230 DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); |
| 1211 __ Addu(scratch, scratch, Operand(dividend)); | 1231 } |
| 1212 } | 1232 |
| 1213 if (s > 0) { | 1233 __ FlooringDiv(result, dividend, Abs(divisor)); |
| 1214 __ sra(scratch, scratch, s); | 1234 __ srl(at, dividend, 31); |
| 1215 __ mov(scratch, scratch); | 1235 __ Addu(result, result, Operand(at)); |
| 1216 } | 1236 if (divisor < 0) __ Subu(result, zero_reg, result); |
| 1217 __ srl(at, dividend, 31); | 1237 |
| 1218 __ Addu(result, scratch, Operand(at)); | 1238 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { |
| 1219 if (divisor < 0) __ Subu(result, zero_reg, Operand(result)); | 1239 __ Mul(scratch0(), result, Operand(divisor)); |
| 1220 // Compute the remainder. | 1240 __ Subu(scratch0(), scratch0(), dividend); |
| 1221 __ li(scratch, Operand(divisor)); | 1241 DeoptimizeIf(ne, instr->environment(), scratch0(), Operand(zero_reg)); |
| 1222 __ Mul(scratch, result, Operand(scratch)); | |
| 1223 __ Subu(remainder, dividend, Operand(scratch)); | |
| 1224 } else { | |
| 1225 __ li(scratch, Operand(divisor)); | |
| 1226 __ div(dividend, scratch); | |
| 1227 __ mfhi(remainder); | |
| 1228 __ mflo(result); | |
| 1229 } | |
| 1230 } | 1242 } |
| 1231 } | 1243 } |
| 1232 | 1244 |
| 1233 | 1245 |
| 1234 void LCodeGen::DoDivI(LDivI* instr) { | 1246 void LCodeGen::DoDivI(LDivI* instr) { |
| 1247 HBinaryOperation* hdiv = instr->hydrogen(); |
| 1235 const Register left = ToRegister(instr->left()); | 1248 const Register left = ToRegister(instr->left()); |
| 1236 const Register right = ToRegister(instr->right()); | 1249 const Register right = ToRegister(instr->right()); |
| 1237 const Register result = ToRegister(instr->result()); | 1250 const Register result = ToRegister(instr->result()); |
| 1238 | 1251 |
| 1239 // On MIPS div is asynchronous - it will run in the background while we | 1252 // On MIPS div is asynchronous - it will run in the background while we |
| 1240 // check for special cases. | 1253 // check for special cases. |
| 1241 __ div(left, right); | 1254 __ div(left, right); |
| 1242 | 1255 |
| 1243 // Check for x / 0. | 1256 // Check for x / 0. |
| 1244 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { | 1257 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1245 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); | 1258 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); |
| 1246 } | 1259 } |
| 1247 | 1260 |
| 1248 // Check for (0 / -x) that will produce negative zero. | 1261 // Check for (0 / -x) that will produce negative zero. |
| 1249 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1262 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1250 Label left_not_zero; | 1263 Label left_not_zero; |
| 1251 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); | 1264 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); |
| 1252 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); | 1265 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); |
| 1253 __ bind(&left_not_zero); | 1266 __ bind(&left_not_zero); |
| 1254 } | 1267 } |
| 1255 | 1268 |
| 1256 // Check for (kMinInt / -1). | 1269 // Check for (kMinInt / -1). |
| 1257 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | 1270 if (hdiv->CheckFlag(HValue::kCanOverflow) && |
| 1271 !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { |
| 1258 Label left_not_min_int; | 1272 Label left_not_min_int; |
| 1259 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); | 1273 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); |
| 1260 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); | 1274 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); |
| 1261 __ bind(&left_not_min_int); | 1275 __ bind(&left_not_min_int); |
| 1262 } | 1276 } |
| 1263 | 1277 |
| 1264 if (!instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { | 1278 if (hdiv->IsMathFloorOfDiv()) { |
| 1279 // We performed a truncating division. Correct the result if necessary. |
| 1280 Label done; |
| 1281 Register remainder = scratch0(); |
| 1282 __ mfhi(remainder); |
| 1283 __ mflo(result); |
| 1284 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); |
| 1285 __ Xor(remainder, remainder, Operand(right)); |
| 1286 __ Branch(&done, ge, remainder, Operand(zero_reg)); |
| 1287 __ Subu(result, result, Operand(1)); |
| 1288 __ bind(&done); |
| 1289 } else if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { |
| 1265 __ mfhi(result); | 1290 __ mfhi(result); |
| 1266 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg)); | 1291 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg)); |
| 1292 __ mflo(result); |
| 1293 } else { |
| 1294 __ mflo(result); |
| 1267 } | 1295 } |
| 1268 __ mflo(result); | |
| 1269 } | 1296 } |
| 1270 | 1297 |
| 1271 | 1298 |
| 1272 void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { | 1299 void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { |
| 1273 DoubleRegister addend = ToDoubleRegister(instr->addend()); | 1300 DoubleRegister addend = ToDoubleRegister(instr->addend()); |
| 1274 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); | 1301 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); |
| 1275 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); | 1302 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); |
| 1276 | 1303 |
| 1277 // This is computed in-place. | 1304 // This is computed in-place. |
| 1278 ASSERT(addend.is(ToDoubleRegister(instr->result()))); | 1305 ASSERT(addend.is(ToDoubleRegister(instr->result()))); |
| 1279 | 1306 |
| 1280 __ madd_d(addend, addend, multiplier, multiplicand); | 1307 __ madd_d(addend, addend, multiplier, multiplicand); |
| 1281 } | 1308 } |
| 1282 | 1309 |
| 1283 | 1310 |
| 1284 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { | 1311 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { |
| 1285 const Register result = ToRegister(instr->result()); | 1312 Register dividend = ToRegister(instr->dividend()); |
| 1286 const Register left = ToRegister(instr->left()); | 1313 Register result = ToRegister(instr->result()); |
| 1287 const Register remainder = ToRegister(instr->temp()); | 1314 int32_t divisor = instr->divisor(); |
| 1288 const Register scratch = scratch0(); | 1315 Register scratch = scratch0(); |
| 1316 ASSERT(!scratch.is(dividend)); |
| 1289 | 1317 |
| 1290 if (instr->right()->IsConstantOperand()) { | 1318 // If the divisor is positive, things are easy: There can be no deopts and we |
| 1291 Label done; | 1319 // can simply do an arithmetic right shift. |
| 1292 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); | 1320 if (divisor == 1) return; |
| 1293 if (divisor < 0) { | 1321 uint16_t shift = WhichPowerOf2Abs(divisor); |
| 1294 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); | 1322 if (divisor > 1) { |
| 1323 __ sra(result, dividend, shift); |
| 1324 return; |
| 1325 } |
| 1326 |
| 1327 // If the divisor is negative, we have to negate and handle edge cases. |
| 1328 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1329 __ Move(scratch, dividend); |
| 1330 } |
| 1331 __ Subu(result, zero_reg, dividend); |
| 1332 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1333 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg)); |
| 1334 } |
| 1335 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1336 // Note that we could emit branch-free code, but that would need one more |
| 1337 // register. |
| 1338 __ Xor(at, scratch, result); |
| 1339 if (divisor == -1) { |
| 1340 DeoptimizeIf(ge, instr->environment(), at, Operand(zero_reg)); |
| 1341 __ sra(result, dividend, shift); |
| 1342 } else { |
| 1343 Label no_overflow, done; |
| 1344 __ Branch(&no_overflow, lt, at, Operand(zero_reg)); |
| 1345 __ li(result, Operand(kMinInt / divisor)); |
| 1346 __ Branch(&done); |
| 1347 __ bind(&no_overflow); |
| 1348 __ sra(result, dividend, shift); |
| 1349 __ bind(&done); |
| 1295 } | 1350 } |
| 1296 EmitSignedIntegerDivisionByConstant(result, | |
| 1297 left, | |
| 1298 divisor, | |
| 1299 remainder, | |
| 1300 scratch, | |
| 1301 instr->environment()); | |
| 1302 // We performed a truncating division. Correct the result if necessary. | |
| 1303 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); | |
| 1304 __ Xor(scratch , remainder, Operand(divisor)); | |
| 1305 __ Branch(&done, ge, scratch, Operand(zero_reg)); | |
| 1306 __ Subu(result, result, Operand(1)); | |
| 1307 __ bind(&done); | |
| 1308 } else { | 1351 } else { |
| 1309 Label done; | 1352 __ sra(result, dividend, shift); |
| 1310 const Register right = ToRegister(instr->right()); | |
| 1311 | |
| 1312 // On MIPS div is asynchronous - it will run in the background while we | |
| 1313 // check for special cases. | |
| 1314 __ div(left, right); | |
| 1315 | |
| 1316 // Check for x / 0. | |
| 1317 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); | |
| 1318 | |
| 1319 // Check for (0 / -x) that will produce negative zero. | |
| 1320 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | |
| 1321 Label left_not_zero; | |
| 1322 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); | |
| 1323 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); | |
| 1324 __ bind(&left_not_zero); | |
| 1325 } | |
| 1326 | |
| 1327 // Check for (kMinInt / -1). | |
| 1328 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { | |
| 1329 Label left_not_min_int; | |
| 1330 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); | |
| 1331 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); | |
| 1332 __ bind(&left_not_min_int); | |
| 1333 } | |
| 1334 | |
| 1335 __ mfhi(remainder); | |
| 1336 __ mflo(result); | |
| 1337 | |
| 1338 // We performed a truncating division. Correct the result if necessary. | |
| 1339 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); | |
| 1340 __ Xor(scratch , remainder, Operand(right)); | |
| 1341 __ Branch(&done, ge, scratch, Operand(zero_reg)); | |
| 1342 __ Subu(result, result, Operand(1)); | |
| 1343 __ bind(&done); | |
| 1344 } | 1353 } |
| 1345 } | 1354 } |
| 1346 | 1355 |
| 1347 | 1356 |
| 1357 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
| 1358 Register dividend = ToRegister(instr->dividend()); |
| 1359 int32_t divisor = instr->divisor(); |
| 1360 Register result = ToRegister(instr->result()); |
| 1361 ASSERT(!dividend.is(result)); |
| 1362 |
| 1363 if (divisor == 0) { |
| 1364 DeoptimizeIf(al, instr->environment()); |
| 1365 return; |
| 1366 } |
| 1367 |
| 1368 // Check for (0 / -x) that will produce negative zero. |
| 1369 HMathFloorOfDiv* hdiv = instr->hydrogen(); |
| 1370 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1371 DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg)); |
| 1372 } |
| 1373 |
| 1374 __ FlooringDiv(result, dividend, divisor); |
| 1375 } |
| 1376 |
| 1377 |
| 1348 void LCodeGen::DoMulI(LMulI* instr) { | 1378 void LCodeGen::DoMulI(LMulI* instr) { |
| 1349 Register scratch = scratch0(); | 1379 Register scratch = scratch0(); |
| 1350 Register result = ToRegister(instr->result()); | 1380 Register result = ToRegister(instr->result()); |
| 1351 // Note that result may alias left. | 1381 // Note that result may alias left. |
| 1352 Register left = ToRegister(instr->left()); | 1382 Register left = ToRegister(instr->left()); |
| 1353 LOperand* right_op = instr->right(); | 1383 LOperand* right_op = instr->right(); |
| 1354 | 1384 |
| 1355 bool bailout_on_minus_zero = | 1385 bool bailout_on_minus_zero = |
| 1356 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); | 1386 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); |
| 1357 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1387 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1460 | 1490 |
| 1461 | 1491 |
| 1462 void LCodeGen::DoBitI(LBitI* instr) { | 1492 void LCodeGen::DoBitI(LBitI* instr) { |
| 1463 LOperand* left_op = instr->left(); | 1493 LOperand* left_op = instr->left(); |
| 1464 LOperand* right_op = instr->right(); | 1494 LOperand* right_op = instr->right(); |
| 1465 ASSERT(left_op->IsRegister()); | 1495 ASSERT(left_op->IsRegister()); |
| 1466 Register left = ToRegister(left_op); | 1496 Register left = ToRegister(left_op); |
| 1467 Register result = ToRegister(instr->result()); | 1497 Register result = ToRegister(instr->result()); |
| 1468 Operand right(no_reg); | 1498 Operand right(no_reg); |
| 1469 | 1499 |
| 1470 if (right_op->IsStackSlot() || right_op->IsArgument()) { | 1500 if (right_op->IsStackSlot()) { |
| 1471 right = Operand(EmitLoadRegister(right_op, at)); | 1501 right = Operand(EmitLoadRegister(right_op, at)); |
| 1472 } else { | 1502 } else { |
| 1473 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand()); | 1503 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand()); |
| 1474 right = ToOperand(right_op); | 1504 right = ToOperand(right_op); |
| 1475 } | 1505 } |
| 1476 | 1506 |
| 1477 switch (instr->op()) { | 1507 switch (instr->op()) { |
| 1478 case Token::BIT_AND: | 1508 case Token::BIT_AND: |
| 1479 __ And(result, left, right); | 1509 __ And(result, left, right); |
| 1480 break; | 1510 break; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1582 } | 1612 } |
| 1583 | 1613 |
| 1584 | 1614 |
| 1585 void LCodeGen::DoSubI(LSubI* instr) { | 1615 void LCodeGen::DoSubI(LSubI* instr) { |
| 1586 LOperand* left = instr->left(); | 1616 LOperand* left = instr->left(); |
| 1587 LOperand* right = instr->right(); | 1617 LOperand* right = instr->right(); |
| 1588 LOperand* result = instr->result(); | 1618 LOperand* result = instr->result(); |
| 1589 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1619 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1590 | 1620 |
| 1591 if (!can_overflow) { | 1621 if (!can_overflow) { |
| 1592 if (right->IsStackSlot() || right->IsArgument()) { | 1622 if (right->IsStackSlot()) { |
| 1593 Register right_reg = EmitLoadRegister(right, at); | 1623 Register right_reg = EmitLoadRegister(right, at); |
| 1594 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg)); | 1624 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg)); |
| 1595 } else { | 1625 } else { |
| 1596 ASSERT(right->IsRegister() || right->IsConstantOperand()); | 1626 ASSERT(right->IsRegister() || right->IsConstantOperand()); |
| 1597 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right)); | 1627 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right)); |
| 1598 } | 1628 } |
| 1599 } else { // can_overflow. | 1629 } else { // can_overflow. |
| 1600 Register overflow = scratch0(); | 1630 Register overflow = scratch0(); |
| 1601 Register scratch = scratch1(); | 1631 Register scratch = scratch1(); |
| 1602 if (right->IsStackSlot() || | 1632 if (right->IsStackSlot() || right->IsConstantOperand()) { |
| 1603 right->IsArgument() || | |
| 1604 right->IsConstantOperand()) { | |
| 1605 Register right_reg = EmitLoadRegister(right, scratch); | 1633 Register right_reg = EmitLoadRegister(right, scratch); |
| 1606 __ SubuAndCheckForOverflow(ToRegister(result), | 1634 __ SubuAndCheckForOverflow(ToRegister(result), |
| 1607 ToRegister(left), | 1635 ToRegister(left), |
| 1608 right_reg, | 1636 right_reg, |
| 1609 overflow); // Reg at also used as scratch. | 1637 overflow); // Reg at also used as scratch. |
| 1610 } else { | 1638 } else { |
| 1611 ASSERT(right->IsRegister()); | 1639 ASSERT(right->IsRegister()); |
| 1612 // Due to overflow check macros not supporting constant operands, | 1640 // Due to overflow check macros not supporting constant operands, |
| 1613 // handling the IsConstantOperand case was moved to prev if clause. | 1641 // handling the IsConstantOperand case was moved to prev if clause. |
| 1614 __ SubuAndCheckForOverflow(ToRegister(result), | 1642 __ SubuAndCheckForOverflow(ToRegister(result), |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 } | 1802 } |
| 1775 | 1803 |
| 1776 | 1804 |
| 1777 void LCodeGen::DoAddI(LAddI* instr) { | 1805 void LCodeGen::DoAddI(LAddI* instr) { |
| 1778 LOperand* left = instr->left(); | 1806 LOperand* left = instr->left(); |
| 1779 LOperand* right = instr->right(); | 1807 LOperand* right = instr->right(); |
| 1780 LOperand* result = instr->result(); | 1808 LOperand* result = instr->result(); |
| 1781 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1809 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1782 | 1810 |
| 1783 if (!can_overflow) { | 1811 if (!can_overflow) { |
| 1784 if (right->IsStackSlot() || right->IsArgument()) { | 1812 if (right->IsStackSlot()) { |
| 1785 Register right_reg = EmitLoadRegister(right, at); | 1813 Register right_reg = EmitLoadRegister(right, at); |
| 1786 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg)); | 1814 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg)); |
| 1787 } else { | 1815 } else { |
| 1788 ASSERT(right->IsRegister() || right->IsConstantOperand()); | 1816 ASSERT(right->IsRegister() || right->IsConstantOperand()); |
| 1789 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right)); | 1817 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right)); |
| 1790 } | 1818 } |
| 1791 } else { // can_overflow. | 1819 } else { // can_overflow. |
| 1792 Register overflow = scratch0(); | 1820 Register overflow = scratch0(); |
| 1793 Register scratch = scratch1(); | 1821 Register scratch = scratch1(); |
| 1794 if (right->IsStackSlot() || | 1822 if (right->IsStackSlot() || |
| 1795 right->IsArgument() || | |
| 1796 right->IsConstantOperand()) { | 1823 right->IsConstantOperand()) { |
| 1797 Register right_reg = EmitLoadRegister(right, scratch); | 1824 Register right_reg = EmitLoadRegister(right, scratch); |
| 1798 __ AdduAndCheckForOverflow(ToRegister(result), | 1825 __ AdduAndCheckForOverflow(ToRegister(result), |
| 1799 ToRegister(left), | 1826 ToRegister(left), |
| 1800 right_reg, | 1827 right_reg, |
| 1801 overflow); // Reg at also used as scratch. | 1828 overflow); // Reg at also used as scratch. |
| 1802 } else { | 1829 } else { |
| 1803 ASSERT(right->IsRegister()); | 1830 ASSERT(right->IsRegister()); |
| 1804 // Due to overflow check macros not supporting constant operands, | 1831 // Due to overflow check macros not supporting constant operands, |
| 1805 // handling the IsConstantOperand case was moved to prev if clause. | 1832 // handling the IsConstantOperand case was moved to prev if clause. |
| (...skipping 1277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3083 case FLOAT64_ELEMENTS: | 3110 case FLOAT64_ELEMENTS: |
| 3084 case EXTERNAL_FLOAT32_ELEMENTS: | 3111 case EXTERNAL_FLOAT32_ELEMENTS: |
| 3085 case EXTERNAL_FLOAT64_ELEMENTS: | 3112 case EXTERNAL_FLOAT64_ELEMENTS: |
| 3086 case FAST_DOUBLE_ELEMENTS: | 3113 case FAST_DOUBLE_ELEMENTS: |
| 3087 case FAST_ELEMENTS: | 3114 case FAST_ELEMENTS: |
| 3088 case FAST_SMI_ELEMENTS: | 3115 case FAST_SMI_ELEMENTS: |
| 3089 case FAST_HOLEY_DOUBLE_ELEMENTS: | 3116 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 3090 case FAST_HOLEY_ELEMENTS: | 3117 case FAST_HOLEY_ELEMENTS: |
| 3091 case FAST_HOLEY_SMI_ELEMENTS: | 3118 case FAST_HOLEY_SMI_ELEMENTS: |
| 3092 case DICTIONARY_ELEMENTS: | 3119 case DICTIONARY_ELEMENTS: |
| 3093 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3120 case SLOPPY_ARGUMENTS_ELEMENTS: |
| 3094 UNREACHABLE(); | 3121 UNREACHABLE(); |
| 3095 break; | 3122 break; |
| 3096 } | 3123 } |
| 3097 } | 3124 } |
| 3098 } | 3125 } |
| 3099 | 3126 |
| 3100 | 3127 |
| 3101 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { | 3128 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { |
| 3102 Register elements = ToRegister(instr->elements()); | 3129 Register elements = ToRegister(instr->elements()); |
| 3103 bool key_is_constant = instr->key()->IsConstantOperand(); | 3130 bool key_is_constant = instr->key()->IsConstantOperand(); |
| (...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3883 } | 3910 } |
| 3884 | 3911 |
| 3885 | 3912 |
| 3886 void LCodeGen::DoCallNew(LCallNew* instr) { | 3913 void LCodeGen::DoCallNew(LCallNew* instr) { |
| 3887 ASSERT(ToRegister(instr->context()).is(cp)); | 3914 ASSERT(ToRegister(instr->context()).is(cp)); |
| 3888 ASSERT(ToRegister(instr->constructor()).is(a1)); | 3915 ASSERT(ToRegister(instr->constructor()).is(a1)); |
| 3889 ASSERT(ToRegister(instr->result()).is(v0)); | 3916 ASSERT(ToRegister(instr->result()).is(v0)); |
| 3890 | 3917 |
| 3891 __ li(a0, Operand(instr->arity())); | 3918 __ li(a0, Operand(instr->arity())); |
| 3892 // No cell in a2 for construct type feedback in optimized code | 3919 // No cell in a2 for construct type feedback in optimized code |
| 3893 Handle<Object> undefined_value(isolate()->factory()->undefined_value()); | 3920 Handle<Object> megamorphic_symbol = |
| 3894 __ li(a2, Operand(undefined_value)); | 3921 TypeFeedbackInfo::MegamorphicSentinel(isolate()); |
| 3922 __ li(a2, Operand(megamorphic_symbol)); |
| 3895 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); | 3923 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); |
| 3896 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 3924 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3897 } | 3925 } |
| 3898 | 3926 |
| 3899 | 3927 |
| 3900 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 3928 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
| 3901 ASSERT(ToRegister(instr->context()).is(cp)); | 3929 ASSERT(ToRegister(instr->context()).is(cp)); |
| 3902 ASSERT(ToRegister(instr->constructor()).is(a1)); | 3930 ASSERT(ToRegister(instr->constructor()).is(a1)); |
| 3903 ASSERT(ToRegister(instr->result()).is(v0)); | 3931 ASSERT(ToRegister(instr->result()).is(v0)); |
| 3904 | 3932 |
| 3905 __ li(a0, Operand(instr->arity())); | 3933 __ li(a0, Operand(instr->arity())); |
| 3906 __ li(a2, Operand(factory()->undefined_value())); | 3934 __ li(a2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate()))); |
| 3907 ElementsKind kind = instr->hydrogen()->elements_kind(); | 3935 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 3908 AllocationSiteOverrideMode override_mode = | 3936 AllocationSiteOverrideMode override_mode = |
| 3909 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) | 3937 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) |
| 3910 ? DISABLE_ALLOCATION_SITES | 3938 ? DISABLE_ALLOCATION_SITES |
| 3911 : DONT_OVERRIDE; | 3939 : DONT_OVERRIDE; |
| 3912 | 3940 |
| 3913 if (instr->arity() == 0) { | 3941 if (instr->arity() == 0) { |
| 3914 ArrayNoArgumentConstructorStub stub(kind, override_mode); | 3942 ArrayNoArgumentConstructorStub stub(kind, override_mode); |
| 3915 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 3943 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3916 } else if (instr->arity() == 1) { | 3944 } else if (instr->arity() == 1) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3980 MemOperand operand = MemOperand(object, offset); | 4008 MemOperand operand = MemOperand(object, offset); |
| 3981 __ Store(value, operand, representation); | 4009 __ Store(value, operand, representation); |
| 3982 return; | 4010 return; |
| 3983 } | 4011 } |
| 3984 | 4012 |
| 3985 Handle<Map> transition = instr->transition(); | 4013 Handle<Map> transition = instr->transition(); |
| 3986 SmiCheck check_needed = | 4014 SmiCheck check_needed = |
| 3987 instr->hydrogen()->value()->IsHeapObject() | 4015 instr->hydrogen()->value()->IsHeapObject() |
| 3988 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4016 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 3989 | 4017 |
| 3990 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { | 4018 if (representation.IsHeapObject()) { |
| 3991 Register value = ToRegister(instr->value()); | 4019 Register value = ToRegister(instr->value()); |
| 3992 if (!instr->hydrogen()->value()->type().IsHeapObject()) { | 4020 if (!instr->hydrogen()->value()->type().IsHeapObject()) { |
| 3993 __ SmiTst(value, scratch); | 4021 __ SmiTst(value, scratch); |
| 3994 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); | 4022 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); |
| 3995 | 4023 |
| 3996 // We know that value is a smi now, so we can omit the check below. | 4024 // We know that value is a smi now, so we can omit the check below. |
| 3997 check_needed = OMIT_SMI_CHECK; | 4025 check_needed = OMIT_SMI_CHECK; |
| 3998 } | 4026 } |
| 3999 } else if (representation.IsDouble()) { | 4027 } else if (representation.IsDouble()) { |
| 4000 ASSERT(transition.is_null()); | 4028 ASSERT(transition.is_null()); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4058 } | 4086 } |
| 4059 | 4087 |
| 4060 | 4088 |
| 4061 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 4089 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 4062 ASSERT(ToRegister(instr->context()).is(cp)); | 4090 ASSERT(ToRegister(instr->context()).is(cp)); |
| 4063 ASSERT(ToRegister(instr->object()).is(a1)); | 4091 ASSERT(ToRegister(instr->object()).is(a1)); |
| 4064 ASSERT(ToRegister(instr->value()).is(a0)); | 4092 ASSERT(ToRegister(instr->value()).is(a0)); |
| 4065 | 4093 |
| 4066 // Name is always in a2. | 4094 // Name is always in a2. |
| 4067 __ li(a2, Operand(instr->name())); | 4095 __ li(a2, Operand(instr->name())); |
| 4068 Handle<Code> ic = StoreIC::initialize_stub(isolate(), | 4096 Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode()); |
| 4069 instr->strict_mode_flag()); | |
| 4070 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4097 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4071 } | 4098 } |
| 4072 | 4099 |
| 4073 | 4100 |
| 4074 void LCodeGen::ApplyCheckIf(Condition condition, | 4101 void LCodeGen::ApplyCheckIf(Condition condition, |
| 4075 LBoundsCheck* check, | 4102 LBoundsCheck* check, |
| 4076 Register src1, | 4103 Register src1, |
| 4077 const Operand& src2) { | 4104 const Operand& src2) { |
| 4078 if (FLAG_debug_code && check->hydrogen()->skip_check()) { | 4105 if (FLAG_debug_code && check->hydrogen()->skip_check()) { |
| 4079 Label done; | 4106 Label done; |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4190 case FLOAT64_ELEMENTS: | 4217 case FLOAT64_ELEMENTS: |
| 4191 case EXTERNAL_FLOAT32_ELEMENTS: | 4218 case EXTERNAL_FLOAT32_ELEMENTS: |
| 4192 case EXTERNAL_FLOAT64_ELEMENTS: | 4219 case EXTERNAL_FLOAT64_ELEMENTS: |
| 4193 case FAST_DOUBLE_ELEMENTS: | 4220 case FAST_DOUBLE_ELEMENTS: |
| 4194 case FAST_ELEMENTS: | 4221 case FAST_ELEMENTS: |
| 4195 case FAST_SMI_ELEMENTS: | 4222 case FAST_SMI_ELEMENTS: |
| 4196 case FAST_HOLEY_DOUBLE_ELEMENTS: | 4223 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4197 case FAST_HOLEY_ELEMENTS: | 4224 case FAST_HOLEY_ELEMENTS: |
| 4198 case FAST_HOLEY_SMI_ELEMENTS: | 4225 case FAST_HOLEY_SMI_ELEMENTS: |
| 4199 case DICTIONARY_ELEMENTS: | 4226 case DICTIONARY_ELEMENTS: |
| 4200 case NON_STRICT_ARGUMENTS_ELEMENTS: | 4227 case SLOPPY_ARGUMENTS_ELEMENTS: |
| 4201 UNREACHABLE(); | 4228 UNREACHABLE(); |
| 4202 break; | 4229 break; |
| 4203 } | 4230 } |
| 4204 } | 4231 } |
| 4205 } | 4232 } |
| 4206 | 4233 |
| 4207 | 4234 |
| 4208 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { | 4235 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { |
| 4209 DoubleRegister value = ToDoubleRegister(instr->value()); | 4236 DoubleRegister value = ToDoubleRegister(instr->value()); |
| 4210 Register elements = ToRegister(instr->elements()); | 4237 Register elements = ToRegister(instr->elements()); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4315 } | 4342 } |
| 4316 } | 4343 } |
| 4317 | 4344 |
| 4318 | 4345 |
| 4319 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 4346 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| 4320 ASSERT(ToRegister(instr->context()).is(cp)); | 4347 ASSERT(ToRegister(instr->context()).is(cp)); |
| 4321 ASSERT(ToRegister(instr->object()).is(a2)); | 4348 ASSERT(ToRegister(instr->object()).is(a2)); |
| 4322 ASSERT(ToRegister(instr->key()).is(a1)); | 4349 ASSERT(ToRegister(instr->key()).is(a1)); |
| 4323 ASSERT(ToRegister(instr->value()).is(a0)); | 4350 ASSERT(ToRegister(instr->value()).is(a0)); |
| 4324 | 4351 |
| 4325 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) | 4352 Handle<Code> ic = (instr->strict_mode() == STRICT) |
| 4326 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 4353 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 4327 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 4354 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 4328 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4355 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4329 } | 4356 } |
| 4330 | 4357 |
| 4331 | 4358 |
| 4332 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { | 4359 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
| 4333 Register object_reg = ToRegister(instr->object()); | 4360 Register object_reg = ToRegister(instr->object()); |
| 4334 Register scratch = scratch0(); | 4361 Register scratch = scratch0(); |
| 4335 | 4362 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4501 Register scratch = scratch0(); | 4528 Register scratch = scratch0(); |
| 4502 __ lw(scratch, ToMemOperand(input)); | 4529 __ lw(scratch, ToMemOperand(input)); |
| 4503 __ mtc1(scratch, single_scratch); | 4530 __ mtc1(scratch, single_scratch); |
| 4504 } else { | 4531 } else { |
| 4505 __ mtc1(ToRegister(input), single_scratch); | 4532 __ mtc1(ToRegister(input), single_scratch); |
| 4506 } | 4533 } |
| 4507 __ cvt_d_w(ToDoubleRegister(output), single_scratch); | 4534 __ cvt_d_w(ToDoubleRegister(output), single_scratch); |
| 4508 } | 4535 } |
| 4509 | 4536 |
| 4510 | 4537 |
| 4511 void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) { | |
| 4512 LOperand* input = instr->value(); | |
| 4513 LOperand* output = instr->result(); | |
| 4514 Register scratch = scratch0(); | |
| 4515 | |
| 4516 ASSERT(output->IsRegister()); | |
| 4517 if (!instr->hydrogen()->value()->HasRange() || | |
| 4518 !instr->hydrogen()->value()->range()->IsInSmiRange()) { | |
| 4519 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch); | |
| 4520 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg)); | |
| 4521 } else { | |
| 4522 __ SmiTag(ToRegister(output), ToRegister(input)); | |
| 4523 } | |
| 4524 } | |
| 4525 | |
| 4526 | |
| 4527 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { | 4538 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { |
| 4528 LOperand* input = instr->value(); | 4539 LOperand* input = instr->value(); |
| 4529 LOperand* output = instr->result(); | 4540 LOperand* output = instr->result(); |
| 4530 | 4541 |
| 4531 FPURegister dbl_scratch = double_scratch0(); | 4542 FPURegister dbl_scratch = double_scratch0(); |
| 4532 __ mtc1(ToRegister(input), dbl_scratch); | 4543 __ mtc1(ToRegister(input), dbl_scratch); |
| 4533 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22); | 4544 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22); |
| 4534 } | 4545 } |
| 4535 | 4546 |
| 4536 | 4547 |
| 4537 void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) { | |
| 4538 LOperand* input = instr->value(); | |
| 4539 LOperand* output = instr->result(); | |
| 4540 if (!instr->hydrogen()->value()->HasRange() || | |
| 4541 !instr->hydrogen()->value()->range()->IsInSmiRange()) { | |
| 4542 Register scratch = scratch0(); | |
| 4543 __ And(scratch, ToRegister(input), Operand(0xc0000000)); | |
| 4544 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); | |
| 4545 } | |
| 4546 __ SmiTag(ToRegister(output), ToRegister(input)); | |
| 4547 } | |
| 4548 | |
| 4549 | |
| 4550 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { | 4548 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
| 4551 class DeferredNumberTagI V8_FINAL : public LDeferredCode { | 4549 class DeferredNumberTagI V8_FINAL : public LDeferredCode { |
| 4552 public: | 4550 public: |
| 4553 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) | 4551 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) |
| 4554 : LDeferredCode(codegen), instr_(instr) { } | 4552 : LDeferredCode(codegen), instr_(instr) { } |
| 4555 virtual void Generate() V8_OVERRIDE { | 4553 virtual void Generate() V8_OVERRIDE { |
| 4556 codegen()->DoDeferredNumberTagI(instr_, | 4554 codegen()->DoDeferredNumberTagIU(instr_, |
| 4557 instr_->value(), | 4555 instr_->value(), |
| 4558 SIGNED_INT32); | 4556 instr_->temp1(), |
| 4557 instr_->temp2(), |
| 4558 SIGNED_INT32); |
| 4559 } | 4559 } |
| 4560 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } | 4560 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
| 4561 private: | 4561 private: |
| 4562 LNumberTagI* instr_; | 4562 LNumberTagI* instr_; |
| 4563 }; | 4563 }; |
| 4564 | 4564 |
| 4565 Register src = ToRegister(instr->value()); | 4565 Register src = ToRegister(instr->value()); |
| 4566 Register dst = ToRegister(instr->result()); | 4566 Register dst = ToRegister(instr->result()); |
| 4567 Register overflow = scratch0(); | 4567 Register overflow = scratch0(); |
| 4568 | 4568 |
| 4569 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); | 4569 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); |
| 4570 __ SmiTagCheckOverflow(dst, src, overflow); | 4570 __ SmiTagCheckOverflow(dst, src, overflow); |
| 4571 __ BranchOnOverflow(deferred->entry(), overflow); | 4571 __ BranchOnOverflow(deferred->entry(), overflow); |
| 4572 __ bind(deferred->exit()); | 4572 __ bind(deferred->exit()); |
| 4573 } | 4573 } |
| 4574 | 4574 |
| 4575 | 4575 |
| 4576 void LCodeGen::DoNumberTagU(LNumberTagU* instr) { | 4576 void LCodeGen::DoNumberTagU(LNumberTagU* instr) { |
| 4577 class DeferredNumberTagU V8_FINAL : public LDeferredCode { | 4577 class DeferredNumberTagU V8_FINAL : public LDeferredCode { |
| 4578 public: | 4578 public: |
| 4579 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) | 4579 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) |
| 4580 : LDeferredCode(codegen), instr_(instr) { } | 4580 : LDeferredCode(codegen), instr_(instr) { } |
| 4581 virtual void Generate() V8_OVERRIDE { | 4581 virtual void Generate() V8_OVERRIDE { |
| 4582 codegen()->DoDeferredNumberTagI(instr_, | 4582 codegen()->DoDeferredNumberTagIU(instr_, |
| 4583 instr_->value(), | 4583 instr_->value(), |
| 4584 UNSIGNED_INT32); | 4584 instr_->temp1(), |
| 4585 instr_->temp2(), |
| 4586 UNSIGNED_INT32); |
| 4585 } | 4587 } |
| 4586 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } | 4588 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
| 4587 private: | 4589 private: |
| 4588 LNumberTagU* instr_; | 4590 LNumberTagU* instr_; |
| 4589 }; | 4591 }; |
| 4590 | 4592 |
| 4591 Register input = ToRegister(instr->value()); | 4593 Register input = ToRegister(instr->value()); |
| 4592 Register result = ToRegister(instr->result()); | 4594 Register result = ToRegister(instr->result()); |
| 4593 | 4595 |
| 4594 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr); | 4596 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr); |
| 4595 __ Branch(deferred->entry(), hi, input, Operand(Smi::kMaxValue)); | 4597 __ Branch(deferred->entry(), hi, input, Operand(Smi::kMaxValue)); |
| 4596 __ SmiTag(result, input); | 4598 __ SmiTag(result, input); |
| 4597 __ bind(deferred->exit()); | 4599 __ bind(deferred->exit()); |
| 4598 } | 4600 } |
| 4599 | 4601 |
| 4600 | 4602 |
| 4601 void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, | 4603 void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr, |
| 4602 LOperand* value, | 4604 LOperand* value, |
| 4603 IntegerSignedness signedness) { | 4605 LOperand* temp1, |
| 4604 Label slow; | 4606 LOperand* temp2, |
| 4607 IntegerSignedness signedness) { |
| 4608 Label done, slow; |
| 4605 Register src = ToRegister(value); | 4609 Register src = ToRegister(value); |
| 4606 Register dst = ToRegister(instr->result()); | 4610 Register dst = ToRegister(instr->result()); |
| 4611 Register tmp1 = scratch0(); |
| 4612 Register tmp2 = ToRegister(temp1); |
| 4613 Register tmp3 = ToRegister(temp2); |
| 4607 DoubleRegister dbl_scratch = double_scratch0(); | 4614 DoubleRegister dbl_scratch = double_scratch0(); |
| 4608 | 4615 |
| 4609 // Preserve the value of all registers. | |
| 4610 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); | |
| 4611 | |
| 4612 Label done; | |
| 4613 if (signedness == SIGNED_INT32) { | 4616 if (signedness == SIGNED_INT32) { |
| 4614 // There was overflow, so bits 30 and 31 of the original integer | 4617 // There was overflow, so bits 30 and 31 of the original integer |
| 4615 // disagree. Try to allocate a heap number in new space and store | 4618 // disagree. Try to allocate a heap number in new space and store |
| 4616 // the value in there. If that fails, call the runtime system. | 4619 // the value in there. If that fails, call the runtime system. |
| 4617 if (dst.is(src)) { | 4620 if (dst.is(src)) { |
| 4618 __ SmiUntag(src, dst); | 4621 __ SmiUntag(src, dst); |
| 4619 __ Xor(src, src, Operand(0x80000000)); | 4622 __ Xor(src, src, Operand(0x80000000)); |
| 4620 } | 4623 } |
| 4621 __ mtc1(src, dbl_scratch); | 4624 __ mtc1(src, dbl_scratch); |
| 4622 __ cvt_d_w(dbl_scratch, dbl_scratch); | 4625 __ cvt_d_w(dbl_scratch, dbl_scratch); |
| 4623 } else { | 4626 } else { |
| 4624 __ mtc1(src, dbl_scratch); | 4627 __ mtc1(src, dbl_scratch); |
| 4625 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22); | 4628 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22); |
| 4626 } | 4629 } |
| 4627 | 4630 |
| 4628 if (FLAG_inline_new) { | 4631 if (FLAG_inline_new) { |
| 4629 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex); | 4632 __ LoadRoot(tmp3, Heap::kHeapNumberMapRootIndex); |
| 4630 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT); | 4633 __ AllocateHeapNumber(dst, tmp1, tmp2, tmp3, &slow, DONT_TAG_RESULT); |
| 4631 __ Move(dst, t1); | |
| 4632 __ Branch(&done); | 4634 __ Branch(&done); |
| 4633 } | 4635 } |
| 4634 | 4636 |
| 4635 // Slow case: Call the runtime system to do the number allocation. | 4637 // Slow case: Call the runtime system to do the number allocation. |
| 4636 __ bind(&slow); | 4638 __ bind(&slow); |
| 4639 { |
| 4640 // TODO(3095996): Put a valid pointer value in the stack slot where the |
| 4641 // result register is stored, as this register is in the pointer map, but |
| 4642 // contains an integer value. |
| 4643 __ mov(dst, zero_reg); |
| 4637 | 4644 |
| 4638 // TODO(3095996): Put a valid pointer value in the stack slot where the result | 4645 // Preserve the value of all registers. |
| 4639 // register is stored, as this register is in the pointer map, but contains an | 4646 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
| 4640 // integer value. | 4647 |
| 4641 __ StoreToSafepointRegisterSlot(zero_reg, dst); | 4648 // NumberTagI and NumberTagD use the context from the frame, rather than |
| 4642 // NumberTagI and NumberTagD use the context from the frame, rather than | 4649 // the environment's HContext or HInlinedContext value. |
| 4643 // the environment's HContext or HInlinedContext value. | 4650 // They only call Runtime::kAllocateHeapNumber. |
| 4644 // They only call Runtime::kAllocateHeapNumber. | 4651 // The corresponding HChange instructions are added in a phase that does |
| 4645 // The corresponding HChange instructions are added in a phase that does | 4652 // not have easy access to the local context. |
| 4646 // not have easy access to the local context. | 4653 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4647 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4654 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 4648 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 4655 RecordSafepointWithRegisters( |
| 4649 RecordSafepointWithRegisters( | 4656 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4650 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 4657 __ Subu(v0, v0, kHeapObjectTag); |
| 4651 __ Move(dst, v0); | 4658 __ StoreToSafepointRegisterSlot(v0, dst); |
| 4652 __ Subu(dst, dst, kHeapObjectTag); | 4659 } |
| 4660 |
| 4653 | 4661 |
| 4654 // Done. Put the value in dbl_scratch into the value of the allocated heap | 4662 // Done. Put the value in dbl_scratch into the value of the allocated heap |
| 4655 // number. | 4663 // number. |
| 4656 __ bind(&done); | 4664 __ bind(&done); |
| 4657 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset)); | 4665 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset)); |
| 4658 __ Addu(dst, dst, kHeapObjectTag); | 4666 __ Addu(dst, dst, kHeapObjectTag); |
| 4659 __ StoreToSafepointRegisterSlot(dst, dst); | |
| 4660 } | 4667 } |
| 4661 | 4668 |
| 4662 | 4669 |
| 4663 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 4670 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| 4664 class DeferredNumberTagD V8_FINAL : public LDeferredCode { | 4671 class DeferredNumberTagD V8_FINAL : public LDeferredCode { |
| 4665 public: | 4672 public: |
| 4666 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) | 4673 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
| 4667 : LDeferredCode(codegen), instr_(instr) { } | 4674 : LDeferredCode(codegen), instr_(instr) { } |
| 4668 virtual void Generate() V8_OVERRIDE { | 4675 virtual void Generate() V8_OVERRIDE { |
| 4669 codegen()->DoDeferredNumberTagD(instr_); | 4676 codegen()->DoDeferredNumberTagD(instr_); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4711 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4718 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4712 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 4719 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 4713 RecordSafepointWithRegisters( | 4720 RecordSafepointWithRegisters( |
| 4714 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 4721 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4715 __ Subu(v0, v0, kHeapObjectTag); | 4722 __ Subu(v0, v0, kHeapObjectTag); |
| 4716 __ StoreToSafepointRegisterSlot(v0, reg); | 4723 __ StoreToSafepointRegisterSlot(v0, reg); |
| 4717 } | 4724 } |
| 4718 | 4725 |
| 4719 | 4726 |
| 4720 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 4727 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 4721 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 4728 HChange* hchange = instr->hydrogen(); |
| 4722 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value())); | 4729 Register input = ToRegister(instr->value()); |
| 4730 Register output = ToRegister(instr->result()); |
| 4731 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4732 hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4733 __ And(at, input, Operand(0xc0000000)); |
| 4734 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); |
| 4735 } |
| 4736 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4737 !hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4738 __ SmiTagCheckOverflow(output, input, at); |
| 4739 DeoptimizeIf(lt, instr->environment(), at, Operand(zero_reg)); |
| 4740 } else { |
| 4741 __ SmiTag(output, input); |
| 4742 } |
| 4723 } | 4743 } |
| 4724 | 4744 |
| 4725 | 4745 |
| 4726 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 4746 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 4727 Register scratch = scratch0(); | 4747 Register scratch = scratch0(); |
| 4728 Register input = ToRegister(instr->value()); | 4748 Register input = ToRegister(instr->value()); |
| 4729 Register result = ToRegister(instr->result()); | 4749 Register result = ToRegister(instr->result()); |
| 4730 if (instr->needs_check()) { | 4750 if (instr->needs_check()) { |
| 4731 STATIC_ASSERT(kHeapObjectTag == 1); | 4751 STATIC_ASSERT(kHeapObjectTag == 1); |
| 4732 // If the input is a HeapObject, value of scratch won't be zero. | 4752 // If the input is a HeapObject, value of scratch won't be zero. |
| (...skipping 440 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5173 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg); | 5193 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg); |
| 5174 __ jmp(&done); | 5194 __ jmp(&done); |
| 5175 | 5195 |
| 5176 __ bind(&is_smi); | 5196 __ bind(&is_smi); |
| 5177 __ ClampUint8(result_reg, scratch); | 5197 __ ClampUint8(result_reg, scratch); |
| 5178 | 5198 |
| 5179 __ bind(&done); | 5199 __ bind(&done); |
| 5180 } | 5200 } |
| 5181 | 5201 |
| 5182 | 5202 |
| 5203 void LCodeGen::DoDoubleBits(LDoubleBits* instr) { |
| 5204 DoubleRegister value_reg = ToDoubleRegister(instr->value()); |
| 5205 Register result_reg = ToRegister(instr->result()); |
| 5206 if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { |
| 5207 __ FmoveHigh(result_reg, value_reg); |
| 5208 } else { |
| 5209 __ FmoveLow(result_reg, value_reg); |
| 5210 } |
| 5211 } |
| 5212 |
| 5213 |
| 5214 void LCodeGen::DoConstructDouble(LConstructDouble* instr) { |
| 5215 Register hi_reg = ToRegister(instr->hi()); |
| 5216 Register lo_reg = ToRegister(instr->lo()); |
| 5217 DoubleRegister result_reg = ToDoubleRegister(instr->result()); |
| 5218 __ Move(result_reg, lo_reg, hi_reg); |
| 5219 } |
| 5220 |
| 5221 |
| 5183 void LCodeGen::DoAllocate(LAllocate* instr) { | 5222 void LCodeGen::DoAllocate(LAllocate* instr) { |
| 5184 class DeferredAllocate V8_FINAL : public LDeferredCode { | 5223 class DeferredAllocate V8_FINAL : public LDeferredCode { |
| 5185 public: | 5224 public: |
| 5186 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) | 5225 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
| 5187 : LDeferredCode(codegen), instr_(instr) { } | 5226 : LDeferredCode(codegen), instr_(instr) { } |
| 5188 virtual void Generate() V8_OVERRIDE { | 5227 virtual void Generate() V8_OVERRIDE { |
| 5189 codegen()->DoDeferredAllocate(instr_); | 5228 codegen()->DoDeferredAllocate(instr_); |
| 5190 } | 5229 } |
| 5191 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } | 5230 virtual LInstruction* instr() V8_OVERRIDE { return instr_; } |
| 5192 private: | 5231 private: |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5352 } | 5391 } |
| 5353 } | 5392 } |
| 5354 | 5393 |
| 5355 | 5394 |
| 5356 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 5395 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
| 5357 ASSERT(ToRegister(instr->context()).is(cp)); | 5396 ASSERT(ToRegister(instr->context()).is(cp)); |
| 5358 // Use the fast case closure allocation code that allocates in new | 5397 // Use the fast case closure allocation code that allocates in new |
| 5359 // space for nested functions that don't need literals cloning. | 5398 // space for nested functions that don't need literals cloning. |
| 5360 bool pretenure = instr->hydrogen()->pretenure(); | 5399 bool pretenure = instr->hydrogen()->pretenure(); |
| 5361 if (!pretenure && instr->hydrogen()->has_no_literals()) { | 5400 if (!pretenure && instr->hydrogen()->has_no_literals()) { |
| 5362 FastNewClosureStub stub(instr->hydrogen()->language_mode(), | 5401 FastNewClosureStub stub(instr->hydrogen()->strict_mode(), |
| 5363 instr->hydrogen()->is_generator()); | 5402 instr->hydrogen()->is_generator()); |
| 5364 __ li(a2, Operand(instr->hydrogen()->shared_info())); | 5403 __ li(a2, Operand(instr->hydrogen()->shared_info())); |
| 5365 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | 5404 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 5366 } else { | 5405 } else { |
| 5367 __ li(a2, Operand(instr->hydrogen()->shared_info())); | 5406 __ li(a2, Operand(instr->hydrogen()->shared_info())); |
| 5368 __ li(a1, Operand(pretenure ? factory()->true_value() | 5407 __ li(a1, Operand(pretenure ? factory()->true_value() |
| 5369 : factory()->false_value())); | 5408 : factory()->false_value())); |
| 5370 __ Push(cp, a2, a1); | 5409 __ Push(cp, a2, a1); |
| 5371 CallRuntime(Runtime::kNewClosure, 3, instr); | 5410 CallRuntime(Runtime::kNewClosure, 3, instr); |
| 5372 } | 5411 } |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5753 __ Subu(scratch, result, scratch); | 5792 __ Subu(scratch, result, scratch); |
| 5754 __ lw(result, FieldMemOperand(scratch, | 5793 __ lw(result, FieldMemOperand(scratch, |
| 5755 FixedArray::kHeaderSize - kPointerSize)); | 5794 FixedArray::kHeaderSize - kPointerSize)); |
| 5756 __ bind(&done); | 5795 __ bind(&done); |
| 5757 } | 5796 } |
| 5758 | 5797 |
| 5759 | 5798 |
| 5760 #undef __ | 5799 #undef __ |
| 5761 | 5800 |
| 5762 } } // namespace v8::internal | 5801 } } // namespace v8::internal |
| OLD | NEW |