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

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

Issue 15769010: Improve code for integral modulus calculation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebased. Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « src/arm/lithium-arm.cc ('k') | src/hydrogen-instructions.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. 1 // Copyright 2012 the V8 project authors. All rights reserved.
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 1134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 } 1145 }
1146 } 1146 }
1147 1147
1148 1148
1149 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { 1149 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1150 // Nothing to do. 1150 // Nothing to do.
1151 } 1151 }
1152 1152
1153 1153
1154 void LCodeGen::DoModI(LModI* instr) { 1154 void LCodeGen::DoModI(LModI* instr) {
1155 if (instr->hydrogen()->HasPowerOf2Divisor()) { 1155 HMod* hmod = instr->hydrogen();
1156 Register dividend = ToRegister(instr->left()); 1156 HValue* left = hmod->left();
1157 Register result = ToRegister(instr->result()); 1157 HValue* right = hmod->right();
1158 if (hmod->HasPowerOf2Divisor()) {
1159 // TODO(svenpanne) We should really do the strength reduction on the
1160 // Hydrogen level.
1161 Register left_reg = ToRegister(instr->left());
1162 Register result_reg = ToRegister(instr->result());
1158 1163
1159 int32_t divisor = 1164 // Note: The code below even works when right contains kMinInt.
1160 HConstant::cast(instr->hydrogen()->right())->Integer32Value(); 1165 int32_t divisor = Abs(right->GetInteger32Constant());
1161 1166
1162 if (divisor < 0) divisor = -divisor; 1167 Label left_is_not_negative, done;
1168 if (left->CanBeNegative()) {
1169 __ cmp(left_reg, Operand::Zero());
1170 __ b(pl, &left_is_not_negative);
1171 __ rsb(result_reg, left_reg, Operand::Zero());
1172 __ and_(result_reg, result_reg, Operand(divisor - 1));
1173 __ rsb(result_reg, result_reg, Operand::Zero(), SetCC);
1174 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1175 DeoptimizeIf(eq, instr->environment());
1176 }
1177 __ b(&done);
1178 }
1163 1179
1164 Label positive_dividend, done; 1180 __ bind(&left_is_not_negative);
1165 __ cmp(dividend, Operand::Zero()); 1181 __ and_(result_reg, left_reg, Operand(divisor - 1));
1166 __ b(pl, &positive_dividend); 1182 __ bind(&done);
1167 __ rsb(result, dividend, Operand::Zero()); 1183
1168 __ and_(result, result, Operand(divisor - 1), SetCC); 1184 } else if (hmod->has_fixed_right_arg()) {
1169 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1185 Register left_reg = ToRegister(instr->left());
1186 Register right_reg = ToRegister(instr->right());
1187 Register result_reg = ToRegister(instr->result());
1188
1189 int32_t divisor = hmod->fixed_right_arg_value();
1190 ASSERT(IsPowerOf2(divisor));
1191
1192 // Check if our assumption of a fixed right operand still holds.
1193 __ cmp(right_reg, Operand(divisor));
1194 DeoptimizeIf(ne, instr->environment());
1195
1196 Label left_is_not_negative, done;
1197 if (left->CanBeNegative()) {
1198 __ cmp(left_reg, Operand::Zero());
1199 __ b(pl, &left_is_not_negative);
1200 __ rsb(result_reg, left_reg, Operand::Zero());
1201 __ and_(result_reg, result_reg, Operand(divisor - 1));
1202 __ rsb(result_reg, result_reg, Operand::Zero(), SetCC);
1203 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1204 DeoptimizeIf(eq, instr->environment());
1205 }
1206 __ b(&done);
1207 }
1208
1209 __ bind(&left_is_not_negative);
1210 __ and_(result_reg, left_reg, Operand(divisor - 1));
1211 __ bind(&done);
1212
1213 } else if (CpuFeatures::IsSupported(SUDIV)) {
1214 CpuFeatureScope scope(masm(), SUDIV);
1215
1216 Register left_reg = ToRegister(instr->left());
1217 Register right_reg = ToRegister(instr->right());
1218 Register result_reg = ToRegister(instr->result());
1219
1220 Label done;
1221 // Check for x % 0, sdiv might signal an exception. We have to deopt in this
1222 // case because we can't return a NaN.
1223 if (right->CanBeZero()) {
1224 __ cmp(right_reg, Operand::Zero());
1170 DeoptimizeIf(eq, instr->environment()); 1225 DeoptimizeIf(eq, instr->environment());
1171 } 1226 }
1172 __ rsb(result, result, Operand::Zero());
1173 __ b(&done);
1174 __ bind(&positive_dividend);
1175 __ and_(result, dividend, Operand(divisor - 1));
1176 __ bind(&done);
1177 return;
1178 }
1179 1227
1180 // These registers hold untagged 32 bit values. 1228 // Check for kMinInt % -1, sdiv will return kMinInt, which is not what we
1181 Register left = ToRegister(instr->left()); 1229 // want. We have to deopt if we care about -0, because we can't return that.
1182 Register right = ToRegister(instr->right()); 1230 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1183 Register result = ToRegister(instr->result()); 1231 Label no_overflow_possible;
1184 Label done; 1232 __ cmp(left_reg, Operand(kMinInt));
1185 1233 __ b(ne, &no_overflow_possible);
1186 // Check for x % 0. 1234 __ cmp(right_reg, Operand(-1));
1187 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { 1235 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1188 __ cmp(right, Operand::Zero()); 1236 DeoptimizeIf(eq, instr->environment());
1189 DeoptimizeIf(eq, instr->environment()); 1237 } else {
1190 } 1238 __ b(ne, &no_overflow_possible);
1191 1239 __ mov(result_reg, Operand::Zero());
1192 if (CpuFeatures::IsSupported(SUDIV)) { 1240 __ jmp(&done);
1193 CpuFeatureScope scope(masm(), SUDIV); 1241 }
1194 // Check for (kMinInt % -1). 1242 __ bind(&no_overflow_possible);
1195 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1196 Label left_not_min_int;
1197 __ cmp(left, Operand(kMinInt));
1198 __ b(ne, &left_not_min_int);
1199 __ cmp(right, Operand(-1));
1200 DeoptimizeIf(eq, instr->environment());
1201 __ bind(&left_not_min_int);
1202 } 1243 }
1203 1244
1204 // For r3 = r1 % r2; we can have the following ARM code 1245 // For 'r3 = r1 % r2' we can have the following ARM code:
1205 // sdiv r3, r1, r2 1246 // sdiv r3, r1, r2
1206 // mls r3, r3, r2, r1 1247 // mls r3, r3, r2, r1
1207 1248
1208 __ sdiv(result, left, right); 1249 __ sdiv(result_reg, left_reg, right_reg);
1209 __ mls(result, result, right, left); 1250 __ mls(result_reg, result_reg, right_reg, left_reg);
1210 1251
1211 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1252 // If we care about -0, test if the dividend is <0 and the result is 0.
1212 __ cmp(result, Operand::Zero()); 1253 if (left->CanBeNegative() &&
1254 hmod->CanBeZero() &&
1255 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1256 __ cmp(result_reg, Operand::Zero());
1213 __ b(ne, &done); 1257 __ b(ne, &done);
1214 __ cmp(left, Operand::Zero()); 1258 __ cmp(left_reg, Operand::Zero());
1215 DeoptimizeIf(lt, instr->environment()); 1259 DeoptimizeIf(lt, instr->environment());
1216 } 1260 }
1261 __ bind(&done);
1262
1217 } else { 1263 } else {
1264 // General case, without any SDIV support.
1265 Register left_reg = ToRegister(instr->left());
1266 Register right_reg = ToRegister(instr->right());
1267 Register result_reg = ToRegister(instr->result());
1218 Register scratch = scratch0(); 1268 Register scratch = scratch0();
1219 Register scratch2 = ToRegister(instr->temp()); 1269 ASSERT(!scratch.is(left_reg));
1220 DwVfpRegister dividend = ToDoubleRegister(instr->temp2()); 1270 ASSERT(!scratch.is(right_reg));
1221 DwVfpRegister divisor = ToDoubleRegister(instr->temp3()); 1271 ASSERT(!scratch.is(result_reg));
1272 DwVfpRegister dividend = ToDoubleRegister(instr->temp());
1273 DwVfpRegister divisor = ToDoubleRegister(instr->temp2());
1274 ASSERT(!divisor.is(dividend));
1222 DwVfpRegister quotient = double_scratch0(); 1275 DwVfpRegister quotient = double_scratch0();
1276 ASSERT(!quotient.is(dividend));
1277 ASSERT(!quotient.is(divisor));
1223 1278
1224 ASSERT(!dividend.is(divisor)); 1279 Label done;
1225 ASSERT(!dividend.is(quotient)); 1280 // Check for x % 0, we have to deopt in this case because we can't return a
1226 ASSERT(!divisor.is(quotient)); 1281 // NaN.
1227 ASSERT(!scratch.is(left)); 1282 if (right->CanBeZero()) {
1228 ASSERT(!scratch.is(right)); 1283 __ cmp(right_reg, Operand::Zero());
1229 ASSERT(!scratch.is(result)); 1284 DeoptimizeIf(eq, instr->environment());
1285 }
1230 1286
1231 Label vfp_modulo, right_negative; 1287 __ Move(result_reg, left_reg);
1232 1288 // Load the arguments in VFP registers. The divisor value is preloaded
1233 __ Move(result, left); 1289 // before. Be careful that 'right_reg' is only live on entry.
1234 1290 // TODO(svenpanne) The last comments seems to be wrong nowadays.
1235 // (0 % x) must yield 0 (if x is finite, which is the case here). 1291 __ vmov(dividend.low(), left_reg);
1236 __ cmp(left, Operand::Zero()); 1292 __ vmov(divisor.low(), right_reg);
1237 __ b(eq, &done);
1238 // Preload right in a vfp register.
1239 __ vmov(divisor.low(), right);
1240 __ b(lt, &vfp_modulo);
1241
1242 __ cmp(left, Operand(right));
1243 __ b(lt, &done);
1244
1245 // Check for (positive) power of two on the right hand side.
1246 __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
1247 scratch,
1248 &right_negative,
1249 &vfp_modulo);
1250 // Perform modulo operation (scratch contains right - 1).
1251 __ and_(result, scratch, Operand(left));
1252 __ b(&done);
1253
1254 __ bind(&right_negative);
1255 // Negate right. The sign of the divisor does not matter.
1256 __ rsb(right, right, Operand::Zero());
1257
1258 __ bind(&vfp_modulo);
1259 // Load the arguments in VFP registers.
1260 // The divisor value is preloaded before. Be careful that 'right'
1261 // is only live on entry.
1262 __ vmov(dividend.low(), left);
1263 // From here on don't use right as it may have been reallocated
1264 // (for example to scratch2).
1265 right = no_reg;
1266 1293
1267 __ vcvt_f64_s32(dividend, dividend.low()); 1294 __ vcvt_f64_s32(dividend, dividend.low());
1268 __ vcvt_f64_s32(divisor, divisor.low()); 1295 __ vcvt_f64_s32(divisor, divisor.low());
1269 1296
1270 // We do not care about the sign of the divisor. 1297 // We do not care about the sign of the divisor. Note that we still handle
1298 // the kMinInt % -1 case correctly, though.
1271 __ vabs(divisor, divisor); 1299 __ vabs(divisor, divisor);
1272 // Compute the quotient and round it to a 32bit integer. 1300 // Compute the quotient and round it to a 32bit integer.
1273 __ vdiv(quotient, dividend, divisor); 1301 __ vdiv(quotient, dividend, divisor);
1274 __ vcvt_s32_f64(quotient.low(), quotient); 1302 __ vcvt_s32_f64(quotient.low(), quotient);
1275 __ vcvt_f64_s32(quotient, quotient.low()); 1303 __ vcvt_f64_s32(quotient, quotient.low());
1276 1304
1277 // Compute the remainder in result. 1305 // Compute the remainder in result.
1278 DwVfpRegister double_scratch = dividend; 1306 DwVfpRegister double_scratch = dividend;
1279 __ vmul(double_scratch, divisor, quotient); 1307 __ vmul(double_scratch, divisor, quotient);
1280 __ vcvt_s32_f64(double_scratch.low(), double_scratch); 1308 __ vcvt_s32_f64(double_scratch.low(), double_scratch);
1281 __ vmov(scratch, double_scratch.low()); 1309 __ vmov(scratch, double_scratch.low());
1310 __ sub(result_reg, left_reg, scratch, SetCC);
1282 1311
1283 if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1312 // If we care about -0, test if the dividend is <0 and the result is 0.
1284 __ sub(result, left, scratch); 1313 if (left->CanBeNegative() &&
1285 } else { 1314 hmod->CanBeZero() &&
1286 Label ok; 1315 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1287 // Check for -0. 1316 __ b(ne, &done);
1288 __ sub(scratch2, left, scratch, SetCC); 1317 __ cmp(left_reg, Operand::Zero());
1289 __ b(ne, &ok);
1290 __ cmp(left, Operand::Zero());
1291 DeoptimizeIf(mi, instr->environment()); 1318 DeoptimizeIf(mi, instr->environment());
1292 __ bind(&ok);
1293 // Load the result and we are done.
1294 __ mov(result, scratch2);
1295 } 1319 }
1320 __ bind(&done);
1296 } 1321 }
1297 __ bind(&done);
1298 } 1322 }
1299 1323
1300 1324
1301 void LCodeGen::EmitSignedIntegerDivisionByConstant( 1325 void LCodeGen::EmitSignedIntegerDivisionByConstant(
1302 Register result, 1326 Register result,
1303 Register dividend, 1327 Register dividend,
1304 int32_t divisor, 1328 int32_t divisor,
1305 Register remainder, 1329 Register remainder,
1306 Register scratch, 1330 Register scratch,
1307 LEnvironment* environment) { 1331 LEnvironment* environment) {
(...skipping 4600 matching lines...) Expand 10 before | Expand all | Expand 10 after
5908 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index)); 5932 __ sub(scratch, result, Operand::PointerOffsetFromSmiKey(index));
5909 __ ldr(result, FieldMemOperand(scratch, 5933 __ ldr(result, FieldMemOperand(scratch,
5910 FixedArray::kHeaderSize - kPointerSize)); 5934 FixedArray::kHeaderSize - kPointerSize));
5911 __ bind(&done); 5935 __ bind(&done);
5912 } 5936 }
5913 5937
5914 5938
5915 #undef __ 5939 #undef __
5916 5940
5917 } } // namespace v8::internal 5941 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/arm/lithium-arm.cc ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698