Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: src/mips/lithium-codegen-mips.cc

Issue 189433008: MIPS: Consistenly handle power-of-2 divisors in division-like operations. (Closed) Base URL: https://github.com/v8/v8.git@gbl
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/mips/lithium-mips.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved.7 1 // Copyright 2012 the V8 project authors. All rights reserved.7
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1042 matching lines...) Expand 10 before | Expand all | Expand 10 after
1053 UNREACHABLE(); 1053 UNREACHABLE();
1054 } 1054 }
1055 } 1055 }
1056 1056
1057 1057
1058 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { 1058 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1059 GenerateOsrPrologue(); 1059 GenerateOsrPrologue();
1060 } 1060 }
1061 1061
1062 1062
1063 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
1064 Register dividend = ToRegister(instr->dividend());
1065 int32_t divisor = instr->divisor();
1066 ASSERT(dividend.is(ToRegister(instr->result())));
1067
1068 // Theoretically, a variation of the branch-free code for integer division by
1069 // a power of 2 (calculating the remainder via an additional multiplication
1070 // (which gets simplified to an 'and') and subtraction) should be faster, and
1071 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
1072 // indicate that positive dividends are heavily favored, so the branching
1073 // version performs better.
1074 HMod* hmod = instr->hydrogen();
1075 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1076 Label dividend_is_not_negative, done;
1077
1078 if (hmod->left()->CanBeNegative()) {
1079 __ Branch(&dividend_is_not_negative, ge, dividend, Operand(zero_reg));
1080 // Note: The code below even works when right contains kMinInt.
1081 __ subu(dividend, zero_reg, dividend);
1082 __ And(dividend, dividend, Operand(mask));
1083 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1084 DeoptimizeIf(eq, instr->environment(), dividend, Operand(zero_reg));
1085 }
1086 __ Branch(USE_DELAY_SLOT, &done);
1087 __ subu(dividend, zero_reg, dividend);
1088 }
1089
1090 __ bind(&dividend_is_not_negative);
1091 __ And(dividend, dividend, Operand(mask));
1092 __ bind(&done);
1093 }
1094
1095
1063 void LCodeGen::DoModI(LModI* instr) { 1096 void LCodeGen::DoModI(LModI* instr) {
1064 HMod* hmod = instr->hydrogen(); 1097 HMod* hmod = instr->hydrogen();
1065 HValue* left = hmod->left(); 1098 HValue* left = hmod->left();
1066 HValue* right = hmod->right(); 1099 HValue* right = hmod->right();
1067 if (hmod->RightIsPowerOf2()) { 1100 const Register left_reg = ToRegister(instr->left());
1068 const Register left_reg = ToRegister(instr->left()); 1101 const Register right_reg = ToRegister(instr->right());
1069 const Register result_reg = ToRegister(instr->result()); 1102 const Register result_reg = ToRegister(instr->result());
1070 1103
1071 // Note: The code below even works when right contains kMinInt. 1104 // div runs in the background while we check for special cases.
1072 int32_t divisor = Abs(right->GetInteger32Constant()); 1105 __ div(left_reg, right_reg);
1073 1106
1074 Label left_is_not_negative, done; 1107 Label done;
1075 if (left->CanBeNegative()) { 1108 // Check for x % 0, we have to deopt in this case because we can't return a
1076 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, 1109 // NaN.
1077 &left_is_not_negative, ge, left_reg, Operand(zero_reg)); 1110 if (right->CanBeZero()) {
1078 __ subu(result_reg, zero_reg, left_reg); 1111 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg));
1079 __ And(result_reg, result_reg, divisor - 1); 1112 }
1080 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1081 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1082 }
1083 __ Branch(USE_DELAY_SLOT, &done);
1084 __ subu(result_reg, zero_reg, result_reg);
1085 }
1086 1113
1087 __ bind(&left_is_not_negative); 1114 // Check for kMinInt % -1, we have to deopt if we care about -0, because we
1088 __ And(result_reg, left_reg, divisor - 1); 1115 // can't return that.
1089 __ bind(&done); 1116 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1090 } else { 1117 Label left_not_min_int;
1091 const Register scratch = scratch0(); 1118 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt));
1092 const Register left_reg = ToRegister(instr->left()); 1119 // TODO(svenpanne) Don't deopt when we don't care about -0.
1093 const Register result_reg = ToRegister(instr->result()); 1120 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1));
1121 __ bind(&left_not_min_int);
1122 }
1094 1123
1095 // div runs in the background while we check for special cases. 1124 // TODO(svenpanne) Only emit the test/deopt if we have to.
1096 Register right_reg = EmitLoadRegister(instr->right(), scratch); 1125 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg));
1097 __ div(left_reg, right_reg); 1126 __ mfhi(result_reg);
1098 1127
1099 Label done; 1128 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1100 // Check for x % 0, we have to deopt in this case because we can't return a 1129 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1101 // NaN.
1102 if (right->CanBeZero()) {
1103 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg));
1104 }
1105
1106 // Check for kMinInt % -1, we have to deopt if we care about -0, because we
1107 // can't return that.
1108 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1109 Label left_not_min_int;
1110 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt));
1111 // TODO(svenpanne) Don't deopt when we don't care about -0.
1112 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1));
1113 __ bind(&left_not_min_int);
1114 }
1115
1116 // TODO(svenpanne) Only emit the test/deopt if we have to.
1117 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg));
1118 __ mfhi(result_reg);
1119
1120 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1121 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1122 }
1123 __ bind(&done);
1124 } 1130 }
1131 __ bind(&done);
1125 } 1132 }
1126 1133
1127 1134
1128 void LCodeGen::EmitSignedIntegerDivisionByConstant( 1135 void LCodeGen::EmitSignedIntegerDivisionByConstant(
1129 Register result, 1136 Register result,
1130 Register dividend, 1137 Register dividend,
1131 int32_t divisor, 1138 int32_t divisor,
1132 Register remainder, 1139 Register remainder,
1133 Register scratch, 1140 Register scratch,
1134 LEnvironment* environment) { 1141 LEnvironment* environment) {
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
1270 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); 1277 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
1271 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); 1278 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
1272 1279
1273 // This is computed in-place. 1280 // This is computed in-place.
1274 ASSERT(addend.is(ToDoubleRegister(instr->result()))); 1281 ASSERT(addend.is(ToDoubleRegister(instr->result())));
1275 1282
1276 __ madd_d(addend, addend, multiplier, multiplicand); 1283 __ madd_d(addend, addend, multiplier, multiplicand);
1277 } 1284 }
1278 1285
1279 1286
1287 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
1288 Register left = ToRegister(instr->dividend());
1289 Register remainder = ToRegister(instr->temp());
1290 Register scratch = scratch0();
1291 Register result = ToRegister(instr->result());
1292
1293 ASSERT(instr->divisor()->IsConstantOperand());
1294 Label done;
1295 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->divisor()));
1296 if (divisor < 0) {
1297 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1298 }
1299 EmitSignedIntegerDivisionByConstant(result,
1300 left,
1301 divisor,
1302 remainder,
1303 scratch,
1304 instr->environment());
1305 // We performed a truncating division. Correct the result if necessary.
1306 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1307 __ Xor(scratch , remainder, Operand(divisor));
1308 __ Branch(&done, ge, scratch, Operand(zero_reg));
1309 __ Subu(result, result, Operand(1));
1310 __ bind(&done);
1311 }
1312
1313
1280 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { 1314 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1281 const Register result = ToRegister(instr->result()); 1315 const Register result = ToRegister(instr->result());
1282 const Register left = ToRegister(instr->left()); 1316 const Register left = ToRegister(instr->left());
1283 const Register remainder = ToRegister(instr->temp()); 1317 const Register remainder = ToRegister(instr->temp());
1284 const Register scratch = scratch0(); 1318 const Register scratch = scratch0();
1285 1319
1286 if (instr->right()->IsConstantOperand()) { 1320 Label done;
1287 Label done; 1321 const Register right = ToRegister(instr->right());
1288 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
1289 if (divisor < 0) {
1290 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1291 }
1292 EmitSignedIntegerDivisionByConstant(result,
1293 left,
1294 divisor,
1295 remainder,
1296 scratch,
1297 instr->environment());
1298 // We performed a truncating division. Correct the result if necessary.
1299 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1300 __ Xor(scratch , remainder, Operand(divisor));
1301 __ Branch(&done, ge, scratch, Operand(zero_reg));
1302 __ Subu(result, result, Operand(1));
1303 __ bind(&done);
1304 } else {
1305 Label done;
1306 const Register right = ToRegister(instr->right());
1307 1322
1308 // On MIPS div is asynchronous - it will run in the background while we 1323 // On MIPS div is asynchronous - it will run in the background while we
1309 // check for special cases. 1324 // check for special cases.
1310 __ div(left, right); 1325 __ div(left, right);
1311 1326
1312 // Check for x / 0. 1327 // Check for x / 0.
1313 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); 1328 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1314 1329
1315 // Check for (0 / -x) that will produce negative zero. 1330 // Check for (0 / -x) that will produce negative zero.
1316 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1331 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1317 Label left_not_zero; 1332 Label left_not_zero;
1318 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); 1333 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1319 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); 1334 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1320 __ bind(&left_not_zero); 1335 __ bind(&left_not_zero);
1321 } 1336 }
1322 1337
1323 // Check for (kMinInt / -1). 1338 // Check for (kMinInt / -1).
1324 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1339 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1325 Label left_not_min_int; 1340 Label left_not_min_int;
1326 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); 1341 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1327 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); 1342 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1328 __ bind(&left_not_min_int); 1343 __ bind(&left_not_min_int);
1329 } 1344 }
1330 1345
1331 __ mfhi(remainder); 1346 __ mfhi(remainder);
1332 __ mflo(result); 1347 __ mflo(result);
1333 1348
1334 // We performed a truncating division. Correct the result if necessary. 1349 // We performed a truncating division. Correct the result if necessary.
1335 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); 1350 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1336 __ Xor(scratch , remainder, Operand(right)); 1351 __ Xor(scratch , remainder, Operand(right));
1337 __ Branch(&done, ge, scratch, Operand(zero_reg)); 1352 __ Branch(&done, ge, scratch, Operand(zero_reg));
1338 __ Subu(result, result, Operand(1)); 1353 __ Subu(result, result, Operand(1));
1339 __ bind(&done); 1354 __ bind(&done);
1340 }
1341 } 1355 }
1342 1356
1343 1357
1344 void LCodeGen::DoMulI(LMulI* instr) { 1358 void LCodeGen::DoMulI(LMulI* instr) {
1345 Register scratch = scratch0(); 1359 Register scratch = scratch0();
1346 Register result = ToRegister(instr->result()); 1360 Register result = ToRegister(instr->result());
1347 // Note that result may alias left. 1361 // Note that result may alias left.
1348 Register left = ToRegister(instr->left()); 1362 Register left = ToRegister(instr->left());
1349 LOperand* right_op = instr->right(); 1363 LOperand* right_op = instr->right();
1350 1364
(...skipping 4401 matching lines...) Expand 10 before | Expand all | Expand 10 after
5752 __ Subu(scratch, result, scratch); 5766 __ Subu(scratch, result, scratch);
5753 __ lw(result, FieldMemOperand(scratch, 5767 __ lw(result, FieldMemOperand(scratch,
5754 FixedArray::kHeaderSize - kPointerSize)); 5768 FixedArray::kHeaderSize - kPointerSize));
5755 __ bind(&done); 5769 __ bind(&done);
5756 } 5770 }
5757 5771
5758 5772
5759 #undef __ 5773 #undef __
5760 5774
5761 } } // namespace v8::internal 5775 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | src/mips/lithium-mips.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698