| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/arm/lithium-codegen-arm.h" | 7 #include "src/arm/lithium-codegen-arm.h" |
| 8 #include "src/arm/lithium-gap-resolver-arm.h" | 8 #include "src/arm/lithium-gap-resolver-arm.h" |
| 9 #include "src/base/bits.h" | 9 #include "src/base/bits.h" |
| 10 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
| (...skipping 1140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); | 1151 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1152 Label dividend_is_not_negative, done; | 1152 Label dividend_is_not_negative, done; |
| 1153 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { | 1153 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { |
| 1154 __ cmp(dividend, Operand::Zero()); | 1154 __ cmp(dividend, Operand::Zero()); |
| 1155 __ b(pl, ÷nd_is_not_negative); | 1155 __ b(pl, ÷nd_is_not_negative); |
| 1156 // Note that this is correct even for kMinInt operands. | 1156 // Note that this is correct even for kMinInt operands. |
| 1157 __ rsb(dividend, dividend, Operand::Zero()); | 1157 __ rsb(dividend, dividend, Operand::Zero()); |
| 1158 __ and_(dividend, dividend, Operand(mask)); | 1158 __ and_(dividend, dividend, Operand(mask)); |
| 1159 __ rsb(dividend, dividend, Operand::Zero(), SetCC); | 1159 __ rsb(dividend, dividend, Operand::Zero(), SetCC); |
| 1160 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1160 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1161 DeoptimizeIf(eq, instr); | 1161 DeoptimizeIf(eq, instr, "minus zero"); |
| 1162 } | 1162 } |
| 1163 __ b(&done); | 1163 __ b(&done); |
| 1164 } | 1164 } |
| 1165 | 1165 |
| 1166 __ bind(÷nd_is_not_negative); | 1166 __ bind(÷nd_is_not_negative); |
| 1167 __ and_(dividend, dividend, Operand(mask)); | 1167 __ and_(dividend, dividend, Operand(mask)); |
| 1168 __ bind(&done); | 1168 __ bind(&done); |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 | 1171 |
| 1172 void LCodeGen::DoModByConstI(LModByConstI* instr) { | 1172 void LCodeGen::DoModByConstI(LModByConstI* instr) { |
| 1173 Register dividend = ToRegister(instr->dividend()); | 1173 Register dividend = ToRegister(instr->dividend()); |
| 1174 int32_t divisor = instr->divisor(); | 1174 int32_t divisor = instr->divisor(); |
| 1175 Register result = ToRegister(instr->result()); | 1175 Register result = ToRegister(instr->result()); |
| 1176 DCHECK(!dividend.is(result)); | 1176 DCHECK(!dividend.is(result)); |
| 1177 | 1177 |
| 1178 if (divisor == 0) { | 1178 if (divisor == 0) { |
| 1179 DeoptimizeIf(al, instr); | 1179 DeoptimizeIf(al, instr, "division by zero"); |
| 1180 return; | 1180 return; |
| 1181 } | 1181 } |
| 1182 | 1182 |
| 1183 __ TruncatingDiv(result, dividend, Abs(divisor)); | 1183 __ TruncatingDiv(result, dividend, Abs(divisor)); |
| 1184 __ mov(ip, Operand(Abs(divisor))); | 1184 __ mov(ip, Operand(Abs(divisor))); |
| 1185 __ smull(result, ip, result, ip); | 1185 __ smull(result, ip, result, ip); |
| 1186 __ sub(result, dividend, result, SetCC); | 1186 __ sub(result, dividend, result, SetCC); |
| 1187 | 1187 |
| 1188 // Check for negative zero. | 1188 // Check for negative zero. |
| 1189 HMod* hmod = instr->hydrogen(); | 1189 HMod* hmod = instr->hydrogen(); |
| 1190 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1190 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1191 Label remainder_not_zero; | 1191 Label remainder_not_zero; |
| 1192 __ b(ne, &remainder_not_zero); | 1192 __ b(ne, &remainder_not_zero); |
| 1193 __ cmp(dividend, Operand::Zero()); | 1193 __ cmp(dividend, Operand::Zero()); |
| 1194 DeoptimizeIf(lt, instr); | 1194 DeoptimizeIf(lt, instr, "minus zero"); |
| 1195 __ bind(&remainder_not_zero); | 1195 __ bind(&remainder_not_zero); |
| 1196 } | 1196 } |
| 1197 } | 1197 } |
| 1198 | 1198 |
| 1199 | 1199 |
| 1200 void LCodeGen::DoModI(LModI* instr) { | 1200 void LCodeGen::DoModI(LModI* instr) { |
| 1201 HMod* hmod = instr->hydrogen(); | 1201 HMod* hmod = instr->hydrogen(); |
| 1202 if (CpuFeatures::IsSupported(SUDIV)) { | 1202 if (CpuFeatures::IsSupported(SUDIV)) { |
| 1203 CpuFeatureScope scope(masm(), SUDIV); | 1203 CpuFeatureScope scope(masm(), SUDIV); |
| 1204 | 1204 |
| 1205 Register left_reg = ToRegister(instr->left()); | 1205 Register left_reg = ToRegister(instr->left()); |
| 1206 Register right_reg = ToRegister(instr->right()); | 1206 Register right_reg = ToRegister(instr->right()); |
| 1207 Register result_reg = ToRegister(instr->result()); | 1207 Register result_reg = ToRegister(instr->result()); |
| 1208 | 1208 |
| 1209 Label done; | 1209 Label done; |
| 1210 // Check for x % 0, sdiv might signal an exception. We have to deopt in this | 1210 // Check for x % 0, sdiv might signal an exception. We have to deopt in this |
| 1211 // case because we can't return a NaN. | 1211 // case because we can't return a NaN. |
| 1212 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { | 1212 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1213 __ cmp(right_reg, Operand::Zero()); | 1213 __ cmp(right_reg, Operand::Zero()); |
| 1214 DeoptimizeIf(eq, instr); | 1214 DeoptimizeIf(eq, instr, "division by zero"); |
| 1215 } | 1215 } |
| 1216 | 1216 |
| 1217 // Check for kMinInt % -1, sdiv will return kMinInt, which is not what we | 1217 // Check for kMinInt % -1, sdiv will return kMinInt, which is not what we |
| 1218 // want. We have to deopt if we care about -0, because we can't return that. | 1218 // want. We have to deopt if we care about -0, because we can't return that. |
| 1219 if (hmod->CheckFlag(HValue::kCanOverflow)) { | 1219 if (hmod->CheckFlag(HValue::kCanOverflow)) { |
| 1220 Label no_overflow_possible; | 1220 Label no_overflow_possible; |
| 1221 __ cmp(left_reg, Operand(kMinInt)); | 1221 __ cmp(left_reg, Operand(kMinInt)); |
| 1222 __ b(ne, &no_overflow_possible); | 1222 __ b(ne, &no_overflow_possible); |
| 1223 __ cmp(right_reg, Operand(-1)); | 1223 __ cmp(right_reg, Operand(-1)); |
| 1224 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1224 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1225 DeoptimizeIf(eq, instr); | 1225 DeoptimizeIf(eq, instr, "minus zero"); |
| 1226 } else { | 1226 } else { |
| 1227 __ b(ne, &no_overflow_possible); | 1227 __ b(ne, &no_overflow_possible); |
| 1228 __ mov(result_reg, Operand::Zero()); | 1228 __ mov(result_reg, Operand::Zero()); |
| 1229 __ jmp(&done); | 1229 __ jmp(&done); |
| 1230 } | 1230 } |
| 1231 __ bind(&no_overflow_possible); | 1231 __ bind(&no_overflow_possible); |
| 1232 } | 1232 } |
| 1233 | 1233 |
| 1234 // For 'r3 = r1 % r2' we can have the following ARM code: | 1234 // For 'r3 = r1 % r2' we can have the following ARM code: |
| 1235 // sdiv r3, r1, r2 | 1235 // sdiv r3, r1, r2 |
| 1236 // mls r3, r3, r2, r1 | 1236 // mls r3, r3, r2, r1 |
| 1237 | 1237 |
| 1238 __ sdiv(result_reg, left_reg, right_reg); | 1238 __ sdiv(result_reg, left_reg, right_reg); |
| 1239 __ Mls(result_reg, result_reg, right_reg, left_reg); | 1239 __ Mls(result_reg, result_reg, right_reg, left_reg); |
| 1240 | 1240 |
| 1241 // If we care about -0, test if the dividend is <0 and the result is 0. | 1241 // If we care about -0, test if the dividend is <0 and the result is 0. |
| 1242 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1242 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1243 __ cmp(result_reg, Operand::Zero()); | 1243 __ cmp(result_reg, Operand::Zero()); |
| 1244 __ b(ne, &done); | 1244 __ b(ne, &done); |
| 1245 __ cmp(left_reg, Operand::Zero()); | 1245 __ cmp(left_reg, Operand::Zero()); |
| 1246 DeoptimizeIf(lt, instr); | 1246 DeoptimizeIf(lt, instr, "minus zero"); |
| 1247 } | 1247 } |
| 1248 __ bind(&done); | 1248 __ bind(&done); |
| 1249 | 1249 |
| 1250 } else { | 1250 } else { |
| 1251 // General case, without any SDIV support. | 1251 // General case, without any SDIV support. |
| 1252 Register left_reg = ToRegister(instr->left()); | 1252 Register left_reg = ToRegister(instr->left()); |
| 1253 Register right_reg = ToRegister(instr->right()); | 1253 Register right_reg = ToRegister(instr->right()); |
| 1254 Register result_reg = ToRegister(instr->result()); | 1254 Register result_reg = ToRegister(instr->result()); |
| 1255 Register scratch = scratch0(); | 1255 Register scratch = scratch0(); |
| 1256 DCHECK(!scratch.is(left_reg)); | 1256 DCHECK(!scratch.is(left_reg)); |
| 1257 DCHECK(!scratch.is(right_reg)); | 1257 DCHECK(!scratch.is(right_reg)); |
| 1258 DCHECK(!scratch.is(result_reg)); | 1258 DCHECK(!scratch.is(result_reg)); |
| 1259 DwVfpRegister dividend = ToDoubleRegister(instr->temp()); | 1259 DwVfpRegister dividend = ToDoubleRegister(instr->temp()); |
| 1260 DwVfpRegister divisor = ToDoubleRegister(instr->temp2()); | 1260 DwVfpRegister divisor = ToDoubleRegister(instr->temp2()); |
| 1261 DCHECK(!divisor.is(dividend)); | 1261 DCHECK(!divisor.is(dividend)); |
| 1262 LowDwVfpRegister quotient = double_scratch0(); | 1262 LowDwVfpRegister quotient = double_scratch0(); |
| 1263 DCHECK(!quotient.is(dividend)); | 1263 DCHECK(!quotient.is(dividend)); |
| 1264 DCHECK(!quotient.is(divisor)); | 1264 DCHECK(!quotient.is(divisor)); |
| 1265 | 1265 |
| 1266 Label done; | 1266 Label done; |
| 1267 // Check for x % 0, we have to deopt in this case because we can't return a | 1267 // Check for x % 0, we have to deopt in this case because we can't return a |
| 1268 // NaN. | 1268 // NaN. |
| 1269 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { | 1269 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1270 __ cmp(right_reg, Operand::Zero()); | 1270 __ cmp(right_reg, Operand::Zero()); |
| 1271 DeoptimizeIf(eq, instr); | 1271 DeoptimizeIf(eq, instr, "division by zero"); |
| 1272 } | 1272 } |
| 1273 | 1273 |
| 1274 __ Move(result_reg, left_reg); | 1274 __ Move(result_reg, left_reg); |
| 1275 // Load the arguments in VFP registers. The divisor value is preloaded | 1275 // Load the arguments in VFP registers. The divisor value is preloaded |
| 1276 // before. Be careful that 'right_reg' is only live on entry. | 1276 // before. Be careful that 'right_reg' is only live on entry. |
| 1277 // TODO(svenpanne) The last comments seems to be wrong nowadays. | 1277 // TODO(svenpanne) The last comments seems to be wrong nowadays. |
| 1278 __ vmov(double_scratch0().low(), left_reg); | 1278 __ vmov(double_scratch0().low(), left_reg); |
| 1279 __ vcvt_f64_s32(dividend, double_scratch0().low()); | 1279 __ vcvt_f64_s32(dividend, double_scratch0().low()); |
| 1280 __ vmov(double_scratch0().low(), right_reg); | 1280 __ vmov(double_scratch0().low(), right_reg); |
| 1281 __ vcvt_f64_s32(divisor, double_scratch0().low()); | 1281 __ vcvt_f64_s32(divisor, double_scratch0().low()); |
| 1282 | 1282 |
| 1283 // We do not care about the sign of the divisor. Note that we still handle | 1283 // We do not care about the sign of the divisor. Note that we still handle |
| 1284 // the kMinInt % -1 case correctly, though. | 1284 // the kMinInt % -1 case correctly, though. |
| 1285 __ vabs(divisor, divisor); | 1285 __ vabs(divisor, divisor); |
| 1286 // Compute the quotient and round it to a 32bit integer. | 1286 // Compute the quotient and round it to a 32bit integer. |
| 1287 __ vdiv(quotient, dividend, divisor); | 1287 __ vdiv(quotient, dividend, divisor); |
| 1288 __ vcvt_s32_f64(quotient.low(), quotient); | 1288 __ vcvt_s32_f64(quotient.low(), quotient); |
| 1289 __ vcvt_f64_s32(quotient, quotient.low()); | 1289 __ vcvt_f64_s32(quotient, quotient.low()); |
| 1290 | 1290 |
| 1291 // Compute the remainder in result. | 1291 // Compute the remainder in result. |
| 1292 __ vmul(double_scratch0(), divisor, quotient); | 1292 __ vmul(double_scratch0(), divisor, quotient); |
| 1293 __ vcvt_s32_f64(double_scratch0().low(), double_scratch0()); | 1293 __ vcvt_s32_f64(double_scratch0().low(), double_scratch0()); |
| 1294 __ vmov(scratch, double_scratch0().low()); | 1294 __ vmov(scratch, double_scratch0().low()); |
| 1295 __ sub(result_reg, left_reg, scratch, SetCC); | 1295 __ sub(result_reg, left_reg, scratch, SetCC); |
| 1296 | 1296 |
| 1297 // If we care about -0, test if the dividend is <0 and the result is 0. | 1297 // If we care about -0, test if the dividend is <0 and the result is 0. |
| 1298 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1298 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1299 __ b(ne, &done); | 1299 __ b(ne, &done); |
| 1300 __ cmp(left_reg, Operand::Zero()); | 1300 __ cmp(left_reg, Operand::Zero()); |
| 1301 DeoptimizeIf(mi, instr); | 1301 DeoptimizeIf(mi, instr, "minus zero"); |
| 1302 } | 1302 } |
| 1303 __ bind(&done); | 1303 __ bind(&done); |
| 1304 } | 1304 } |
| 1305 } | 1305 } |
| 1306 | 1306 |
| 1307 | 1307 |
| 1308 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { | 1308 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { |
| 1309 Register dividend = ToRegister(instr->dividend()); | 1309 Register dividend = ToRegister(instr->dividend()); |
| 1310 int32_t divisor = instr->divisor(); | 1310 int32_t divisor = instr->divisor(); |
| 1311 Register result = ToRegister(instr->result()); | 1311 Register result = ToRegister(instr->result()); |
| 1312 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); | 1312 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); |
| 1313 DCHECK(!result.is(dividend)); | 1313 DCHECK(!result.is(dividend)); |
| 1314 | 1314 |
| 1315 // Check for (0 / -x) that will produce negative zero. | 1315 // Check for (0 / -x) that will produce negative zero. |
| 1316 HDiv* hdiv = instr->hydrogen(); | 1316 HDiv* hdiv = instr->hydrogen(); |
| 1317 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1317 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1318 __ cmp(dividend, Operand::Zero()); | 1318 __ cmp(dividend, Operand::Zero()); |
| 1319 DeoptimizeIf(eq, instr); | 1319 DeoptimizeIf(eq, instr, "minus zero"); |
| 1320 } | 1320 } |
| 1321 // Check for (kMinInt / -1). | 1321 // Check for (kMinInt / -1). |
| 1322 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { | 1322 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { |
| 1323 __ cmp(dividend, Operand(kMinInt)); | 1323 __ cmp(dividend, Operand(kMinInt)); |
| 1324 DeoptimizeIf(eq, instr); | 1324 DeoptimizeIf(eq, instr, "overflow"); |
| 1325 } | 1325 } |
| 1326 // Deoptimize if remainder will not be 0. | 1326 // Deoptimize if remainder will not be 0. |
| 1327 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && | 1327 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && |
| 1328 divisor != 1 && divisor != -1) { | 1328 divisor != 1 && divisor != -1) { |
| 1329 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); | 1329 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); |
| 1330 __ tst(dividend, Operand(mask)); | 1330 __ tst(dividend, Operand(mask)); |
| 1331 DeoptimizeIf(ne, instr); | 1331 DeoptimizeIf(ne, instr, "lost precision"); |
| 1332 } | 1332 } |
| 1333 | 1333 |
| 1334 if (divisor == -1) { // Nice shortcut, not needed for correctness. | 1334 if (divisor == -1) { // Nice shortcut, not needed for correctness. |
| 1335 __ rsb(result, dividend, Operand(0)); | 1335 __ rsb(result, dividend, Operand(0)); |
| 1336 return; | 1336 return; |
| 1337 } | 1337 } |
| 1338 int32_t shift = WhichPowerOf2Abs(divisor); | 1338 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1339 if (shift == 0) { | 1339 if (shift == 0) { |
| 1340 __ mov(result, dividend); | 1340 __ mov(result, dividend); |
| 1341 } else if (shift == 1) { | 1341 } else if (shift == 1) { |
| 1342 __ add(result, dividend, Operand(dividend, LSR, 31)); | 1342 __ add(result, dividend, Operand(dividend, LSR, 31)); |
| 1343 } else { | 1343 } else { |
| 1344 __ mov(result, Operand(dividend, ASR, 31)); | 1344 __ mov(result, Operand(dividend, ASR, 31)); |
| 1345 __ add(result, dividend, Operand(result, LSR, 32 - shift)); | 1345 __ add(result, dividend, Operand(result, LSR, 32 - shift)); |
| 1346 } | 1346 } |
| 1347 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); | 1347 if (shift > 0) __ mov(result, Operand(result, ASR, shift)); |
| 1348 if (divisor < 0) __ rsb(result, result, Operand(0)); | 1348 if (divisor < 0) __ rsb(result, result, Operand(0)); |
| 1349 } | 1349 } |
| 1350 | 1350 |
| 1351 | 1351 |
| 1352 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { | 1352 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { |
| 1353 Register dividend = ToRegister(instr->dividend()); | 1353 Register dividend = ToRegister(instr->dividend()); |
| 1354 int32_t divisor = instr->divisor(); | 1354 int32_t divisor = instr->divisor(); |
| 1355 Register result = ToRegister(instr->result()); | 1355 Register result = ToRegister(instr->result()); |
| 1356 DCHECK(!dividend.is(result)); | 1356 DCHECK(!dividend.is(result)); |
| 1357 | 1357 |
| 1358 if (divisor == 0) { | 1358 if (divisor == 0) { |
| 1359 DeoptimizeIf(al, instr); | 1359 DeoptimizeIf(al, instr, "division by zero"); |
| 1360 return; | 1360 return; |
| 1361 } | 1361 } |
| 1362 | 1362 |
| 1363 // Check for (0 / -x) that will produce negative zero. | 1363 // Check for (0 / -x) that will produce negative zero. |
| 1364 HDiv* hdiv = instr->hydrogen(); | 1364 HDiv* hdiv = instr->hydrogen(); |
| 1365 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1365 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1366 __ cmp(dividend, Operand::Zero()); | 1366 __ cmp(dividend, Operand::Zero()); |
| 1367 DeoptimizeIf(eq, instr); | 1367 DeoptimizeIf(eq, instr, "minus zero"); |
| 1368 } | 1368 } |
| 1369 | 1369 |
| 1370 __ TruncatingDiv(result, dividend, Abs(divisor)); | 1370 __ TruncatingDiv(result, dividend, Abs(divisor)); |
| 1371 if (divisor < 0) __ rsb(result, result, Operand::Zero()); | 1371 if (divisor < 0) __ rsb(result, result, Operand::Zero()); |
| 1372 | 1372 |
| 1373 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { | 1373 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { |
| 1374 __ mov(ip, Operand(divisor)); | 1374 __ mov(ip, Operand(divisor)); |
| 1375 __ smull(scratch0(), ip, result, ip); | 1375 __ smull(scratch0(), ip, result, ip); |
| 1376 __ sub(scratch0(), scratch0(), dividend, SetCC); | 1376 __ sub(scratch0(), scratch0(), dividend, SetCC); |
| 1377 DeoptimizeIf(ne, instr); | 1377 DeoptimizeIf(ne, instr, "lost precision"); |
| 1378 } | 1378 } |
| 1379 } | 1379 } |
| 1380 | 1380 |
| 1381 | 1381 |
| 1382 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. | 1382 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. |
| 1383 void LCodeGen::DoDivI(LDivI* instr) { | 1383 void LCodeGen::DoDivI(LDivI* instr) { |
| 1384 HBinaryOperation* hdiv = instr->hydrogen(); | 1384 HBinaryOperation* hdiv = instr->hydrogen(); |
| 1385 Register dividend = ToRegister(instr->dividend()); | 1385 Register dividend = ToRegister(instr->dividend()); |
| 1386 Register divisor = ToRegister(instr->divisor()); | 1386 Register divisor = ToRegister(instr->divisor()); |
| 1387 Register result = ToRegister(instr->result()); | 1387 Register result = ToRegister(instr->result()); |
| 1388 | 1388 |
| 1389 // Check for x / 0. | 1389 // Check for x / 0. |
| 1390 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { | 1390 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1391 __ cmp(divisor, Operand::Zero()); | 1391 __ cmp(divisor, Operand::Zero()); |
| 1392 DeoptimizeIf(eq, instr); | 1392 DeoptimizeIf(eq, instr, "division by zero"); |
| 1393 } | 1393 } |
| 1394 | 1394 |
| 1395 // Check for (0 / -x) that will produce negative zero. | 1395 // Check for (0 / -x) that will produce negative zero. |
| 1396 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1396 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1397 Label positive; | 1397 Label positive; |
| 1398 if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { | 1398 if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1399 // Do the test only if it hadn't be done above. | 1399 // Do the test only if it hadn't be done above. |
| 1400 __ cmp(divisor, Operand::Zero()); | 1400 __ cmp(divisor, Operand::Zero()); |
| 1401 } | 1401 } |
| 1402 __ b(pl, &positive); | 1402 __ b(pl, &positive); |
| 1403 __ cmp(dividend, Operand::Zero()); | 1403 __ cmp(dividend, Operand::Zero()); |
| 1404 DeoptimizeIf(eq, instr); | 1404 DeoptimizeIf(eq, instr, "minus zero"); |
| 1405 __ bind(&positive); | 1405 __ bind(&positive); |
| 1406 } | 1406 } |
| 1407 | 1407 |
| 1408 // Check for (kMinInt / -1). | 1408 // Check for (kMinInt / -1). |
| 1409 if (hdiv->CheckFlag(HValue::kCanOverflow) && | 1409 if (hdiv->CheckFlag(HValue::kCanOverflow) && |
| 1410 (!CpuFeatures::IsSupported(SUDIV) || | 1410 (!CpuFeatures::IsSupported(SUDIV) || |
| 1411 !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) { | 1411 !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) { |
| 1412 // We don't need to check for overflow when truncating with sdiv | 1412 // We don't need to check for overflow when truncating with sdiv |
| 1413 // support because, on ARM, sdiv kMinInt, -1 -> kMinInt. | 1413 // support because, on ARM, sdiv kMinInt, -1 -> kMinInt. |
| 1414 __ cmp(dividend, Operand(kMinInt)); | 1414 __ cmp(dividend, Operand(kMinInt)); |
| 1415 __ cmp(divisor, Operand(-1), eq); | 1415 __ cmp(divisor, Operand(-1), eq); |
| 1416 DeoptimizeIf(eq, instr); | 1416 DeoptimizeIf(eq, instr, "overflow"); |
| 1417 } | 1417 } |
| 1418 | 1418 |
| 1419 if (CpuFeatures::IsSupported(SUDIV)) { | 1419 if (CpuFeatures::IsSupported(SUDIV)) { |
| 1420 CpuFeatureScope scope(masm(), SUDIV); | 1420 CpuFeatureScope scope(masm(), SUDIV); |
| 1421 __ sdiv(result, dividend, divisor); | 1421 __ sdiv(result, dividend, divisor); |
| 1422 } else { | 1422 } else { |
| 1423 DoubleRegister vleft = ToDoubleRegister(instr->temp()); | 1423 DoubleRegister vleft = ToDoubleRegister(instr->temp()); |
| 1424 DoubleRegister vright = double_scratch0(); | 1424 DoubleRegister vright = double_scratch0(); |
| 1425 __ vmov(double_scratch0().low(), dividend); | 1425 __ vmov(double_scratch0().low(), dividend); |
| 1426 __ vcvt_f64_s32(vleft, double_scratch0().low()); | 1426 __ vcvt_f64_s32(vleft, double_scratch0().low()); |
| 1427 __ vmov(double_scratch0().low(), divisor); | 1427 __ vmov(double_scratch0().low(), divisor); |
| 1428 __ vcvt_f64_s32(vright, double_scratch0().low()); | 1428 __ vcvt_f64_s32(vright, double_scratch0().low()); |
| 1429 __ vdiv(vleft, vleft, vright); // vleft now contains the result. | 1429 __ vdiv(vleft, vleft, vright); // vleft now contains the result. |
| 1430 __ vcvt_s32_f64(double_scratch0().low(), vleft); | 1430 __ vcvt_s32_f64(double_scratch0().low(), vleft); |
| 1431 __ vmov(result, double_scratch0().low()); | 1431 __ vmov(result, double_scratch0().low()); |
| 1432 } | 1432 } |
| 1433 | 1433 |
| 1434 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { | 1434 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { |
| 1435 // Compute remainder and deopt if it's not zero. | 1435 // Compute remainder and deopt if it's not zero. |
| 1436 Register remainder = scratch0(); | 1436 Register remainder = scratch0(); |
| 1437 __ Mls(remainder, result, divisor, dividend); | 1437 __ Mls(remainder, result, divisor, dividend); |
| 1438 __ cmp(remainder, Operand::Zero()); | 1438 __ cmp(remainder, Operand::Zero()); |
| 1439 DeoptimizeIf(ne, instr); | 1439 DeoptimizeIf(ne, instr, "lost precision"); |
| 1440 } | 1440 } |
| 1441 } | 1441 } |
| 1442 | 1442 |
| 1443 | 1443 |
| 1444 void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { | 1444 void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { |
| 1445 DwVfpRegister addend = ToDoubleRegister(instr->addend()); | 1445 DwVfpRegister addend = ToDoubleRegister(instr->addend()); |
| 1446 DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier()); | 1446 DwVfpRegister multiplier = ToDoubleRegister(instr->multiplier()); |
| 1447 DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand()); | 1447 DwVfpRegister multiplicand = ToDoubleRegister(instr->multiplicand()); |
| 1448 | 1448 |
| 1449 // This is computed in-place. | 1449 // This is computed in-place. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1480 // can simply do an arithmetic right shift. | 1480 // can simply do an arithmetic right shift. |
| 1481 int32_t shift = WhichPowerOf2Abs(divisor); | 1481 int32_t shift = WhichPowerOf2Abs(divisor); |
| 1482 if (divisor > 1) { | 1482 if (divisor > 1) { |
| 1483 __ mov(result, Operand(dividend, ASR, shift)); | 1483 __ mov(result, Operand(dividend, ASR, shift)); |
| 1484 return; | 1484 return; |
| 1485 } | 1485 } |
| 1486 | 1486 |
| 1487 // If the divisor is negative, we have to negate and handle edge cases. | 1487 // If the divisor is negative, we have to negate and handle edge cases. |
| 1488 __ rsb(result, dividend, Operand::Zero(), SetCC); | 1488 __ rsb(result, dividend, Operand::Zero(), SetCC); |
| 1489 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1489 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1490 DeoptimizeIf(eq, instr); | 1490 DeoptimizeIf(eq, instr, "minus zero"); |
| 1491 } | 1491 } |
| 1492 | 1492 |
| 1493 // Dividing by -1 is basically negation, unless we overflow. | 1493 // Dividing by -1 is basically negation, unless we overflow. |
| 1494 if (divisor == -1) { | 1494 if (divisor == -1) { |
| 1495 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { | 1495 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1496 DeoptimizeIf(vs, instr); | 1496 DeoptimizeIf(vs, instr, "overflow"); |
| 1497 } | 1497 } |
| 1498 return; | 1498 return; |
| 1499 } | 1499 } |
| 1500 | 1500 |
| 1501 // If the negation could not overflow, simply shifting is OK. | 1501 // If the negation could not overflow, simply shifting is OK. |
| 1502 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { | 1502 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { |
| 1503 __ mov(result, Operand(result, ASR, shift)); | 1503 __ mov(result, Operand(result, ASR, shift)); |
| 1504 return; | 1504 return; |
| 1505 } | 1505 } |
| 1506 | 1506 |
| 1507 __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs); | 1507 __ mov(result, Operand(kMinInt / divisor), LeaveCC, vs); |
| 1508 __ mov(result, Operand(result, ASR, shift), LeaveCC, vc); | 1508 __ mov(result, Operand(result, ASR, shift), LeaveCC, vc); |
| 1509 } | 1509 } |
| 1510 | 1510 |
| 1511 | 1511 |
| 1512 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { | 1512 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { |
| 1513 Register dividend = ToRegister(instr->dividend()); | 1513 Register dividend = ToRegister(instr->dividend()); |
| 1514 int32_t divisor = instr->divisor(); | 1514 int32_t divisor = instr->divisor(); |
| 1515 Register result = ToRegister(instr->result()); | 1515 Register result = ToRegister(instr->result()); |
| 1516 DCHECK(!dividend.is(result)); | 1516 DCHECK(!dividend.is(result)); |
| 1517 | 1517 |
| 1518 if (divisor == 0) { | 1518 if (divisor == 0) { |
| 1519 DeoptimizeIf(al, instr); | 1519 DeoptimizeIf(al, instr, "division by zero"); |
| 1520 return; | 1520 return; |
| 1521 } | 1521 } |
| 1522 | 1522 |
| 1523 // Check for (0 / -x) that will produce negative zero. | 1523 // Check for (0 / -x) that will produce negative zero. |
| 1524 HMathFloorOfDiv* hdiv = instr->hydrogen(); | 1524 HMathFloorOfDiv* hdiv = instr->hydrogen(); |
| 1525 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { | 1525 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { |
| 1526 __ cmp(dividend, Operand::Zero()); | 1526 __ cmp(dividend, Operand::Zero()); |
| 1527 DeoptimizeIf(eq, instr); | 1527 DeoptimizeIf(eq, instr, "minus zero"); |
| 1528 } | 1528 } |
| 1529 | 1529 |
| 1530 // Easy case: We need no dynamic check for the dividend and the flooring | 1530 // Easy case: We need no dynamic check for the dividend and the flooring |
| 1531 // division is the same as the truncating division. | 1531 // division is the same as the truncating division. |
| 1532 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || | 1532 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || |
| 1533 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { | 1533 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { |
| 1534 __ TruncatingDiv(result, dividend, Abs(divisor)); | 1534 __ TruncatingDiv(result, dividend, Abs(divisor)); |
| 1535 if (divisor < 0) __ rsb(result, result, Operand::Zero()); | 1535 if (divisor < 0) __ rsb(result, result, Operand::Zero()); |
| 1536 return; | 1536 return; |
| 1537 } | 1537 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1558 // TODO(svenpanne) Refactor this to avoid code duplication with DoDivI. | 1558 // TODO(svenpanne) Refactor this to avoid code duplication with DoDivI. |
| 1559 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) { | 1559 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) { |
| 1560 HBinaryOperation* hdiv = instr->hydrogen(); | 1560 HBinaryOperation* hdiv = instr->hydrogen(); |
| 1561 Register left = ToRegister(instr->dividend()); | 1561 Register left = ToRegister(instr->dividend()); |
| 1562 Register right = ToRegister(instr->divisor()); | 1562 Register right = ToRegister(instr->divisor()); |
| 1563 Register result = ToRegister(instr->result()); | 1563 Register result = ToRegister(instr->result()); |
| 1564 | 1564 |
| 1565 // Check for x / 0. | 1565 // Check for x / 0. |
| 1566 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { | 1566 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1567 __ cmp(right, Operand::Zero()); | 1567 __ cmp(right, Operand::Zero()); |
| 1568 DeoptimizeIf(eq, instr); | 1568 DeoptimizeIf(eq, instr, "division by zero"); |
| 1569 } | 1569 } |
| 1570 | 1570 |
| 1571 // Check for (0 / -x) that will produce negative zero. | 1571 // Check for (0 / -x) that will produce negative zero. |
| 1572 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1572 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1573 Label positive; | 1573 Label positive; |
| 1574 if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { | 1574 if (!instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) { |
| 1575 // Do the test only if it hadn't be done above. | 1575 // Do the test only if it hadn't be done above. |
| 1576 __ cmp(right, Operand::Zero()); | 1576 __ cmp(right, Operand::Zero()); |
| 1577 } | 1577 } |
| 1578 __ b(pl, &positive); | 1578 __ b(pl, &positive); |
| 1579 __ cmp(left, Operand::Zero()); | 1579 __ cmp(left, Operand::Zero()); |
| 1580 DeoptimizeIf(eq, instr); | 1580 DeoptimizeIf(eq, instr, "minus zero"); |
| 1581 __ bind(&positive); | 1581 __ bind(&positive); |
| 1582 } | 1582 } |
| 1583 | 1583 |
| 1584 // Check for (kMinInt / -1). | 1584 // Check for (kMinInt / -1). |
| 1585 if (hdiv->CheckFlag(HValue::kCanOverflow) && | 1585 if (hdiv->CheckFlag(HValue::kCanOverflow) && |
| 1586 (!CpuFeatures::IsSupported(SUDIV) || | 1586 (!CpuFeatures::IsSupported(SUDIV) || |
| 1587 !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) { | 1587 !hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32))) { |
| 1588 // We don't need to check for overflow when truncating with sdiv | 1588 // We don't need to check for overflow when truncating with sdiv |
| 1589 // support because, on ARM, sdiv kMinInt, -1 -> kMinInt. | 1589 // support because, on ARM, sdiv kMinInt, -1 -> kMinInt. |
| 1590 __ cmp(left, Operand(kMinInt)); | 1590 __ cmp(left, Operand(kMinInt)); |
| 1591 __ cmp(right, Operand(-1), eq); | 1591 __ cmp(right, Operand(-1), eq); |
| 1592 DeoptimizeIf(eq, instr); | 1592 DeoptimizeIf(eq, instr, "overflow"); |
| 1593 } | 1593 } |
| 1594 | 1594 |
| 1595 if (CpuFeatures::IsSupported(SUDIV)) { | 1595 if (CpuFeatures::IsSupported(SUDIV)) { |
| 1596 CpuFeatureScope scope(masm(), SUDIV); | 1596 CpuFeatureScope scope(masm(), SUDIV); |
| 1597 __ sdiv(result, left, right); | 1597 __ sdiv(result, left, right); |
| 1598 } else { | 1598 } else { |
| 1599 DoubleRegister vleft = ToDoubleRegister(instr->temp()); | 1599 DoubleRegister vleft = ToDoubleRegister(instr->temp()); |
| 1600 DoubleRegister vright = double_scratch0(); | 1600 DoubleRegister vright = double_scratch0(); |
| 1601 __ vmov(double_scratch0().low(), left); | 1601 __ vmov(double_scratch0().low(), left); |
| 1602 __ vcvt_f64_s32(vleft, double_scratch0().low()); | 1602 __ vcvt_f64_s32(vleft, double_scratch0().low()); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1628 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); | 1628 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); |
| 1629 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1629 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1630 | 1630 |
| 1631 if (right_op->IsConstantOperand()) { | 1631 if (right_op->IsConstantOperand()) { |
| 1632 int32_t constant = ToInteger32(LConstantOperand::cast(right_op)); | 1632 int32_t constant = ToInteger32(LConstantOperand::cast(right_op)); |
| 1633 | 1633 |
| 1634 if (bailout_on_minus_zero && (constant < 0)) { | 1634 if (bailout_on_minus_zero && (constant < 0)) { |
| 1635 // The case of a null constant will be handled separately. | 1635 // The case of a null constant will be handled separately. |
| 1636 // If constant is negative and left is null, the result should be -0. | 1636 // If constant is negative and left is null, the result should be -0. |
| 1637 __ cmp(left, Operand::Zero()); | 1637 __ cmp(left, Operand::Zero()); |
| 1638 DeoptimizeIf(eq, instr); | 1638 DeoptimizeIf(eq, instr, "minus zero"); |
| 1639 } | 1639 } |
| 1640 | 1640 |
| 1641 switch (constant) { | 1641 switch (constant) { |
| 1642 case -1: | 1642 case -1: |
| 1643 if (overflow) { | 1643 if (overflow) { |
| 1644 __ rsb(result, left, Operand::Zero(), SetCC); | 1644 __ rsb(result, left, Operand::Zero(), SetCC); |
| 1645 DeoptimizeIf(vs, instr); | 1645 DeoptimizeIf(vs, instr, "overflow"); |
| 1646 } else { | 1646 } else { |
| 1647 __ rsb(result, left, Operand::Zero()); | 1647 __ rsb(result, left, Operand::Zero()); |
| 1648 } | 1648 } |
| 1649 break; | 1649 break; |
| 1650 case 0: | 1650 case 0: |
| 1651 if (bailout_on_minus_zero) { | 1651 if (bailout_on_minus_zero) { |
| 1652 // If left is strictly negative and the constant is null, the | 1652 // If left is strictly negative and the constant is null, the |
| 1653 // result is -0. Deoptimize if required, otherwise return 0. | 1653 // result is -0. Deoptimize if required, otherwise return 0. |
| 1654 __ cmp(left, Operand::Zero()); | 1654 __ cmp(left, Operand::Zero()); |
| 1655 DeoptimizeIf(mi, instr); | 1655 DeoptimizeIf(mi, instr, "minus zero"); |
| 1656 } | 1656 } |
| 1657 __ mov(result, Operand::Zero()); | 1657 __ mov(result, Operand::Zero()); |
| 1658 break; | 1658 break; |
| 1659 case 1: | 1659 case 1: |
| 1660 __ Move(result, left); | 1660 __ Move(result, left); |
| 1661 break; | 1661 break; |
| 1662 default: | 1662 default: |
| 1663 // Multiplying by powers of two and powers of two plus or minus | 1663 // Multiplying by powers of two and powers of two plus or minus |
| 1664 // one can be done faster with shifted operands. | 1664 // one can be done faster with shifted operands. |
| 1665 // For other constants we emit standard code. | 1665 // For other constants we emit standard code. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1695 if (overflow) { | 1695 if (overflow) { |
| 1696 Register scratch = scratch0(); | 1696 Register scratch = scratch0(); |
| 1697 // scratch:result = left * right. | 1697 // scratch:result = left * right. |
| 1698 if (instr->hydrogen()->representation().IsSmi()) { | 1698 if (instr->hydrogen()->representation().IsSmi()) { |
| 1699 __ SmiUntag(result, left); | 1699 __ SmiUntag(result, left); |
| 1700 __ smull(result, scratch, result, right); | 1700 __ smull(result, scratch, result, right); |
| 1701 } else { | 1701 } else { |
| 1702 __ smull(result, scratch, left, right); | 1702 __ smull(result, scratch, left, right); |
| 1703 } | 1703 } |
| 1704 __ cmp(scratch, Operand(result, ASR, 31)); | 1704 __ cmp(scratch, Operand(result, ASR, 31)); |
| 1705 DeoptimizeIf(ne, instr); | 1705 DeoptimizeIf(ne, instr, "overflow"); |
| 1706 } else { | 1706 } else { |
| 1707 if (instr->hydrogen()->representation().IsSmi()) { | 1707 if (instr->hydrogen()->representation().IsSmi()) { |
| 1708 __ SmiUntag(result, left); | 1708 __ SmiUntag(result, left); |
| 1709 __ mul(result, result, right); | 1709 __ mul(result, result, right); |
| 1710 } else { | 1710 } else { |
| 1711 __ mul(result, left, right); | 1711 __ mul(result, left, right); |
| 1712 } | 1712 } |
| 1713 } | 1713 } |
| 1714 | 1714 |
| 1715 if (bailout_on_minus_zero) { | 1715 if (bailout_on_minus_zero) { |
| 1716 Label done; | 1716 Label done; |
| 1717 __ teq(left, Operand(right)); | 1717 __ teq(left, Operand(right)); |
| 1718 __ b(pl, &done); | 1718 __ b(pl, &done); |
| 1719 // Bail out if the result is minus zero. | 1719 // Bail out if the result is minus zero. |
| 1720 __ cmp(result, Operand::Zero()); | 1720 __ cmp(result, Operand::Zero()); |
| 1721 DeoptimizeIf(eq, instr); | 1721 DeoptimizeIf(eq, instr, "minus zero"); |
| 1722 __ bind(&done); | 1722 __ bind(&done); |
| 1723 } | 1723 } |
| 1724 } | 1724 } |
| 1725 } | 1725 } |
| 1726 | 1726 |
| 1727 | 1727 |
| 1728 void LCodeGen::DoBitI(LBitI* instr) { | 1728 void LCodeGen::DoBitI(LBitI* instr) { |
| 1729 LOperand* left_op = instr->left(); | 1729 LOperand* left_op = instr->left(); |
| 1730 LOperand* right_op = instr->right(); | 1730 LOperand* right_op = instr->right(); |
| 1731 DCHECK(left_op->IsRegister()); | 1731 DCHECK(left_op->IsRegister()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1774 switch (instr->op()) { | 1774 switch (instr->op()) { |
| 1775 case Token::ROR: | 1775 case Token::ROR: |
| 1776 __ mov(result, Operand(left, ROR, scratch)); | 1776 __ mov(result, Operand(left, ROR, scratch)); |
| 1777 break; | 1777 break; |
| 1778 case Token::SAR: | 1778 case Token::SAR: |
| 1779 __ mov(result, Operand(left, ASR, scratch)); | 1779 __ mov(result, Operand(left, ASR, scratch)); |
| 1780 break; | 1780 break; |
| 1781 case Token::SHR: | 1781 case Token::SHR: |
| 1782 if (instr->can_deopt()) { | 1782 if (instr->can_deopt()) { |
| 1783 __ mov(result, Operand(left, LSR, scratch), SetCC); | 1783 __ mov(result, Operand(left, LSR, scratch), SetCC); |
| 1784 DeoptimizeIf(mi, instr); | 1784 DeoptimizeIf(mi, instr, "negative value"); |
| 1785 } else { | 1785 } else { |
| 1786 __ mov(result, Operand(left, LSR, scratch)); | 1786 __ mov(result, Operand(left, LSR, scratch)); |
| 1787 } | 1787 } |
| 1788 break; | 1788 break; |
| 1789 case Token::SHL: | 1789 case Token::SHL: |
| 1790 __ mov(result, Operand(left, LSL, scratch)); | 1790 __ mov(result, Operand(left, LSL, scratch)); |
| 1791 break; | 1791 break; |
| 1792 default: | 1792 default: |
| 1793 UNREACHABLE(); | 1793 UNREACHABLE(); |
| 1794 break; | 1794 break; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1811 } else { | 1811 } else { |
| 1812 __ Move(result, left); | 1812 __ Move(result, left); |
| 1813 } | 1813 } |
| 1814 break; | 1814 break; |
| 1815 case Token::SHR: | 1815 case Token::SHR: |
| 1816 if (shift_count != 0) { | 1816 if (shift_count != 0) { |
| 1817 __ mov(result, Operand(left, LSR, shift_count)); | 1817 __ mov(result, Operand(left, LSR, shift_count)); |
| 1818 } else { | 1818 } else { |
| 1819 if (instr->can_deopt()) { | 1819 if (instr->can_deopt()) { |
| 1820 __ tst(left, Operand(0x80000000)); | 1820 __ tst(left, Operand(0x80000000)); |
| 1821 DeoptimizeIf(ne, instr); | 1821 DeoptimizeIf(ne, instr, "negative value"); |
| 1822 } | 1822 } |
| 1823 __ Move(result, left); | 1823 __ Move(result, left); |
| 1824 } | 1824 } |
| 1825 break; | 1825 break; |
| 1826 case Token::SHL: | 1826 case Token::SHL: |
| 1827 if (shift_count != 0) { | 1827 if (shift_count != 0) { |
| 1828 if (instr->hydrogen_value()->representation().IsSmi() && | 1828 if (instr->hydrogen_value()->representation().IsSmi() && |
| 1829 instr->can_deopt()) { | 1829 instr->can_deopt()) { |
| 1830 if (shift_count != 1) { | 1830 if (shift_count != 1) { |
| 1831 __ mov(result, Operand(left, LSL, shift_count - 1)); | 1831 __ mov(result, Operand(left, LSL, shift_count - 1)); |
| 1832 __ SmiTag(result, result, SetCC); | 1832 __ SmiTag(result, result, SetCC); |
| 1833 } else { | 1833 } else { |
| 1834 __ SmiTag(result, left, SetCC); | 1834 __ SmiTag(result, left, SetCC); |
| 1835 } | 1835 } |
| 1836 DeoptimizeIf(vs, instr); | 1836 DeoptimizeIf(vs, instr, "overflow"); |
| 1837 } else { | 1837 } else { |
| 1838 __ mov(result, Operand(left, LSL, shift_count)); | 1838 __ mov(result, Operand(left, LSL, shift_count)); |
| 1839 } | 1839 } |
| 1840 } else { | 1840 } else { |
| 1841 __ Move(result, left); | 1841 __ Move(result, left); |
| 1842 } | 1842 } |
| 1843 break; | 1843 break; |
| 1844 default: | 1844 default: |
| 1845 UNREACHABLE(); | 1845 UNREACHABLE(); |
| 1846 break; | 1846 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1858 | 1858 |
| 1859 if (right->IsStackSlot()) { | 1859 if (right->IsStackSlot()) { |
| 1860 Register right_reg = EmitLoadRegister(right, ip); | 1860 Register right_reg = EmitLoadRegister(right, ip); |
| 1861 __ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); | 1861 __ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); |
| 1862 } else { | 1862 } else { |
| 1863 DCHECK(right->IsRegister() || right->IsConstantOperand()); | 1863 DCHECK(right->IsRegister() || right->IsConstantOperand()); |
| 1864 __ sub(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); | 1864 __ sub(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); |
| 1865 } | 1865 } |
| 1866 | 1866 |
| 1867 if (can_overflow) { | 1867 if (can_overflow) { |
| 1868 DeoptimizeIf(vs, instr); | 1868 DeoptimizeIf(vs, instr, "overflow"); |
| 1869 } | 1869 } |
| 1870 } | 1870 } |
| 1871 | 1871 |
| 1872 | 1872 |
| 1873 void LCodeGen::DoRSubI(LRSubI* instr) { | 1873 void LCodeGen::DoRSubI(LRSubI* instr) { |
| 1874 LOperand* left = instr->left(); | 1874 LOperand* left = instr->left(); |
| 1875 LOperand* right = instr->right(); | 1875 LOperand* right = instr->right(); |
| 1876 LOperand* result = instr->result(); | 1876 LOperand* result = instr->result(); |
| 1877 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1877 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1878 SBit set_cond = can_overflow ? SetCC : LeaveCC; | 1878 SBit set_cond = can_overflow ? SetCC : LeaveCC; |
| 1879 | 1879 |
| 1880 if (right->IsStackSlot()) { | 1880 if (right->IsStackSlot()) { |
| 1881 Register right_reg = EmitLoadRegister(right, ip); | 1881 Register right_reg = EmitLoadRegister(right, ip); |
| 1882 __ rsb(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); | 1882 __ rsb(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); |
| 1883 } else { | 1883 } else { |
| 1884 DCHECK(right->IsRegister() || right->IsConstantOperand()); | 1884 DCHECK(right->IsRegister() || right->IsConstantOperand()); |
| 1885 __ rsb(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); | 1885 __ rsb(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); |
| 1886 } | 1886 } |
| 1887 | 1887 |
| 1888 if (can_overflow) { | 1888 if (can_overflow) { |
| 1889 DeoptimizeIf(vs, instr); | 1889 DeoptimizeIf(vs, instr, "overflow"); |
| 1890 } | 1890 } |
| 1891 } | 1891 } |
| 1892 | 1892 |
| 1893 | 1893 |
| 1894 void LCodeGen::DoConstantI(LConstantI* instr) { | 1894 void LCodeGen::DoConstantI(LConstantI* instr) { |
| 1895 __ mov(ToRegister(instr->result()), Operand(instr->value())); | 1895 __ mov(ToRegister(instr->result()), Operand(instr->value())); |
| 1896 } | 1896 } |
| 1897 | 1897 |
| 1898 | 1898 |
| 1899 void LCodeGen::DoConstantS(LConstantS* instr) { | 1899 void LCodeGen::DoConstantS(LConstantS* instr) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1933 Register result = ToRegister(instr->result()); | 1933 Register result = ToRegister(instr->result()); |
| 1934 Register scratch = ToRegister(instr->temp()); | 1934 Register scratch = ToRegister(instr->temp()); |
| 1935 Smi* index = instr->index(); | 1935 Smi* index = instr->index(); |
| 1936 Label runtime, done; | 1936 Label runtime, done; |
| 1937 DCHECK(object.is(result)); | 1937 DCHECK(object.is(result)); |
| 1938 DCHECK(object.is(r0)); | 1938 DCHECK(object.is(r0)); |
| 1939 DCHECK(!scratch.is(scratch0())); | 1939 DCHECK(!scratch.is(scratch0())); |
| 1940 DCHECK(!scratch.is(object)); | 1940 DCHECK(!scratch.is(object)); |
| 1941 | 1941 |
| 1942 __ SmiTst(object); | 1942 __ SmiTst(object); |
| 1943 DeoptimizeIf(eq, instr); | 1943 DeoptimizeIf(eq, instr, "Smi"); |
| 1944 __ CompareObjectType(object, scratch, scratch, JS_DATE_TYPE); | 1944 __ CompareObjectType(object, scratch, scratch, JS_DATE_TYPE); |
| 1945 DeoptimizeIf(ne, instr); | 1945 DeoptimizeIf(ne, instr, "not a date object"); |
| 1946 | 1946 |
| 1947 if (index->value() == 0) { | 1947 if (index->value() == 0) { |
| 1948 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset)); | 1948 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset)); |
| 1949 } else { | 1949 } else { |
| 1950 if (index->value() < JSDate::kFirstUncachedField) { | 1950 if (index->value() < JSDate::kFirstUncachedField) { |
| 1951 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 1951 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
| 1952 __ mov(scratch, Operand(stamp)); | 1952 __ mov(scratch, Operand(stamp)); |
| 1953 __ ldr(scratch, MemOperand(scratch)); | 1953 __ ldr(scratch, MemOperand(scratch)); |
| 1954 __ ldr(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset)); | 1954 __ ldr(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset)); |
| 1955 __ cmp(scratch, scratch0()); | 1955 __ cmp(scratch, scratch0()); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2052 | 2052 |
| 2053 if (right->IsStackSlot()) { | 2053 if (right->IsStackSlot()) { |
| 2054 Register right_reg = EmitLoadRegister(right, ip); | 2054 Register right_reg = EmitLoadRegister(right, ip); |
| 2055 __ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); | 2055 __ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond); |
| 2056 } else { | 2056 } else { |
| 2057 DCHECK(right->IsRegister() || right->IsConstantOperand()); | 2057 DCHECK(right->IsRegister() || right->IsConstantOperand()); |
| 2058 __ add(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); | 2058 __ add(ToRegister(result), ToRegister(left), ToOperand(right), set_cond); |
| 2059 } | 2059 } |
| 2060 | 2060 |
| 2061 if (can_overflow) { | 2061 if (can_overflow) { |
| 2062 DeoptimizeIf(vs, instr); | 2062 DeoptimizeIf(vs, instr, "overflow"); |
| 2063 } | 2063 } |
| 2064 } | 2064 } |
| 2065 | 2065 |
| 2066 | 2066 |
| 2067 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { | 2067 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { |
| 2068 LOperand* left = instr->left(); | 2068 LOperand* left = instr->left(); |
| 2069 LOperand* right = instr->right(); | 2069 LOperand* right = instr->right(); |
| 2070 HMathMinMax::Operation operation = instr->hydrogen()->operation(); | 2070 HMathMinMax::Operation operation = instr->hydrogen()->operation(); |
| 2071 if (instr->hydrogen()->representation().IsSmiOrInteger32()) { | 2071 if (instr->hydrogen()->representation().IsSmiOrInteger32()) { |
| 2072 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; | 2072 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 } | 2278 } |
| 2279 | 2279 |
| 2280 if (expected.Contains(ToBooleanStub::SMI)) { | 2280 if (expected.Contains(ToBooleanStub::SMI)) { |
| 2281 // Smis: 0 -> false, all other -> true. | 2281 // Smis: 0 -> false, all other -> true. |
| 2282 __ cmp(reg, Operand::Zero()); | 2282 __ cmp(reg, Operand::Zero()); |
| 2283 __ b(eq, instr->FalseLabel(chunk_)); | 2283 __ b(eq, instr->FalseLabel(chunk_)); |
| 2284 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); | 2284 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2285 } else if (expected.NeedsMap()) { | 2285 } else if (expected.NeedsMap()) { |
| 2286 // If we need a map later and have a Smi -> deopt. | 2286 // If we need a map later and have a Smi -> deopt. |
| 2287 __ SmiTst(reg); | 2287 __ SmiTst(reg); |
| 2288 DeoptimizeIf(eq, instr); | 2288 DeoptimizeIf(eq, instr, "Smi"); |
| 2289 } | 2289 } |
| 2290 | 2290 |
| 2291 const Register map = scratch0(); | 2291 const Register map = scratch0(); |
| 2292 if (expected.NeedsMap()) { | 2292 if (expected.NeedsMap()) { |
| 2293 __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset)); | 2293 __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 2294 | 2294 |
| 2295 if (expected.CanBeUndetectable()) { | 2295 if (expected.CanBeUndetectable()) { |
| 2296 // Undetectable -> false. | 2296 // Undetectable -> false. |
| 2297 __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); | 2297 __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset)); |
| 2298 __ tst(ip, Operand(1 << Map::kIsUndetectable)); | 2298 __ tst(ip, Operand(1 << Map::kIsUndetectable)); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2334 __ VFPCompareAndSetFlags(dbl_scratch, 0.0); | 2334 __ VFPCompareAndSetFlags(dbl_scratch, 0.0); |
| 2335 __ cmp(r0, r0, vs); // NaN -> false. | 2335 __ cmp(r0, r0, vs); // NaN -> false. |
| 2336 __ b(eq, instr->FalseLabel(chunk_)); // +0, -0 -> false. | 2336 __ b(eq, instr->FalseLabel(chunk_)); // +0, -0 -> false. |
| 2337 __ b(instr->TrueLabel(chunk_)); | 2337 __ b(instr->TrueLabel(chunk_)); |
| 2338 __ bind(¬_heap_number); | 2338 __ bind(¬_heap_number); |
| 2339 } | 2339 } |
| 2340 | 2340 |
| 2341 if (!expected.IsGeneric()) { | 2341 if (!expected.IsGeneric()) { |
| 2342 // We've seen something for the first time -> deopt. | 2342 // We've seen something for the first time -> deopt. |
| 2343 // This can only happen if we are not generic already. | 2343 // This can only happen if we are not generic already. |
| 2344 DeoptimizeIf(al, instr); | 2344 DeoptimizeIf(al, instr, "unexpected object"); |
| 2345 } | 2345 } |
| 2346 } | 2346 } |
| 2347 } | 2347 } |
| 2348 } | 2348 } |
| 2349 | 2349 |
| 2350 | 2350 |
| 2351 void LCodeGen::EmitGoto(int block) { | 2351 void LCodeGen::EmitGoto(int block) { |
| 2352 if (!IsNextEmittedBlock(block)) { | 2352 if (!IsNextEmittedBlock(block)) { |
| 2353 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); | 2353 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); |
| 2354 } | 2354 } |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2979 } | 2979 } |
| 2980 | 2980 |
| 2981 | 2981 |
| 2982 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { | 2982 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { |
| 2983 Register result = ToRegister(instr->result()); | 2983 Register result = ToRegister(instr->result()); |
| 2984 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell().handle()))); | 2984 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell().handle()))); |
| 2985 __ ldr(result, FieldMemOperand(ip, Cell::kValueOffset)); | 2985 __ ldr(result, FieldMemOperand(ip, Cell::kValueOffset)); |
| 2986 if (instr->hydrogen()->RequiresHoleCheck()) { | 2986 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2987 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2987 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 2988 __ cmp(result, ip); | 2988 __ cmp(result, ip); |
| 2989 DeoptimizeIf(eq, instr); | 2989 DeoptimizeIf(eq, instr, "hole"); |
| 2990 } | 2990 } |
| 2991 } | 2991 } |
| 2992 | 2992 |
| 2993 | 2993 |
| 2994 template <class T> | 2994 template <class T> |
| 2995 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { | 2995 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { |
| 2996 DCHECK(FLAG_vector_ics); | 2996 DCHECK(FLAG_vector_ics); |
| 2997 Register vector = ToRegister(instr->temp_vector()); | 2997 Register vector = ToRegister(instr->temp_vector()); |
| 2998 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); | 2998 DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister())); |
| 2999 __ Move(vector, instr->hydrogen()->feedback_vector()); | 2999 __ Move(vector, instr->hydrogen()->feedback_vector()); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3029 | 3029 |
| 3030 // If the cell we are storing to contains the hole it could have | 3030 // If the cell we are storing to contains the hole it could have |
| 3031 // been deleted from the property dictionary. In that case, we need | 3031 // been deleted from the property dictionary. In that case, we need |
| 3032 // to update the property details in the property dictionary to mark | 3032 // to update the property details in the property dictionary to mark |
| 3033 // it as no longer deleted. | 3033 // it as no longer deleted. |
| 3034 if (instr->hydrogen()->RequiresHoleCheck()) { | 3034 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3035 // We use a temp to check the payload (CompareRoot might clobber ip). | 3035 // We use a temp to check the payload (CompareRoot might clobber ip). |
| 3036 Register payload = ToRegister(instr->temp()); | 3036 Register payload = ToRegister(instr->temp()); |
| 3037 __ ldr(payload, FieldMemOperand(cell, Cell::kValueOffset)); | 3037 __ ldr(payload, FieldMemOperand(cell, Cell::kValueOffset)); |
| 3038 __ CompareRoot(payload, Heap::kTheHoleValueRootIndex); | 3038 __ CompareRoot(payload, Heap::kTheHoleValueRootIndex); |
| 3039 DeoptimizeIf(eq, instr); | 3039 DeoptimizeIf(eq, instr, "hole"); |
| 3040 } | 3040 } |
| 3041 | 3041 |
| 3042 // Store the value. | 3042 // Store the value. |
| 3043 __ str(value, FieldMemOperand(cell, Cell::kValueOffset)); | 3043 __ str(value, FieldMemOperand(cell, Cell::kValueOffset)); |
| 3044 // Cells are always rescanned, so no write barrier here. | 3044 // Cells are always rescanned, so no write barrier here. |
| 3045 } | 3045 } |
| 3046 | 3046 |
| 3047 | 3047 |
| 3048 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 3048 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 3049 Register context = ToRegister(instr->context()); | 3049 Register context = ToRegister(instr->context()); |
| 3050 Register result = ToRegister(instr->result()); | 3050 Register result = ToRegister(instr->result()); |
| 3051 __ ldr(result, ContextOperand(context, instr->slot_index())); | 3051 __ ldr(result, ContextOperand(context, instr->slot_index())); |
| 3052 if (instr->hydrogen()->RequiresHoleCheck()) { | 3052 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3053 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 3053 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 3054 __ cmp(result, ip); | 3054 __ cmp(result, ip); |
| 3055 if (instr->hydrogen()->DeoptimizesOnHole()) { | 3055 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 3056 DeoptimizeIf(eq, instr); | 3056 DeoptimizeIf(eq, instr, "hole"); |
| 3057 } else { | 3057 } else { |
| 3058 __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq); | 3058 __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq); |
| 3059 } | 3059 } |
| 3060 } | 3060 } |
| 3061 } | 3061 } |
| 3062 | 3062 |
| 3063 | 3063 |
| 3064 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 3064 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 3065 Register context = ToRegister(instr->context()); | 3065 Register context = ToRegister(instr->context()); |
| 3066 Register value = ToRegister(instr->value()); | 3066 Register value = ToRegister(instr->value()); |
| 3067 Register scratch = scratch0(); | 3067 Register scratch = scratch0(); |
| 3068 MemOperand target = ContextOperand(context, instr->slot_index()); | 3068 MemOperand target = ContextOperand(context, instr->slot_index()); |
| 3069 | 3069 |
| 3070 Label skip_assignment; | 3070 Label skip_assignment; |
| 3071 | 3071 |
| 3072 if (instr->hydrogen()->RequiresHoleCheck()) { | 3072 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3073 __ ldr(scratch, target); | 3073 __ ldr(scratch, target); |
| 3074 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 3074 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 3075 __ cmp(scratch, ip); | 3075 __ cmp(scratch, ip); |
| 3076 if (instr->hydrogen()->DeoptimizesOnHole()) { | 3076 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 3077 DeoptimizeIf(eq, instr); | 3077 DeoptimizeIf(eq, instr, "hole"); |
| 3078 } else { | 3078 } else { |
| 3079 __ b(ne, &skip_assignment); | 3079 __ b(ne, &skip_assignment); |
| 3080 } | 3080 } |
| 3081 } | 3081 } |
| 3082 | 3082 |
| 3083 __ str(value, target); | 3083 __ str(value, target); |
| 3084 if (instr->hydrogen()->NeedsWriteBarrier()) { | 3084 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 3085 SmiCheck check_needed = | 3085 SmiCheck check_needed = |
| 3086 instr->hydrogen()->value()->type().IsHeapObject() | 3086 instr->hydrogen()->value()->type().IsHeapObject() |
| 3087 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 3087 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3147 Register function = ToRegister(instr->function()); | 3147 Register function = ToRegister(instr->function()); |
| 3148 Register result = ToRegister(instr->result()); | 3148 Register result = ToRegister(instr->result()); |
| 3149 | 3149 |
| 3150 // Get the prototype or initial map from the function. | 3150 // Get the prototype or initial map from the function. |
| 3151 __ ldr(result, | 3151 __ ldr(result, |
| 3152 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 3152 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 3153 | 3153 |
| 3154 // Check that the function has a prototype or an initial map. | 3154 // Check that the function has a prototype or an initial map. |
| 3155 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 3155 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 3156 __ cmp(result, ip); | 3156 __ cmp(result, ip); |
| 3157 DeoptimizeIf(eq, instr); | 3157 DeoptimizeIf(eq, instr, "hole"); |
| 3158 | 3158 |
| 3159 // If the function does not have an initial map, we're done. | 3159 // If the function does not have an initial map, we're done. |
| 3160 Label done; | 3160 Label done; |
| 3161 __ CompareObjectType(result, scratch, scratch, MAP_TYPE); | 3161 __ CompareObjectType(result, scratch, scratch, MAP_TYPE); |
| 3162 __ b(ne, &done); | 3162 __ b(ne, &done); |
| 3163 | 3163 |
| 3164 // Get the prototype from the initial map. | 3164 // Get the prototype from the initial map. |
| 3165 __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); | 3165 __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset)); |
| 3166 | 3166 |
| 3167 // All done. | 3167 // All done. |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3273 break; | 3273 break; |
| 3274 case EXTERNAL_INT32_ELEMENTS: | 3274 case EXTERNAL_INT32_ELEMENTS: |
| 3275 case INT32_ELEMENTS: | 3275 case INT32_ELEMENTS: |
| 3276 __ ldr(result, mem_operand); | 3276 __ ldr(result, mem_operand); |
| 3277 break; | 3277 break; |
| 3278 case EXTERNAL_UINT32_ELEMENTS: | 3278 case EXTERNAL_UINT32_ELEMENTS: |
| 3279 case UINT32_ELEMENTS: | 3279 case UINT32_ELEMENTS: |
| 3280 __ ldr(result, mem_operand); | 3280 __ ldr(result, mem_operand); |
| 3281 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { | 3281 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
| 3282 __ cmp(result, Operand(0x80000000)); | 3282 __ cmp(result, Operand(0x80000000)); |
| 3283 DeoptimizeIf(cs, instr); | 3283 DeoptimizeIf(cs, instr, "negative value"); |
| 3284 } | 3284 } |
| 3285 break; | 3285 break; |
| 3286 case FLOAT32_ELEMENTS: | 3286 case FLOAT32_ELEMENTS: |
| 3287 case FLOAT64_ELEMENTS: | 3287 case FLOAT64_ELEMENTS: |
| 3288 case EXTERNAL_FLOAT32_ELEMENTS: | 3288 case EXTERNAL_FLOAT32_ELEMENTS: |
| 3289 case EXTERNAL_FLOAT64_ELEMENTS: | 3289 case EXTERNAL_FLOAT64_ELEMENTS: |
| 3290 case FAST_HOLEY_DOUBLE_ELEMENTS: | 3290 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 3291 case FAST_HOLEY_ELEMENTS: | 3291 case FAST_HOLEY_ELEMENTS: |
| 3292 case FAST_HOLEY_SMI_ELEMENTS: | 3292 case FAST_HOLEY_SMI_ELEMENTS: |
| 3293 case FAST_DOUBLE_ELEMENTS: | 3293 case FAST_DOUBLE_ELEMENTS: |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3326 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) | 3326 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) |
| 3327 ? (element_size_shift - kSmiTagSize) : element_size_shift; | 3327 ? (element_size_shift - kSmiTagSize) : element_size_shift; |
| 3328 __ add(scratch, scratch, Operand(key, LSL, shift_size)); | 3328 __ add(scratch, scratch, Operand(key, LSL, shift_size)); |
| 3329 } | 3329 } |
| 3330 | 3330 |
| 3331 __ vldr(result, scratch, 0); | 3331 __ vldr(result, scratch, 0); |
| 3332 | 3332 |
| 3333 if (instr->hydrogen()->RequiresHoleCheck()) { | 3333 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3334 __ ldr(scratch, MemOperand(scratch, sizeof(kHoleNanLower32))); | 3334 __ ldr(scratch, MemOperand(scratch, sizeof(kHoleNanLower32))); |
| 3335 __ cmp(scratch, Operand(kHoleNanUpper32)); | 3335 __ cmp(scratch, Operand(kHoleNanUpper32)); |
| 3336 DeoptimizeIf(eq, instr); | 3336 DeoptimizeIf(eq, instr, "hole"); |
| 3337 } | 3337 } |
| 3338 } | 3338 } |
| 3339 | 3339 |
| 3340 | 3340 |
| 3341 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { | 3341 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { |
| 3342 Register elements = ToRegister(instr->elements()); | 3342 Register elements = ToRegister(instr->elements()); |
| 3343 Register result = ToRegister(instr->result()); | 3343 Register result = ToRegister(instr->result()); |
| 3344 Register scratch = scratch0(); | 3344 Register scratch = scratch0(); |
| 3345 Register store_base = scratch; | 3345 Register store_base = scratch; |
| 3346 int offset = instr->base_offset(); | 3346 int offset = instr->base_offset(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3360 } else { | 3360 } else { |
| 3361 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); | 3361 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2)); |
| 3362 } | 3362 } |
| 3363 } | 3363 } |
| 3364 __ ldr(result, MemOperand(store_base, offset)); | 3364 __ ldr(result, MemOperand(store_base, offset)); |
| 3365 | 3365 |
| 3366 // Check for the hole value. | 3366 // Check for the hole value. |
| 3367 if (instr->hydrogen()->RequiresHoleCheck()) { | 3367 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 3368 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { | 3368 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { |
| 3369 __ SmiTst(result); | 3369 __ SmiTst(result); |
| 3370 DeoptimizeIf(ne, instr); | 3370 DeoptimizeIf(ne, instr, "not a Smi"); |
| 3371 } else { | 3371 } else { |
| 3372 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | 3372 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); |
| 3373 __ cmp(result, scratch); | 3373 __ cmp(result, scratch); |
| 3374 DeoptimizeIf(eq, instr); | 3374 DeoptimizeIf(eq, instr, "hole"); |
| 3375 } | 3375 } |
| 3376 } | 3376 } |
| 3377 } | 3377 } |
| 3378 | 3378 |
| 3379 | 3379 |
| 3380 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { | 3380 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { |
| 3381 if (instr->is_typed_elements()) { | 3381 if (instr->is_typed_elements()) { |
| 3382 DoLoadKeyedExternalArray(instr); | 3382 DoLoadKeyedExternalArray(instr); |
| 3383 } else if (instr->hydrogen()->representation().IsDouble()) { | 3383 } else if (instr->hydrogen()->representation().IsDouble()) { |
| 3384 DoLoadKeyedFixedDoubleArray(instr); | 3384 DoLoadKeyedFixedDoubleArray(instr); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3506 // Normal function. Replace undefined or null with global receiver. | 3506 // Normal function. Replace undefined or null with global receiver. |
| 3507 __ LoadRoot(scratch, Heap::kNullValueRootIndex); | 3507 __ LoadRoot(scratch, Heap::kNullValueRootIndex); |
| 3508 __ cmp(receiver, scratch); | 3508 __ cmp(receiver, scratch); |
| 3509 __ b(eq, &global_object); | 3509 __ b(eq, &global_object); |
| 3510 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | 3510 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); |
| 3511 __ cmp(receiver, scratch); | 3511 __ cmp(receiver, scratch); |
| 3512 __ b(eq, &global_object); | 3512 __ b(eq, &global_object); |
| 3513 | 3513 |
| 3514 // Deoptimize if the receiver is not a JS object. | 3514 // Deoptimize if the receiver is not a JS object. |
| 3515 __ SmiTst(receiver); | 3515 __ SmiTst(receiver); |
| 3516 DeoptimizeIf(eq, instr); | 3516 DeoptimizeIf(eq, instr, "Smi"); |
| 3517 __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE); | 3517 __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE); |
| 3518 DeoptimizeIf(lt, instr); | 3518 DeoptimizeIf(lt, instr, "not a JavaScript object"); |
| 3519 | 3519 |
| 3520 __ b(&result_in_receiver); | 3520 __ b(&result_in_receiver); |
| 3521 __ bind(&global_object); | 3521 __ bind(&global_object); |
| 3522 __ ldr(result, FieldMemOperand(function, JSFunction::kContextOffset)); | 3522 __ ldr(result, FieldMemOperand(function, JSFunction::kContextOffset)); |
| 3523 __ ldr(result, | 3523 __ ldr(result, |
| 3524 ContextOperand(result, Context::GLOBAL_OBJECT_INDEX)); | 3524 ContextOperand(result, Context::GLOBAL_OBJECT_INDEX)); |
| 3525 __ ldr(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset)); | 3525 __ ldr(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset)); |
| 3526 | 3526 |
| 3527 if (result.is(receiver)) { | 3527 if (result.is(receiver)) { |
| 3528 __ bind(&result_in_receiver); | 3528 __ bind(&result_in_receiver); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3543 Register elements = ToRegister(instr->elements()); | 3543 Register elements = ToRegister(instr->elements()); |
| 3544 Register scratch = scratch0(); | 3544 Register scratch = scratch0(); |
| 3545 DCHECK(receiver.is(r0)); // Used for parameter count. | 3545 DCHECK(receiver.is(r0)); // Used for parameter count. |
| 3546 DCHECK(function.is(r1)); // Required by InvokeFunction. | 3546 DCHECK(function.is(r1)); // Required by InvokeFunction. |
| 3547 DCHECK(ToRegister(instr->result()).is(r0)); | 3547 DCHECK(ToRegister(instr->result()).is(r0)); |
| 3548 | 3548 |
| 3549 // Copy the arguments to this function possibly from the | 3549 // Copy the arguments to this function possibly from the |
| 3550 // adaptor frame below it. | 3550 // adaptor frame below it. |
| 3551 const uint32_t kArgumentsLimit = 1 * KB; | 3551 const uint32_t kArgumentsLimit = 1 * KB; |
| 3552 __ cmp(length, Operand(kArgumentsLimit)); | 3552 __ cmp(length, Operand(kArgumentsLimit)); |
| 3553 DeoptimizeIf(hi, instr); | 3553 DeoptimizeIf(hi, instr, "too many arguments"); |
| 3554 | 3554 |
| 3555 // Push the receiver and use the register to keep the original | 3555 // Push the receiver and use the register to keep the original |
| 3556 // number of arguments. | 3556 // number of arguments. |
| 3557 __ push(receiver); | 3557 __ push(receiver); |
| 3558 __ mov(receiver, length); | 3558 __ mov(receiver, length); |
| 3559 // The arguments are at a one pointer size offset from elements. | 3559 // The arguments are at a one pointer size offset from elements. |
| 3560 __ add(elements, elements, Operand(1 * kPointerSize)); | 3560 __ add(elements, elements, Operand(1 * kPointerSize)); |
| 3561 | 3561 |
| 3562 // Loop through the arguments pushing them onto the execution | 3562 // Loop through the arguments pushing them onto the execution |
| 3563 // stack. | 3563 // stack. |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3673 DCHECK(instr->context() != NULL); | 3673 DCHECK(instr->context() != NULL); |
| 3674 DCHECK(ToRegister(instr->context()).is(cp)); | 3674 DCHECK(ToRegister(instr->context()).is(cp)); |
| 3675 Register input = ToRegister(instr->value()); | 3675 Register input = ToRegister(instr->value()); |
| 3676 Register result = ToRegister(instr->result()); | 3676 Register result = ToRegister(instr->result()); |
| 3677 Register scratch = scratch0(); | 3677 Register scratch = scratch0(); |
| 3678 | 3678 |
| 3679 // Deoptimize if not a heap number. | 3679 // Deoptimize if not a heap number. |
| 3680 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); | 3680 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 3681 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3681 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 3682 __ cmp(scratch, Operand(ip)); | 3682 __ cmp(scratch, Operand(ip)); |
| 3683 DeoptimizeIf(ne, instr); | 3683 DeoptimizeIf(ne, instr, "not a heap number"); |
| 3684 | 3684 |
| 3685 Label done; | 3685 Label done; |
| 3686 Register exponent = scratch0(); | 3686 Register exponent = scratch0(); |
| 3687 scratch = no_reg; | 3687 scratch = no_reg; |
| 3688 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); | 3688 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); |
| 3689 // Check the sign of the argument. If the argument is positive, just | 3689 // Check the sign of the argument. If the argument is positive, just |
| 3690 // return it. | 3690 // return it. |
| 3691 __ tst(exponent, Operand(HeapNumber::kSignMask)); | 3691 __ tst(exponent, Operand(HeapNumber::kSignMask)); |
| 3692 // Move the input to the result if necessary. | 3692 // Move the input to the result if necessary. |
| 3693 __ Move(result, input); | 3693 __ Move(result, input); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3741 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { | 3741 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { |
| 3742 Register input = ToRegister(instr->value()); | 3742 Register input = ToRegister(instr->value()); |
| 3743 Register result = ToRegister(instr->result()); | 3743 Register result = ToRegister(instr->result()); |
| 3744 __ cmp(input, Operand::Zero()); | 3744 __ cmp(input, Operand::Zero()); |
| 3745 __ Move(result, input, pl); | 3745 __ Move(result, input, pl); |
| 3746 // We can make rsb conditional because the previous cmp instruction | 3746 // We can make rsb conditional because the previous cmp instruction |
| 3747 // will clear the V (overflow) flag and rsb won't set this flag | 3747 // will clear the V (overflow) flag and rsb won't set this flag |
| 3748 // if input is positive. | 3748 // if input is positive. |
| 3749 __ rsb(result, input, Operand::Zero(), SetCC, mi); | 3749 __ rsb(result, input, Operand::Zero(), SetCC, mi); |
| 3750 // Deoptimize on overflow. | 3750 // Deoptimize on overflow. |
| 3751 DeoptimizeIf(vs, instr); | 3751 DeoptimizeIf(vs, instr, "overflow"); |
| 3752 } | 3752 } |
| 3753 | 3753 |
| 3754 | 3754 |
| 3755 void LCodeGen::DoMathAbs(LMathAbs* instr) { | 3755 void LCodeGen::DoMathAbs(LMathAbs* instr) { |
| 3756 // Class for deferred case. | 3756 // Class for deferred case. |
| 3757 class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode { | 3757 class DeferredMathAbsTaggedHeapNumber FINAL : public LDeferredCode { |
| 3758 public: | 3758 public: |
| 3759 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr) | 3759 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr) |
| 3760 : LDeferredCode(codegen), instr_(instr) { } | 3760 : LDeferredCode(codegen), instr_(instr) { } |
| 3761 virtual void Generate() OVERRIDE { | 3761 virtual void Generate() OVERRIDE { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3787 } | 3787 } |
| 3788 | 3788 |
| 3789 | 3789 |
| 3790 void LCodeGen::DoMathFloor(LMathFloor* instr) { | 3790 void LCodeGen::DoMathFloor(LMathFloor* instr) { |
| 3791 DwVfpRegister input = ToDoubleRegister(instr->value()); | 3791 DwVfpRegister input = ToDoubleRegister(instr->value()); |
| 3792 Register result = ToRegister(instr->result()); | 3792 Register result = ToRegister(instr->result()); |
| 3793 Register input_high = scratch0(); | 3793 Register input_high = scratch0(); |
| 3794 Label done, exact; | 3794 Label done, exact; |
| 3795 | 3795 |
| 3796 __ TryInt32Floor(result, input, input_high, double_scratch0(), &done, &exact); | 3796 __ TryInt32Floor(result, input, input_high, double_scratch0(), &done, &exact); |
| 3797 DeoptimizeIf(al, instr); | 3797 DeoptimizeIf(al, instr, "lost precision or NaN"); |
| 3798 | 3798 |
| 3799 __ bind(&exact); | 3799 __ bind(&exact); |
| 3800 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3800 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3801 // Test for -0. | 3801 // Test for -0. |
| 3802 __ cmp(result, Operand::Zero()); | 3802 __ cmp(result, Operand::Zero()); |
| 3803 __ b(ne, &done); | 3803 __ b(ne, &done); |
| 3804 __ cmp(input_high, Operand::Zero()); | 3804 __ cmp(input_high, Operand::Zero()); |
| 3805 DeoptimizeIf(mi, instr); | 3805 DeoptimizeIf(mi, instr, "minus zero"); |
| 3806 } | 3806 } |
| 3807 __ bind(&done); | 3807 __ bind(&done); |
| 3808 } | 3808 } |
| 3809 | 3809 |
| 3810 | 3810 |
| 3811 void LCodeGen::DoMathRound(LMathRound* instr) { | 3811 void LCodeGen::DoMathRound(LMathRound* instr) { |
| 3812 DwVfpRegister input = ToDoubleRegister(instr->value()); | 3812 DwVfpRegister input = ToDoubleRegister(instr->value()); |
| 3813 Register result = ToRegister(instr->result()); | 3813 Register result = ToRegister(instr->result()); |
| 3814 DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp()); | 3814 DwVfpRegister double_scratch1 = ToDoubleRegister(instr->temp()); |
| 3815 DwVfpRegister input_plus_dot_five = double_scratch1; | 3815 DwVfpRegister input_plus_dot_five = double_scratch1; |
| 3816 Register input_high = scratch0(); | 3816 Register input_high = scratch0(); |
| 3817 DwVfpRegister dot_five = double_scratch0(); | 3817 DwVfpRegister dot_five = double_scratch0(); |
| 3818 Label convert, done; | 3818 Label convert, done; |
| 3819 | 3819 |
| 3820 __ Vmov(dot_five, 0.5, scratch0()); | 3820 __ Vmov(dot_five, 0.5, scratch0()); |
| 3821 __ vabs(double_scratch1, input); | 3821 __ vabs(double_scratch1, input); |
| 3822 __ VFPCompareAndSetFlags(double_scratch1, dot_five); | 3822 __ VFPCompareAndSetFlags(double_scratch1, dot_five); |
| 3823 // If input is in [-0.5, -0], the result is -0. | 3823 // If input is in [-0.5, -0], the result is -0. |
| 3824 // If input is in [+0, +0.5[, the result is +0. | 3824 // If input is in [+0, +0.5[, the result is +0. |
| 3825 // If the input is +0.5, the result is 1. | 3825 // If the input is +0.5, the result is 1. |
| 3826 __ b(hi, &convert); // Out of [-0.5, +0.5]. | 3826 __ b(hi, &convert); // Out of [-0.5, +0.5]. |
| 3827 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 3827 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 3828 __ VmovHigh(input_high, input); | 3828 __ VmovHigh(input_high, input); |
| 3829 __ cmp(input_high, Operand::Zero()); | 3829 __ cmp(input_high, Operand::Zero()); |
| 3830 DeoptimizeIf(mi, instr); // [-0.5, -0]. | 3830 // [-0.5, -0]. |
| 3831 DeoptimizeIf(mi, instr, "minus zero"); |
| 3831 } | 3832 } |
| 3832 __ VFPCompareAndSetFlags(input, dot_five); | 3833 __ VFPCompareAndSetFlags(input, dot_five); |
| 3833 __ mov(result, Operand(1), LeaveCC, eq); // +0.5. | 3834 __ mov(result, Operand(1), LeaveCC, eq); // +0.5. |
| 3834 // Remaining cases: [+0, +0.5[ or [-0.5, +0.5[, depending on | 3835 // Remaining cases: [+0, +0.5[ or [-0.5, +0.5[, depending on |
| 3835 // flag kBailoutOnMinusZero. | 3836 // flag kBailoutOnMinusZero. |
| 3836 __ mov(result, Operand::Zero(), LeaveCC, ne); | 3837 __ mov(result, Operand::Zero(), LeaveCC, ne); |
| 3837 __ b(&done); | 3838 __ b(&done); |
| 3838 | 3839 |
| 3839 __ bind(&convert); | 3840 __ bind(&convert); |
| 3840 __ vadd(input_plus_dot_five, input, dot_five); | 3841 __ vadd(input_plus_dot_five, input, dot_five); |
| 3841 // Reuse dot_five (double_scratch0) as we no longer need this value. | 3842 // Reuse dot_five (double_scratch0) as we no longer need this value. |
| 3842 __ TryInt32Floor(result, input_plus_dot_five, input_high, double_scratch0(), | 3843 __ TryInt32Floor(result, input_plus_dot_five, input_high, double_scratch0(), |
| 3843 &done, &done); | 3844 &done, &done); |
| 3844 DeoptimizeIf(al, instr); | 3845 DeoptimizeIf(al, instr, "lost precision or NaN"); |
| 3845 __ bind(&done); | 3846 __ bind(&done); |
| 3846 } | 3847 } |
| 3847 | 3848 |
| 3848 | 3849 |
| 3849 void LCodeGen::DoMathFround(LMathFround* instr) { | 3850 void LCodeGen::DoMathFround(LMathFround* instr) { |
| 3850 DwVfpRegister input_reg = ToDoubleRegister(instr->value()); | 3851 DwVfpRegister input_reg = ToDoubleRegister(instr->value()); |
| 3851 DwVfpRegister output_reg = ToDoubleRegister(instr->result()); | 3852 DwVfpRegister output_reg = ToDoubleRegister(instr->result()); |
| 3852 LowDwVfpRegister scratch = double_scratch0(); | 3853 LowDwVfpRegister scratch = double_scratch0(); |
| 3853 __ vcvt_f32_f64(scratch.low(), input_reg); | 3854 __ vcvt_f32_f64(scratch.low(), input_reg); |
| 3854 __ vcvt_f64_f32(output_reg, scratch.low()); | 3855 __ vcvt_f64_f32(output_reg, scratch.low()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3898 if (exponent_type.IsSmi()) { | 3899 if (exponent_type.IsSmi()) { |
| 3899 MathPowStub stub(isolate(), MathPowStub::TAGGED); | 3900 MathPowStub stub(isolate(), MathPowStub::TAGGED); |
| 3900 __ CallStub(&stub); | 3901 __ CallStub(&stub); |
| 3901 } else if (exponent_type.IsTagged()) { | 3902 } else if (exponent_type.IsTagged()) { |
| 3902 Label no_deopt; | 3903 Label no_deopt; |
| 3903 __ JumpIfSmi(tagged_exponent, &no_deopt); | 3904 __ JumpIfSmi(tagged_exponent, &no_deopt); |
| 3904 DCHECK(!r6.is(tagged_exponent)); | 3905 DCHECK(!r6.is(tagged_exponent)); |
| 3905 __ ldr(r6, FieldMemOperand(tagged_exponent, HeapObject::kMapOffset)); | 3906 __ ldr(r6, FieldMemOperand(tagged_exponent, HeapObject::kMapOffset)); |
| 3906 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3907 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 3907 __ cmp(r6, Operand(ip)); | 3908 __ cmp(r6, Operand(ip)); |
| 3908 DeoptimizeIf(ne, instr); | 3909 DeoptimizeIf(ne, instr, "not a heap number"); |
| 3909 __ bind(&no_deopt); | 3910 __ bind(&no_deopt); |
| 3910 MathPowStub stub(isolate(), MathPowStub::TAGGED); | 3911 MathPowStub stub(isolate(), MathPowStub::TAGGED); |
| 3911 __ CallStub(&stub); | 3912 __ CallStub(&stub); |
| 3912 } else if (exponent_type.IsInteger32()) { | 3913 } else if (exponent_type.IsInteger32()) { |
| 3913 MathPowStub stub(isolate(), MathPowStub::INTEGER); | 3914 MathPowStub stub(isolate(), MathPowStub::INTEGER); |
| 3914 __ CallStub(&stub); | 3915 __ CallStub(&stub); |
| 3915 } else { | 3916 } else { |
| 3916 DCHECK(exponent_type.IsDouble()); | 3917 DCHECK(exponent_type.IsDouble()); |
| 3917 MathPowStub stub(isolate(), MathPowStub::DOUBLE); | 3918 MathPowStub stub(isolate(), MathPowStub::DOUBLE); |
| 3918 __ CallStub(&stub); | 3919 __ CallStub(&stub); |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4250 Register index = ToRegister(instr->index()); | 4251 Register index = ToRegister(instr->index()); |
| 4251 Operand length = ToOperand(instr->length()); | 4252 Operand length = ToOperand(instr->length()); |
| 4252 __ cmp(index, length); | 4253 __ cmp(index, length); |
| 4253 } | 4254 } |
| 4254 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { | 4255 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { |
| 4255 Label done; | 4256 Label done; |
| 4256 __ b(NegateCondition(cc), &done); | 4257 __ b(NegateCondition(cc), &done); |
| 4257 __ stop("eliminated bounds check failed"); | 4258 __ stop("eliminated bounds check failed"); |
| 4258 __ bind(&done); | 4259 __ bind(&done); |
| 4259 } else { | 4260 } else { |
| 4260 DeoptimizeIf(cc, instr); | 4261 DeoptimizeIf(cc, instr, "out of bounds"); |
| 4261 } | 4262 } |
| 4262 } | 4263 } |
| 4263 | 4264 |
| 4264 | 4265 |
| 4265 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { | 4266 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { |
| 4266 Register external_pointer = ToRegister(instr->elements()); | 4267 Register external_pointer = ToRegister(instr->elements()); |
| 4267 Register key = no_reg; | 4268 Register key = no_reg; |
| 4268 ElementsKind elements_kind = instr->elements_kind(); | 4269 ElementsKind elements_kind = instr->elements_kind(); |
| 4269 bool key_is_constant = instr->key()->IsConstantOperand(); | 4270 bool key_is_constant = instr->key()->IsConstantOperand(); |
| 4270 int constant_key = 0; | 4271 int constant_key = 0; |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4498 } | 4499 } |
| 4499 __ bind(¬_applicable); | 4500 __ bind(¬_applicable); |
| 4500 } | 4501 } |
| 4501 | 4502 |
| 4502 | 4503 |
| 4503 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { | 4504 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
| 4504 Register object = ToRegister(instr->object()); | 4505 Register object = ToRegister(instr->object()); |
| 4505 Register temp = ToRegister(instr->temp()); | 4506 Register temp = ToRegister(instr->temp()); |
| 4506 Label no_memento_found; | 4507 Label no_memento_found; |
| 4507 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); | 4508 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); |
| 4508 DeoptimizeIf(eq, instr); | 4509 DeoptimizeIf(eq, instr, "memento found"); |
| 4509 __ bind(&no_memento_found); | 4510 __ bind(&no_memento_found); |
| 4510 } | 4511 } |
| 4511 | 4512 |
| 4512 | 4513 |
| 4513 void LCodeGen::DoStringAdd(LStringAdd* instr) { | 4514 void LCodeGen::DoStringAdd(LStringAdd* instr) { |
| 4514 DCHECK(ToRegister(instr->context()).is(cp)); | 4515 DCHECK(ToRegister(instr->context()).is(cp)); |
| 4515 DCHECK(ToRegister(instr->left()).is(r1)); | 4516 DCHECK(ToRegister(instr->left()).is(r1)); |
| 4516 DCHECK(ToRegister(instr->right()).is(r0)); | 4517 DCHECK(ToRegister(instr->right()).is(r0)); |
| 4517 StringAddStub stub(isolate(), | 4518 StringAddStub stub(isolate(), |
| 4518 instr->hydrogen()->flags(), | 4519 instr->hydrogen()->flags(), |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4832 } | 4833 } |
| 4833 | 4834 |
| 4834 | 4835 |
| 4835 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 4836 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 4836 HChange* hchange = instr->hydrogen(); | 4837 HChange* hchange = instr->hydrogen(); |
| 4837 Register input = ToRegister(instr->value()); | 4838 Register input = ToRegister(instr->value()); |
| 4838 Register output = ToRegister(instr->result()); | 4839 Register output = ToRegister(instr->result()); |
| 4839 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4840 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4840 hchange->value()->CheckFlag(HValue::kUint32)) { | 4841 hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4841 __ tst(input, Operand(0xc0000000)); | 4842 __ tst(input, Operand(0xc0000000)); |
| 4842 DeoptimizeIf(ne, instr); | 4843 DeoptimizeIf(ne, instr, "overflow"); |
| 4843 } | 4844 } |
| 4844 if (hchange->CheckFlag(HValue::kCanOverflow) && | 4845 if (hchange->CheckFlag(HValue::kCanOverflow) && |
| 4845 !hchange->value()->CheckFlag(HValue::kUint32)) { | 4846 !hchange->value()->CheckFlag(HValue::kUint32)) { |
| 4846 __ SmiTag(output, input, SetCC); | 4847 __ SmiTag(output, input, SetCC); |
| 4847 DeoptimizeIf(vs, instr); | 4848 DeoptimizeIf(vs, instr, "overflow"); |
| 4848 } else { | 4849 } else { |
| 4849 __ SmiTag(output, input); | 4850 __ SmiTag(output, input); |
| 4850 } | 4851 } |
| 4851 } | 4852 } |
| 4852 | 4853 |
| 4853 | 4854 |
| 4854 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { | 4855 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
| 4855 Register input = ToRegister(instr->value()); | 4856 Register input = ToRegister(instr->value()); |
| 4856 Register result = ToRegister(instr->result()); | 4857 Register result = ToRegister(instr->result()); |
| 4857 if (instr->needs_check()) { | 4858 if (instr->needs_check()) { |
| 4858 STATIC_ASSERT(kHeapObjectTag == 1); | 4859 STATIC_ASSERT(kHeapObjectTag == 1); |
| 4859 // If the input is a HeapObject, SmiUntag will set the carry flag. | 4860 // If the input is a HeapObject, SmiUntag will set the carry flag. |
| 4860 __ SmiUntag(result, input, SetCC); | 4861 __ SmiUntag(result, input, SetCC); |
| 4861 DeoptimizeIf(cs, instr); | 4862 DeoptimizeIf(cs, instr, "not a Smi"); |
| 4862 } else { | 4863 } else { |
| 4863 __ SmiUntag(result, input); | 4864 __ SmiUntag(result, input); |
| 4864 } | 4865 } |
| 4865 } | 4866 } |
| 4866 | 4867 |
| 4867 | 4868 |
| 4868 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, | 4869 void LCodeGen::EmitNumberUntagD(LNumberUntagD* instr, Register input_reg, |
| 4869 DwVfpRegister result_reg, | 4870 DwVfpRegister result_reg, |
| 4870 NumberUntagDMode mode) { | 4871 NumberUntagDMode mode) { |
| 4871 bool can_convert_undefined_to_nan = | 4872 bool can_convert_undefined_to_nan = |
| 4872 instr->hydrogen()->can_convert_undefined_to_nan(); | 4873 instr->hydrogen()->can_convert_undefined_to_nan(); |
| 4873 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero(); | 4874 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero(); |
| 4874 | 4875 |
| 4875 Register scratch = scratch0(); | 4876 Register scratch = scratch0(); |
| 4876 SwVfpRegister flt_scratch = double_scratch0().low(); | 4877 SwVfpRegister flt_scratch = double_scratch0().low(); |
| 4877 DCHECK(!result_reg.is(double_scratch0())); | 4878 DCHECK(!result_reg.is(double_scratch0())); |
| 4878 Label convert, load_smi, done; | 4879 Label convert, load_smi, done; |
| 4879 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { | 4880 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
| 4880 // Smi check. | 4881 // Smi check. |
| 4881 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); | 4882 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); |
| 4882 // Heap number map check. | 4883 // Heap number map check. |
| 4883 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); | 4884 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
| 4884 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 4885 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
| 4885 __ cmp(scratch, Operand(ip)); | 4886 __ cmp(scratch, Operand(ip)); |
| 4886 if (can_convert_undefined_to_nan) { | 4887 if (can_convert_undefined_to_nan) { |
| 4887 __ b(ne, &convert); | 4888 __ b(ne, &convert); |
| 4888 } else { | 4889 } else { |
| 4889 DeoptimizeIf(ne, instr); | 4890 DeoptimizeIf(ne, instr, "not a heap number"); |
| 4890 } | 4891 } |
| 4891 // load heap number | 4892 // load heap number |
| 4892 __ vldr(result_reg, input_reg, HeapNumber::kValueOffset - kHeapObjectTag); | 4893 __ vldr(result_reg, input_reg, HeapNumber::kValueOffset - kHeapObjectTag); |
| 4893 if (deoptimize_on_minus_zero) { | 4894 if (deoptimize_on_minus_zero) { |
| 4894 __ VmovLow(scratch, result_reg); | 4895 __ VmovLow(scratch, result_reg); |
| 4895 __ cmp(scratch, Operand::Zero()); | 4896 __ cmp(scratch, Operand::Zero()); |
| 4896 __ b(ne, &done); | 4897 __ b(ne, &done); |
| 4897 __ VmovHigh(scratch, result_reg); | 4898 __ VmovHigh(scratch, result_reg); |
| 4898 __ cmp(scratch, Operand(HeapNumber::kSignMask)); | 4899 __ cmp(scratch, Operand(HeapNumber::kSignMask)); |
| 4899 DeoptimizeIf(eq, instr); | 4900 DeoptimizeIf(eq, instr, "minus zero"); |
| 4900 } | 4901 } |
| 4901 __ jmp(&done); | 4902 __ jmp(&done); |
| 4902 if (can_convert_undefined_to_nan) { | 4903 if (can_convert_undefined_to_nan) { |
| 4903 __ bind(&convert); | 4904 __ bind(&convert); |
| 4904 // Convert undefined (and hole) to NaN. | 4905 // Convert undefined (and hole) to NaN. |
| 4905 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 4906 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 4906 __ cmp(input_reg, Operand(ip)); | 4907 __ cmp(input_reg, Operand(ip)); |
| 4907 DeoptimizeIf(ne, instr); | 4908 DeoptimizeIf(ne, instr, "not a heap number/undefined"); |
| 4908 __ LoadRoot(scratch, Heap::kNanValueRootIndex); | 4909 __ LoadRoot(scratch, Heap::kNanValueRootIndex); |
| 4909 __ vldr(result_reg, scratch, HeapNumber::kValueOffset - kHeapObjectTag); | 4910 __ vldr(result_reg, scratch, HeapNumber::kValueOffset - kHeapObjectTag); |
| 4910 __ jmp(&done); | 4911 __ jmp(&done); |
| 4911 } | 4912 } |
| 4912 } else { | 4913 } else { |
| 4913 __ SmiUntag(scratch, input_reg); | 4914 __ SmiUntag(scratch, input_reg); |
| 4914 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); | 4915 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); |
| 4915 } | 4916 } |
| 4916 // Smi to double register conversion | 4917 // Smi to double register conversion |
| 4917 __ bind(&load_smi); | 4918 __ bind(&load_smi); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4965 __ bind(&check_bools); | 4966 __ bind(&check_bools); |
| 4966 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 4967 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 4967 __ cmp(scratch2, Operand(ip)); | 4968 __ cmp(scratch2, Operand(ip)); |
| 4968 __ b(ne, &check_false); | 4969 __ b(ne, &check_false); |
| 4969 __ mov(input_reg, Operand(1)); | 4970 __ mov(input_reg, Operand(1)); |
| 4970 __ b(&done); | 4971 __ b(&done); |
| 4971 | 4972 |
| 4972 __ bind(&check_false); | 4973 __ bind(&check_false); |
| 4973 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 4974 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 4974 __ cmp(scratch2, Operand(ip)); | 4975 __ cmp(scratch2, Operand(ip)); |
| 4975 DeoptimizeIf(ne, instr, "cannot truncate"); | 4976 DeoptimizeIf(ne, instr, "not a heap number/undefined/true/false"); |
| 4976 __ mov(input_reg, Operand::Zero()); | 4977 __ mov(input_reg, Operand::Zero()); |
| 4977 } else { | 4978 } else { |
| 4978 DeoptimizeIf(ne, instr, "not a heap number"); | 4979 DeoptimizeIf(ne, instr, "not a heap number"); |
| 4979 | 4980 |
| 4980 __ sub(ip, scratch2, Operand(kHeapObjectTag)); | 4981 __ sub(ip, scratch2, Operand(kHeapObjectTag)); |
| 4981 __ vldr(double_scratch2, ip, HeapNumber::kValueOffset); | 4982 __ vldr(double_scratch2, ip, HeapNumber::kValueOffset); |
| 4982 __ TryDoubleToInt32Exact(input_reg, double_scratch2, double_scratch); | 4983 __ TryDoubleToInt32Exact(input_reg, double_scratch2, double_scratch); |
| 4983 DeoptimizeIf(ne, instr, "lost precision or NaN"); | 4984 DeoptimizeIf(ne, instr, "lost precision or NaN"); |
| 4984 | 4985 |
| 4985 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 4986 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5050 Register result_reg = ToRegister(instr->result()); | 5051 Register result_reg = ToRegister(instr->result()); |
| 5051 Register scratch1 = scratch0(); | 5052 Register scratch1 = scratch0(); |
| 5052 DwVfpRegister double_input = ToDoubleRegister(instr->value()); | 5053 DwVfpRegister double_input = ToDoubleRegister(instr->value()); |
| 5053 LowDwVfpRegister double_scratch = double_scratch0(); | 5054 LowDwVfpRegister double_scratch = double_scratch0(); |
| 5054 | 5055 |
| 5055 if (instr->truncating()) { | 5056 if (instr->truncating()) { |
| 5056 __ TruncateDoubleToI(result_reg, double_input); | 5057 __ TruncateDoubleToI(result_reg, double_input); |
| 5057 } else { | 5058 } else { |
| 5058 __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); | 5059 __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); |
| 5059 // Deoptimize if the input wasn't a int32 (inside a double). | 5060 // Deoptimize if the input wasn't a int32 (inside a double). |
| 5060 DeoptimizeIf(ne, instr); | 5061 DeoptimizeIf(ne, instr, "lost precision or NaN"); |
| 5061 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 5062 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 5062 Label done; | 5063 Label done; |
| 5063 __ cmp(result_reg, Operand::Zero()); | 5064 __ cmp(result_reg, Operand::Zero()); |
| 5064 __ b(ne, &done); | 5065 __ b(ne, &done); |
| 5065 __ VmovHigh(scratch1, double_input); | 5066 __ VmovHigh(scratch1, double_input); |
| 5066 __ tst(scratch1, Operand(HeapNumber::kSignMask)); | 5067 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 5067 DeoptimizeIf(ne, instr); | 5068 DeoptimizeIf(ne, instr, "minus zero"); |
| 5068 __ bind(&done); | 5069 __ bind(&done); |
| 5069 } | 5070 } |
| 5070 } | 5071 } |
| 5071 } | 5072 } |
| 5072 | 5073 |
| 5073 | 5074 |
| 5074 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { | 5075 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { |
| 5075 Register result_reg = ToRegister(instr->result()); | 5076 Register result_reg = ToRegister(instr->result()); |
| 5076 Register scratch1 = scratch0(); | 5077 Register scratch1 = scratch0(); |
| 5077 DwVfpRegister double_input = ToDoubleRegister(instr->value()); | 5078 DwVfpRegister double_input = ToDoubleRegister(instr->value()); |
| 5078 LowDwVfpRegister double_scratch = double_scratch0(); | 5079 LowDwVfpRegister double_scratch = double_scratch0(); |
| 5079 | 5080 |
| 5080 if (instr->truncating()) { | 5081 if (instr->truncating()) { |
| 5081 __ TruncateDoubleToI(result_reg, double_input); | 5082 __ TruncateDoubleToI(result_reg, double_input); |
| 5082 } else { | 5083 } else { |
| 5083 __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); | 5084 __ TryDoubleToInt32Exact(result_reg, double_input, double_scratch); |
| 5084 // Deoptimize if the input wasn't a int32 (inside a double). | 5085 // Deoptimize if the input wasn't a int32 (inside a double). |
| 5085 DeoptimizeIf(ne, instr); | 5086 DeoptimizeIf(ne, instr, "lost precision or NaN"); |
| 5086 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 5087 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 5087 Label done; | 5088 Label done; |
| 5088 __ cmp(result_reg, Operand::Zero()); | 5089 __ cmp(result_reg, Operand::Zero()); |
| 5089 __ b(ne, &done); | 5090 __ b(ne, &done); |
| 5090 __ VmovHigh(scratch1, double_input); | 5091 __ VmovHigh(scratch1, double_input); |
| 5091 __ tst(scratch1, Operand(HeapNumber::kSignMask)); | 5092 __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
| 5092 DeoptimizeIf(ne, instr); | 5093 DeoptimizeIf(ne, instr, "minus zero"); |
| 5093 __ bind(&done); | 5094 __ bind(&done); |
| 5094 } | 5095 } |
| 5095 } | 5096 } |
| 5096 __ SmiTag(result_reg, SetCC); | 5097 __ SmiTag(result_reg, SetCC); |
| 5097 DeoptimizeIf(vs, instr); | 5098 DeoptimizeIf(vs, instr, "overflow"); |
| 5098 } | 5099 } |
| 5099 | 5100 |
| 5100 | 5101 |
| 5101 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { | 5102 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { |
| 5102 LOperand* input = instr->value(); | 5103 LOperand* input = instr->value(); |
| 5103 __ SmiTst(ToRegister(input)); | 5104 __ SmiTst(ToRegister(input)); |
| 5104 DeoptimizeIf(ne, instr); | 5105 DeoptimizeIf(ne, instr, "not a Smi"); |
| 5105 } | 5106 } |
| 5106 | 5107 |
| 5107 | 5108 |
| 5108 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { | 5109 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { |
| 5109 if (!instr->hydrogen()->value()->type().IsHeapObject()) { | 5110 if (!instr->hydrogen()->value()->type().IsHeapObject()) { |
| 5110 LOperand* input = instr->value(); | 5111 LOperand* input = instr->value(); |
| 5111 __ SmiTst(ToRegister(input)); | 5112 __ SmiTst(ToRegister(input)); |
| 5112 DeoptimizeIf(eq, instr); | 5113 DeoptimizeIf(eq, instr, "Smi"); |
| 5113 } | 5114 } |
| 5114 } | 5115 } |
| 5115 | 5116 |
| 5116 | 5117 |
| 5117 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 5118 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 5118 Register input = ToRegister(instr->value()); | 5119 Register input = ToRegister(instr->value()); |
| 5119 Register scratch = scratch0(); | 5120 Register scratch = scratch0(); |
| 5120 | 5121 |
| 5121 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); | 5122 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); |
| 5122 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 5123 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 5123 | 5124 |
| 5124 if (instr->hydrogen()->is_interval_check()) { | 5125 if (instr->hydrogen()->is_interval_check()) { |
| 5125 InstanceType first; | 5126 InstanceType first; |
| 5126 InstanceType last; | 5127 InstanceType last; |
| 5127 instr->hydrogen()->GetCheckInterval(&first, &last); | 5128 instr->hydrogen()->GetCheckInterval(&first, &last); |
| 5128 | 5129 |
| 5129 __ cmp(scratch, Operand(first)); | 5130 __ cmp(scratch, Operand(first)); |
| 5130 | 5131 |
| 5131 // If there is only one type in the interval check for equality. | 5132 // If there is only one type in the interval check for equality. |
| 5132 if (first == last) { | 5133 if (first == last) { |
| 5133 DeoptimizeIf(ne, instr); | 5134 DeoptimizeIf(ne, instr, "wrong instance type"); |
| 5134 } else { | 5135 } else { |
| 5135 DeoptimizeIf(lo, instr); | 5136 DeoptimizeIf(lo, instr, "wrong instance type"); |
| 5136 // Omit check for the last type. | 5137 // Omit check for the last type. |
| 5137 if (last != LAST_TYPE) { | 5138 if (last != LAST_TYPE) { |
| 5138 __ cmp(scratch, Operand(last)); | 5139 __ cmp(scratch, Operand(last)); |
| 5139 DeoptimizeIf(hi, instr); | 5140 DeoptimizeIf(hi, instr, "wrong instance type"); |
| 5140 } | 5141 } |
| 5141 } | 5142 } |
| 5142 } else { | 5143 } else { |
| 5143 uint8_t mask; | 5144 uint8_t mask; |
| 5144 uint8_t tag; | 5145 uint8_t tag; |
| 5145 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); | 5146 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); |
| 5146 | 5147 |
| 5147 if (base::bits::IsPowerOfTwo32(mask)) { | 5148 if (base::bits::IsPowerOfTwo32(mask)) { |
| 5148 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag)); | 5149 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag)); |
| 5149 __ tst(scratch, Operand(mask)); | 5150 __ tst(scratch, Operand(mask)); |
| 5150 DeoptimizeIf(tag == 0 ? ne : eq, instr); | 5151 DeoptimizeIf(tag == 0 ? ne : eq, instr, "wrong instance type"); |
| 5151 } else { | 5152 } else { |
| 5152 __ and_(scratch, scratch, Operand(mask)); | 5153 __ and_(scratch, scratch, Operand(mask)); |
| 5153 __ cmp(scratch, Operand(tag)); | 5154 __ cmp(scratch, Operand(tag)); |
| 5154 DeoptimizeIf(ne, instr); | 5155 DeoptimizeIf(ne, instr, "wrong instance type"); |
| 5155 } | 5156 } |
| 5156 } | 5157 } |
| 5157 } | 5158 } |
| 5158 | 5159 |
| 5159 | 5160 |
| 5160 void LCodeGen::DoCheckValue(LCheckValue* instr) { | 5161 void LCodeGen::DoCheckValue(LCheckValue* instr) { |
| 5161 Register reg = ToRegister(instr->value()); | 5162 Register reg = ToRegister(instr->value()); |
| 5162 Handle<HeapObject> object = instr->hydrogen()->object().handle(); | 5163 Handle<HeapObject> object = instr->hydrogen()->object().handle(); |
| 5163 AllowDeferredHandleDereference smi_check; | 5164 AllowDeferredHandleDereference smi_check; |
| 5164 if (isolate()->heap()->InNewSpace(*object)) { | 5165 if (isolate()->heap()->InNewSpace(*object)) { |
| 5165 Register reg = ToRegister(instr->value()); | 5166 Register reg = ToRegister(instr->value()); |
| 5166 Handle<Cell> cell = isolate()->factory()->NewCell(object); | 5167 Handle<Cell> cell = isolate()->factory()->NewCell(object); |
| 5167 __ mov(ip, Operand(Handle<Object>(cell))); | 5168 __ mov(ip, Operand(Handle<Object>(cell))); |
| 5168 __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset)); | 5169 __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset)); |
| 5169 __ cmp(reg, ip); | 5170 __ cmp(reg, ip); |
| 5170 } else { | 5171 } else { |
| 5171 __ cmp(reg, Operand(object)); | 5172 __ cmp(reg, Operand(object)); |
| 5172 } | 5173 } |
| 5173 DeoptimizeIf(ne, instr); | 5174 DeoptimizeIf(ne, instr, "value mismatch"); |
| 5174 } | 5175 } |
| 5175 | 5176 |
| 5176 | 5177 |
| 5177 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { | 5178 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { |
| 5178 { | 5179 { |
| 5179 PushSafepointRegistersScope scope(this); | 5180 PushSafepointRegistersScope scope(this); |
| 5180 __ push(object); | 5181 __ push(object); |
| 5181 __ mov(cp, Operand::Zero()); | 5182 __ mov(cp, Operand::Zero()); |
| 5182 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); | 5183 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); |
| 5183 RecordSafepointWithRegisters( | 5184 RecordSafepointWithRegisters( |
| 5184 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); | 5185 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); |
| 5185 __ StoreToSafepointRegisterSlot(r0, scratch0()); | 5186 __ StoreToSafepointRegisterSlot(r0, scratch0()); |
| 5186 } | 5187 } |
| 5187 __ tst(scratch0(), Operand(kSmiTagMask)); | 5188 __ tst(scratch0(), Operand(kSmiTagMask)); |
| 5188 DeoptimizeIf(eq, instr); | 5189 DeoptimizeIf(eq, instr, "instance migration failed"); |
| 5189 } | 5190 } |
| 5190 | 5191 |
| 5191 | 5192 |
| 5192 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { | 5193 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { |
| 5193 class DeferredCheckMaps FINAL : public LDeferredCode { | 5194 class DeferredCheckMaps FINAL : public LDeferredCode { |
| 5194 public: | 5195 public: |
| 5195 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) | 5196 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) |
| 5196 : LDeferredCode(codegen), instr_(instr), object_(object) { | 5197 : LDeferredCode(codegen), instr_(instr), object_(object) { |
| 5197 SetExit(check_maps()); | 5198 SetExit(check_maps()); |
| 5198 } | 5199 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5235 Handle<Map> map = maps->at(i).handle(); | 5236 Handle<Map> map = maps->at(i).handle(); |
| 5236 __ CompareMap(map_reg, map, &success); | 5237 __ CompareMap(map_reg, map, &success); |
| 5237 __ b(eq, &success); | 5238 __ b(eq, &success); |
| 5238 } | 5239 } |
| 5239 | 5240 |
| 5240 Handle<Map> map = maps->at(maps->size() - 1).handle(); | 5241 Handle<Map> map = maps->at(maps->size() - 1).handle(); |
| 5241 __ CompareMap(map_reg, map, &success); | 5242 __ CompareMap(map_reg, map, &success); |
| 5242 if (instr->hydrogen()->HasMigrationTarget()) { | 5243 if (instr->hydrogen()->HasMigrationTarget()) { |
| 5243 __ b(ne, deferred->entry()); | 5244 __ b(ne, deferred->entry()); |
| 5244 } else { | 5245 } else { |
| 5245 DeoptimizeIf(ne, instr); | 5246 DeoptimizeIf(ne, instr, "wrong map"); |
| 5246 } | 5247 } |
| 5247 | 5248 |
| 5248 __ bind(&success); | 5249 __ bind(&success); |
| 5249 } | 5250 } |
| 5250 | 5251 |
| 5251 | 5252 |
| 5252 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { | 5253 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { |
| 5253 DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped()); | 5254 DwVfpRegister value_reg = ToDoubleRegister(instr->unclamped()); |
| 5254 Register result_reg = ToRegister(instr->result()); | 5255 Register result_reg = ToRegister(instr->result()); |
| 5255 __ ClampDoubleToUint8(result_reg, value_reg, double_scratch0()); | 5256 __ ClampDoubleToUint8(result_reg, value_reg, double_scratch0()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 5274 __ UntagAndJumpIfSmi(result_reg, input_reg, &is_smi); | 5275 __ UntagAndJumpIfSmi(result_reg, input_reg, &is_smi); |
| 5275 | 5276 |
| 5276 // Check for heap number | 5277 // Check for heap number |
| 5277 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); | 5278 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
| 5278 __ cmp(scratch, Operand(factory()->heap_number_map())); | 5279 __ cmp(scratch, Operand(factory()->heap_number_map())); |
| 5279 __ b(eq, &heap_number); | 5280 __ b(eq, &heap_number); |
| 5280 | 5281 |
| 5281 // Check for undefined. Undefined is converted to zero for clamping | 5282 // Check for undefined. Undefined is converted to zero for clamping |
| 5282 // conversions. | 5283 // conversions. |
| 5283 __ cmp(input_reg, Operand(factory()->undefined_value())); | 5284 __ cmp(input_reg, Operand(factory()->undefined_value())); |
| 5284 DeoptimizeIf(ne, instr); | 5285 DeoptimizeIf(ne, instr, "not a heap number/undefined"); |
| 5285 __ mov(result_reg, Operand::Zero()); | 5286 __ mov(result_reg, Operand::Zero()); |
| 5286 __ jmp(&done); | 5287 __ jmp(&done); |
| 5287 | 5288 |
| 5288 // Heap number | 5289 // Heap number |
| 5289 __ bind(&heap_number); | 5290 __ bind(&heap_number); |
| 5290 __ vldr(temp_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); | 5291 __ vldr(temp_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); |
| 5291 __ ClampDoubleToUint8(result_reg, temp_reg, double_scratch0()); | 5292 __ ClampDoubleToUint8(result_reg, temp_reg, double_scratch0()); |
| 5292 __ jmp(&done); | 5293 __ jmp(&done); |
| 5293 | 5294 |
| 5294 // smi | 5295 // smi |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5744 DCHECK(!environment->HasBeenRegistered()); | 5745 DCHECK(!environment->HasBeenRegistered()); |
| 5745 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); | 5746 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); |
| 5746 | 5747 |
| 5747 GenerateOsrPrologue(); | 5748 GenerateOsrPrologue(); |
| 5748 } | 5749 } |
| 5749 | 5750 |
| 5750 | 5751 |
| 5751 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { | 5752 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { |
| 5752 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 5753 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| 5753 __ cmp(r0, ip); | 5754 __ cmp(r0, ip); |
| 5754 DeoptimizeIf(eq, instr); | 5755 DeoptimizeIf(eq, instr, "undefined"); |
| 5755 | 5756 |
| 5756 Register null_value = r5; | 5757 Register null_value = r5; |
| 5757 __ LoadRoot(null_value, Heap::kNullValueRootIndex); | 5758 __ LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 5758 __ cmp(r0, null_value); | 5759 __ cmp(r0, null_value); |
| 5759 DeoptimizeIf(eq, instr); | 5760 DeoptimizeIf(eq, instr, "null"); |
| 5760 | 5761 |
| 5761 __ SmiTst(r0); | 5762 __ SmiTst(r0); |
| 5762 DeoptimizeIf(eq, instr); | 5763 DeoptimizeIf(eq, instr, "Smi"); |
| 5763 | 5764 |
| 5764 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 5765 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 5765 __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE); | 5766 __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE); |
| 5766 DeoptimizeIf(le, instr); | 5767 DeoptimizeIf(le, instr, "wrong instance type"); |
| 5767 | 5768 |
| 5768 Label use_cache, call_runtime; | 5769 Label use_cache, call_runtime; |
| 5769 __ CheckEnumCache(null_value, &call_runtime); | 5770 __ CheckEnumCache(null_value, &call_runtime); |
| 5770 | 5771 |
| 5771 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5772 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5772 __ b(&use_cache); | 5773 __ b(&use_cache); |
| 5773 | 5774 |
| 5774 // Get the set of properties to enumerate. | 5775 // Get the set of properties to enumerate. |
| 5775 __ bind(&call_runtime); | 5776 __ bind(&call_runtime); |
| 5776 __ push(r0); | 5777 __ push(r0); |
| 5777 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); | 5778 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); |
| 5778 | 5779 |
| 5779 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5780 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5780 __ LoadRoot(ip, Heap::kMetaMapRootIndex); | 5781 __ LoadRoot(ip, Heap::kMetaMapRootIndex); |
| 5781 __ cmp(r1, ip); | 5782 __ cmp(r1, ip); |
| 5782 DeoptimizeIf(ne, instr); | 5783 DeoptimizeIf(ne, instr, "wrong map"); |
| 5783 __ bind(&use_cache); | 5784 __ bind(&use_cache); |
| 5784 } | 5785 } |
| 5785 | 5786 |
| 5786 | 5787 |
| 5787 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { | 5788 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
| 5788 Register map = ToRegister(instr->map()); | 5789 Register map = ToRegister(instr->map()); |
| 5789 Register result = ToRegister(instr->result()); | 5790 Register result = ToRegister(instr->result()); |
| 5790 Label load_cache, done; | 5791 Label load_cache, done; |
| 5791 __ EnumLength(result, map); | 5792 __ EnumLength(result, map); |
| 5792 __ cmp(result, Operand(Smi::FromInt(0))); | 5793 __ cmp(result, Operand(Smi::FromInt(0))); |
| 5793 __ b(ne, &load_cache); | 5794 __ b(ne, &load_cache); |
| 5794 __ mov(result, Operand(isolate()->factory()->empty_fixed_array())); | 5795 __ mov(result, Operand(isolate()->factory()->empty_fixed_array())); |
| 5795 __ jmp(&done); | 5796 __ jmp(&done); |
| 5796 | 5797 |
| 5797 __ bind(&load_cache); | 5798 __ bind(&load_cache); |
| 5798 __ LoadInstanceDescriptors(map, result); | 5799 __ LoadInstanceDescriptors(map, result); |
| 5799 __ ldr(result, | 5800 __ ldr(result, |
| 5800 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); | 5801 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); |
| 5801 __ ldr(result, | 5802 __ ldr(result, |
| 5802 FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); | 5803 FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); |
| 5803 __ cmp(result, Operand::Zero()); | 5804 __ cmp(result, Operand::Zero()); |
| 5804 DeoptimizeIf(eq, instr); | 5805 DeoptimizeIf(eq, instr, "no cache"); |
| 5805 | 5806 |
| 5806 __ bind(&done); | 5807 __ bind(&done); |
| 5807 } | 5808 } |
| 5808 | 5809 |
| 5809 | 5810 |
| 5810 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { | 5811 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { |
| 5811 Register object = ToRegister(instr->value()); | 5812 Register object = ToRegister(instr->value()); |
| 5812 Register map = ToRegister(instr->map()); | 5813 Register map = ToRegister(instr->map()); |
| 5813 __ ldr(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset)); | 5814 __ ldr(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset)); |
| 5814 __ cmp(map, scratch0()); | 5815 __ cmp(map, scratch0()); |
| 5815 DeoptimizeIf(ne, instr); | 5816 DeoptimizeIf(ne, instr, "wrong map"); |
| 5816 } | 5817 } |
| 5817 | 5818 |
| 5818 | 5819 |
| 5819 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, | 5820 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, |
| 5820 Register result, | 5821 Register result, |
| 5821 Register object, | 5822 Register object, |
| 5822 Register index) { | 5823 Register index) { |
| 5823 PushSafepointRegistersScope scope(this); | 5824 PushSafepointRegistersScope scope(this); |
| 5824 __ Push(object); | 5825 __ Push(object); |
| 5825 __ Push(index); | 5826 __ Push(index); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5902 __ Push(scope_info); | 5903 __ Push(scope_info); |
| 5903 __ push(ToRegister(instr->function())); | 5904 __ push(ToRegister(instr->function())); |
| 5904 CallRuntime(Runtime::kPushBlockContext, 2, instr); | 5905 CallRuntime(Runtime::kPushBlockContext, 2, instr); |
| 5905 RecordSafepoint(Safepoint::kNoLazyDeopt); | 5906 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 5906 } | 5907 } |
| 5907 | 5908 |
| 5908 | 5909 |
| 5909 #undef __ | 5910 #undef __ |
| 5910 | 5911 |
| 5911 } } // namespace v8::internal | 5912 } } // namespace v8::internal |
| OLD | NEW |