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

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

Issue 2876011: Do integer mod via sum-of-digits technique. This benefits the date (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 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
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 6240 matching lines...) Expand 10 before | Expand all | Expand 10 after
6251 6251
6252 #ifdef DEBUG 6252 #ifdef DEBUG
6253 bool CodeGenerator::HasValidEntryRegisters() { return true; } 6253 bool CodeGenerator::HasValidEntryRegisters() { return true; }
6254 #endif 6254 #endif
6255 6255
6256 6256
6257 #undef __ 6257 #undef __
6258 #define __ ACCESS_MASM(masm) 6258 #define __ ACCESS_MASM(masm)
6259 6259
6260 6260
6261 // This uses versions of the sum-of-digits-to-see-if-a-number-is-divisible-by-3
6262 // trick. See http://en.wikipedia.org/wiki/Divisibility_rule
6263 // Takes the sum of the digits base (mask + 1) repeatedly until we have a
6264 // number from 0 to mask. On exit the 'eq' condition flags are set if the
6265 // answer is exactly the mask.
6266 void DigitSum(MacroAssembler* masm,
Søren Thygesen Gjesse 2010/06/28 07:19:36 static (times 5)? And why are these functions not
6267 Register lhs,
6268 int mask,
6269 int shift) {
6270 ASSERT(mask > 0);
6271 ASSERT(mask <= 0xff); // This ensures we don't need ip to use it.
6272 Label loop, entry;
6273 __ jmp(&entry);
6274 __ bind(&loop);
6275 __ and_(ip, lhs, Operand(mask));
6276 __ add(lhs, ip, Operand(lhs, LSR, shift));
6277 __ bind(&entry);
6278 __ cmp(lhs, Operand(mask));
6279 __ b(gt, &loop);
6280 }
6281
6282
6283 void DigitSum(MacroAssembler* masm,
6284 Register lhs,
6285 Register scratch,
6286 int mask,
6287 int shift1,
6288 int shift2) {
6289 ASSERT(mask > 0);
6290 ASSERT(mask <= 0xff); // This ensures we don't need ip to use it.
6291 Label loop, entry;
6292 __ jmp(&entry);
6293 __ bind(&loop);
6294 __ bic(scratch, lhs, Operand(mask));
6295 __ and_(ip, lhs, Operand(mask));
6296 __ add(lhs, ip, Operand(lhs, LSR, shift1));
6297 __ add(lhs, lhs, Operand(scratch, LSR, shift2));
6298 __ bind(&entry);
6299 __ cmp(lhs, Operand(mask));
6300 __ b(gt, &loop);
6301 }
6302
6303
6304 // Splits the number into two halves (bottom half has shift bits). The top
6305 // half is subtracted from the bottom half. If the result is negative then
6306 // rhs is added.
6307 void ModGetInRangeBySubtraction(MacroAssembler* masm,
6308 Register lhs,
6309 int shift,
6310 int rhs) {
6311 int mask = (1 << shift) - 1;
6312 __ and_(ip, lhs, Operand(mask));
6313 __ sub(lhs, ip, Operand(lhs, LSR, shift), SetCC);
6314 __ add(lhs, lhs, Operand(rhs), LeaveCC, mi);
6315 }
6316
6317
6318 void ModReduce(MacroAssembler* masm,
6319 Register lhs,
6320 int max,
6321 int denominator) {
6322 int limit = denominator;
6323 while (limit * 2 <= max) limit *= 2;
6324 while (limit >= denominator) {
6325 __ cmp(lhs, Operand(limit));
6326 __ sub(lhs, lhs, Operand(limit), LeaveCC, ge);
6327 limit >>= 1;
6328 }
6329 }
6330
6331
6332 void ModAnswer(MacroAssembler* masm,
6333 Register result,
6334 Register shift_distance,
6335 Register mask_bits,
6336 Register sum_of_digits) {
6337 __ add(result, mask_bits, Operand(sum_of_digits, LSL, shift_distance));
6338 __ Ret();
6339 }
6340
6261 Handle<String> Reference::GetName() { 6341 Handle<String> Reference::GetName() {
6262 ASSERT(type_ == NAMED); 6342 ASSERT(type_ == NAMED);
6263 Property* property = expression_->AsProperty(); 6343 Property* property = expression_->AsProperty();
6264 if (property == NULL) { 6344 if (property == NULL) {
6265 // Global variable reference treated as a named property reference. 6345 // Global variable reference treated as a named property reference.
6266 VariableProxy* proxy = expression_->AsVariableProxy(); 6346 VariableProxy* proxy = expression_->AsVariableProxy();
6267 ASSERT(proxy->AsVariable() != NULL); 6347 ASSERT(proxy->AsVariable() != NULL);
6268 ASSERT(proxy->AsVariable()->is_global()); 6348 ASSERT(proxy->AsVariable()->is_global());
6269 return proxy->name(); 6349 return proxy->name();
6270 } else { 6350 } else {
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
6614 static const uint32_t exponent_word_for_1 = 6694 static const uint32_t exponent_word_for_1 =
6615 HeapNumber::kExponentBias << HeapNumber::kExponentShift; 6695 HeapNumber::kExponentBias << HeapNumber::kExponentShift;
6616 __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq); 6696 __ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
6617 // 1, 0 and -1 all have 0 for the second word. 6697 // 1, 0 and -1 all have 0 for the second word.
6618 __ mov(mantissa, Operand(0)); 6698 __ mov(mantissa, Operand(0));
6619 __ Ret(); 6699 __ Ret();
6620 6700
6621 __ bind(&not_special); 6701 __ bind(&not_special);
6622 // Count leading zeros. Uses mantissa for a scratch register on pre-ARM5. 6702 // Count leading zeros. Uses mantissa for a scratch register on pre-ARM5.
6623 // Gets the wrong answer for 0, but we already checked for that case above. 6703 // Gets the wrong answer for 0, but we already checked for that case above.
6624 __ CountLeadingZeros(source_, mantissa, zeros_); 6704 __ CountLeadingZeros(zeros_, source_, mantissa);
6625 // Compute exponent and or it into the exponent register. 6705 // Compute exponent and or it into the exponent register.
6626 // We use mantissa as a scratch register here. Use a fudge factor to 6706 // We use mantissa as a scratch register here. Use a fudge factor to
6627 // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts 6707 // divide the constant 31 + HeapNumber::kExponentBias, 0x41d, into two parts
6628 // that fit in the ARM's constant field. 6708 // that fit in the ARM's constant field.
6629 int fudge = 0x400; 6709 int fudge = 0x400;
6630 __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge)); 6710 __ rsb(mantissa, zeros_, Operand(31 + HeapNumber::kExponentBias - fudge));
6631 __ add(mantissa, mantissa, Operand(fudge)); 6711 __ add(mantissa, mantissa, Operand(fudge));
6632 __ orr(exponent, 6712 __ orr(exponent,
6633 exponent, 6713 exponent,
6634 Operand(mantissa, LSL, HeapNumber::kExponentShift)); 6714 Operand(mantissa, LSL, HeapNumber::kExponentShift));
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after
7343 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 7423 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
7344 7424
7345 // Smi-smi case (overflow). 7425 // Smi-smi case (overflow).
7346 // Since both are Smis there is no heap number to overwrite, so allocate. 7426 // Since both are Smis there is no heap number to overwrite, so allocate.
7347 // The new heap number is in r5. r3 and r7 are scratch. 7427 // The new heap number is in r5. r3 and r7 are scratch.
7348 __ AllocateHeapNumber( 7428 __ AllocateHeapNumber(
7349 r5, r3, r7, heap_number_map, lhs.is(r0) ? &slow_reverse : &slow); 7429 r5, r3, r7, heap_number_map, lhs.is(r0) ? &slow_reverse : &slow);
7350 7430
7351 // If we have floating point hardware, inline ADD, SUB, MUL, and DIV, 7431 // If we have floating point hardware, inline ADD, SUB, MUL, and DIV,
7352 // using registers d7 and d6 for the double values. 7432 // using registers d7 and d6 for the double values.
7353 if (use_fp_registers) { 7433 if (CpuFeatures::IsSupported(VFP3)) {
7354 CpuFeatures::Scope scope(VFP3); 7434 CpuFeatures::Scope scope(VFP3);
7355 __ mov(r7, Operand(rhs, ASR, kSmiTagSize)); 7435 __ mov(r7, Operand(rhs, ASR, kSmiTagSize));
7356 __ vmov(s15, r7); 7436 __ vmov(s15, r7);
7357 __ vcvt_f64_s32(d7, s15); 7437 __ vcvt_f64_s32(d7, s15);
7358 __ mov(r7, Operand(lhs, ASR, kSmiTagSize)); 7438 __ mov(r7, Operand(lhs, ASR, kSmiTagSize));
7359 __ vmov(s13, r7); 7439 __ vmov(s13, r7);
7360 __ vcvt_f64_s32(d6, s13); 7440 __ vcvt_f64_s32(d6, s13);
7441 if (!use_fp_registers) {
7442 __ vmov(r2, r3, d7);
7443 __ vmov(r0, r1, d6);
7444 }
7361 } else { 7445 } else {
7362 // Write Smi from rhs to r3 and r2 in double format. r3 is scratch. 7446 // Write Smi from rhs to r3 and r2 in double format. r9 is scratch.
7363 __ mov(r7, Operand(rhs)); 7447 __ mov(r7, Operand(rhs));
7364 ConvertToDoubleStub stub1(r3, r2, r7, r9); 7448 ConvertToDoubleStub stub1(r3, r2, r7, r9);
7365 __ push(lr); 7449 __ push(lr);
7366 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET); 7450 __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
7367 // Write Smi from lhs to r1 and r0 in double format. r9 is scratch. 7451 // Write Smi from lhs to r1 and r0 in double format. r9 is scratch.
7368 __ mov(r7, Operand(lhs)); 7452 __ mov(r7, Operand(lhs));
7369 ConvertToDoubleStub stub2(r1, r0, r7, r9); 7453 ConvertToDoubleStub stub2(r1, r0, r7, r9);
7370 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET); 7454 __ Call(stub2.GetCode(), RelocInfo::CODE_TARGET);
7371 __ pop(lr); 7455 __ pop(lr);
7372 } 7456 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
7427 // Calling convention says that second double is in r2 and r3. 7511 // Calling convention says that second double is in r2 and r3.
7428 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); 7512 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset));
7429 } 7513 }
7430 __ jmp(&finished_loading_r0); 7514 __ jmp(&finished_loading_r0);
7431 __ bind(&r0_is_smi); 7515 __ bind(&r0_is_smi);
7432 if (mode_ == OVERWRITE_RIGHT) { 7516 if (mode_ == OVERWRITE_RIGHT) {
7433 // We can't overwrite a Smi so get address of new heap number into r5. 7517 // We can't overwrite a Smi so get address of new heap number into r5.
7434 __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); 7518 __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
7435 } 7519 }
7436 7520
7437 if (use_fp_registers) { 7521 if (CpuFeatures::IsSupported(VFP3)) {
7438 CpuFeatures::Scope scope(VFP3); 7522 CpuFeatures::Scope scope(VFP3);
7439 // Convert smi in r0 to double in d7. 7523 // Convert smi in r0 to double in d7.
7440 __ mov(r7, Operand(r0, ASR, kSmiTagSize)); 7524 __ mov(r7, Operand(r0, ASR, kSmiTagSize));
7441 __ vmov(s15, r7); 7525 __ vmov(s15, r7);
7442 __ vcvt_f64_s32(d7, s15); 7526 __ vcvt_f64_s32(d7, s15);
7527 if (!use_fp_registers) {
7528 __ vmov(r2, r3, d7);
7529 }
7443 } else { 7530 } else {
7444 // Write Smi from r0 to r3 and r2 in double format. 7531 // Write Smi from r0 to r3 and r2 in double format.
7445 __ mov(r7, Operand(r0)); 7532 __ mov(r7, Operand(r0));
7446 ConvertToDoubleStub stub3(r3, r2, r7, r4); 7533 ConvertToDoubleStub stub3(r3, r2, r7, r4);
7447 __ push(lr); 7534 __ push(lr);
7448 __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET); 7535 __ Call(stub3.GetCode(), RelocInfo::CODE_TARGET);
7449 __ pop(lr); 7536 __ pop(lr);
7450 } 7537 }
7451 7538
7452 // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis. 7539 // HEAP_NUMBERS stub is slower than GENERIC on a pair of smis.
(...skipping 30 matching lines...) Expand all
7483 // Calling convention says that first double is in r0 and r1. 7570 // Calling convention says that first double is in r0 and r1.
7484 __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset)); 7571 __ Ldrd(r0, r1, FieldMemOperand(r1, HeapNumber::kValueOffset));
7485 } 7572 }
7486 __ jmp(&finished_loading_r1); 7573 __ jmp(&finished_loading_r1);
7487 __ bind(&r1_is_smi); 7574 __ bind(&r1_is_smi);
7488 if (mode_ == OVERWRITE_LEFT) { 7575 if (mode_ == OVERWRITE_LEFT) {
7489 // We can't overwrite a Smi so get address of new heap number into r5. 7576 // We can't overwrite a Smi so get address of new heap number into r5.
7490 __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow); 7577 __ AllocateHeapNumber(r5, r4, r7, heap_number_map, &slow);
7491 } 7578 }
7492 7579
7493 if (use_fp_registers) { 7580 if (CpuFeatures::IsSupported(VFP3)) {
7494 CpuFeatures::Scope scope(VFP3); 7581 CpuFeatures::Scope scope(VFP3);
7495 // Convert smi in r1 to double in d6. 7582 // Convert smi in r1 to double in d6.
7496 __ mov(r7, Operand(r1, ASR, kSmiTagSize)); 7583 __ mov(r7, Operand(r1, ASR, kSmiTagSize));
7497 __ vmov(s13, r7); 7584 __ vmov(s13, r7);
7498 __ vcvt_f64_s32(d6, s13); 7585 __ vcvt_f64_s32(d6, s13);
7586 if (!use_fp_registers) {
7587 __ vmov(r0, r1, d6);
7588 }
7499 } else { 7589 } else {
7500 // Write Smi from r1 to r1 and r0 in double format. 7590 // Write Smi from r1 to r1 and r0 in double format.
7501 __ mov(r7, Operand(r1)); 7591 __ mov(r7, Operand(r1));
7502 ConvertToDoubleStub stub4(r1, r0, r7, r9); 7592 ConvertToDoubleStub stub4(r1, r0, r7, r9);
7503 __ push(lr); 7593 __ push(lr);
7504 __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET); 7594 __ Call(stub4.GetCode(), RelocInfo::CODE_TARGET);
7505 __ pop(lr); 7595 __ pop(lr);
7506 } 7596 }
7507 7597
7508 __ bind(&finished_loading_r1); 7598 __ bind(&finished_loading_r1);
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after
7935 *required_shift = 2; 8025 *required_shift = 2;
7936 break; 8026 break;
7937 default: 8027 default:
7938 ASSERT(!IsPowerOf2(known_int)); // That would be very inefficient. 8028 ASSERT(!IsPowerOf2(known_int)); // That would be very inefficient.
7939 __ mul(result, source, known_int_register); 8029 __ mul(result, source, known_int_register);
7940 *required_shift = 0; 8030 *required_shift = 0;
7941 } 8031 }
7942 } 8032 }
7943 8033
7944 8034
8035 // See comment for class.
8036 void IntegerModStub::Generate(MacroAssembler* masm) {
8037 __ mov(lhs_, Operand(lhs_, LSR, shift_distance_));
8038 __ bic(odd_number_, odd_number_, Operand(1));
8039 __ mov(odd_number_, Operand(odd_number_, LSL, 1));
8040 // We now have (odd_number_ - 1) * 2 in the register.
8041 // Build a switch out of branches instead of data because it avoids
8042 // having to teach the assembler about intra-code-object pointers
8043 // that are not in relative branch instructions.
8044 Label mod3, mod5, mod7, mod9, mod11, mod13, mod15, mod17, mod19;
8045 Label mod21, mod23, mod25;
8046 { Assembler::BlockConstPoolScope block_const_pool(masm);
8047 __ add(pc, pc, Operand(odd_number_));
8048 // When you read pc it is always 8 ahead, but when you write it you always
8049 // write the actual value. So we put in two nops to take up the slack.
8050 __ nop();
8051 __ nop();
8052 __ b(&mod3);
8053 __ b(&mod5);
8054 __ b(&mod7);
8055 __ b(&mod9);
8056 __ b(&mod11);
8057 __ b(&mod13);
8058 __ b(&mod15);
8059 __ b(&mod17);
8060 __ b(&mod19);
8061 __ b(&mod21);
8062 __ b(&mod23);
8063 __ b(&mod25);
8064 }
8065 __ bind(&mod3);
8066 DigitSum(masm, lhs_, 3, 2);
8067 __ sub(lhs_, lhs_, Operand(3), LeaveCC, eq);
8068 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8069
8070 __ bind(&mod5);
8071 DigitSum(masm, lhs_, 0xf, 4);
8072 ModGetInRangeBySubtraction(masm, lhs_, 2, 5);
8073 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8074
8075 __ bind(&mod7);
8076 DigitSum(masm, lhs_, 7, 3);
8077 __ sub(lhs_, lhs_, Operand(7), LeaveCC, eq);
8078 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8079
8080 __ bind(&mod9);
8081 DigitSum(masm, lhs_, 0x3f, 6);
8082 ModGetInRangeBySubtraction(masm, lhs_, 3, 9);
8083 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8084
8085 __ bind(&mod11);
8086 DigitSum(masm, lhs_, r5, 0x3f, 6, 3);
8087 ModReduce(masm, lhs_, 0x3f, 11);
8088 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8089
8090 __ bind(&mod13);
8091 DigitSum(masm, lhs_, r5, 0xff, 8, 5);
8092 ModReduce(masm, lhs_, 0xff, 13);
8093 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8094
8095 __ bind(&mod15);
8096 DigitSum(masm, lhs_, 0xf, 4);
8097 __ sub(lhs_, lhs_, Operand(15), LeaveCC, eq);
8098 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8099
8100 __ bind(&mod17);
8101 DigitSum(masm, lhs_, 0xff, 8);
8102 ModGetInRangeBySubtraction(masm, lhs_, 4, 17);
8103 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8104
8105 __ bind(&mod19);
8106 DigitSum(masm, lhs_, r5, 0xff, 8, 5);
8107 ModReduce(masm, lhs_, 0xff, 19);
8108 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8109
8110 __ bind(&mod21);
8111 DigitSum(masm, lhs_, 0x3f, 6);
8112 ModReduce(masm, lhs_, 0x3f, 21);
8113 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8114
8115 __ bind(&mod23);
8116 DigitSum(masm, lhs_, r5, 0xff, 8, 7);
8117 ModReduce(masm, lhs_, 0xff, 23);
8118 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8119
8120 __ bind(&mod25);
8121 DigitSum(masm, lhs_, r5, 0x7f, 7, 6);
8122 ModReduce(masm, lhs_, 0x7f, 25);
8123 ModAnswer(masm, result_, shift_distance_, mask_bits_, lhs_);
8124 }
8125
8126
7945 const char* GenericBinaryOpStub::GetName() { 8127 const char* GenericBinaryOpStub::GetName() {
7946 if (name_ != NULL) return name_; 8128 if (name_ != NULL) return name_;
7947 const int len = 100; 8129 const int len = 100;
7948 name_ = Bootstrapper::AllocateAutoDeletedArray(len); 8130 name_ = Bootstrapper::AllocateAutoDeletedArray(len);
7949 if (name_ == NULL) return "OOM"; 8131 if (name_ == NULL) return "OOM";
7950 const char* op_name = Token::Name(op_); 8132 const char* op_name = Token::Name(op_);
7951 const char* overwrite_name; 8133 const char* overwrite_name;
7952 switch (mode_) { 8134 switch (mode_) {
7953 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 8135 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
7954 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 8136 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
8062 __ bind(&slow); 8244 __ bind(&slow);
8063 } 8245 }
8064 HandleBinaryOpSlowCases(masm, &not_smi, lhs, rhs, Builtins::MUL); 8246 HandleBinaryOpSlowCases(masm, &not_smi, lhs, rhs, Builtins::MUL);
8065 break; 8247 break;
8066 } 8248 }
8067 8249
8068 case Token::DIV: 8250 case Token::DIV:
8069 case Token::MOD: { 8251 case Token::MOD: {
8070 Label not_smi; 8252 Label not_smi;
8071 if (ShouldGenerateSmiCode() && specialized_on_rhs_) { 8253 if (ShouldGenerateSmiCode() && specialized_on_rhs_) {
8072 Label smi_is_unsuitable; 8254 Label lhs_is_unsuitable;
8073 __ BranchOnNotSmi(lhs, &not_smi); 8255 __ BranchOnNotSmi(lhs, &not_smi);
8074 if (IsPowerOf2(constant_rhs_)) { 8256 if (IsPowerOf2(constant_rhs_)) {
8075 if (op_ == Token::MOD) { 8257 if (op_ == Token::MOD) {
8076 __ and_(rhs, 8258 __ and_(rhs,
8077 lhs, 8259 lhs,
8078 Operand(0x80000000u | ((constant_rhs_ << kSmiTagSize) - 1)), 8260 Operand(0x80000000u | ((constant_rhs_ << kSmiTagSize) - 1)),
8079 SetCC); 8261 SetCC);
8080 // We now have the answer, but if the input was negative we also 8262 // We now have the answer, but if the input was negative we also
8081 // have the sign bit. Our work is done if the result is 8263 // have the sign bit. Our work is done if the result is
8082 // positive or zero: 8264 // positive or zero:
8083 if (!rhs.is(r0)) { 8265 if (!rhs.is(r0)) {
8084 __ mov(r0, rhs, LeaveCC, pl); 8266 __ mov(r0, rhs, LeaveCC, pl);
8085 } 8267 }
8086 __ Ret(pl); 8268 __ Ret(pl);
8087 // A mod of a negative left hand side must return a negative number. 8269 // A mod of a negative left hand side must return a negative number.
8088 // Unfortunately if the answer is 0 then we must return -0. And we 8270 // Unfortunately if the answer is 0 then we must return -0. And we
8089 // already optimistically trashed rhs so we may need to restore it. 8271 // already optimistically trashed rhs so we may need to restore it.
8090 __ eor(rhs, rhs, Operand(0x80000000u), SetCC); 8272 __ eor(rhs, rhs, Operand(0x80000000u), SetCC);
8091 // Next two instructions are conditional on the answer being -0. 8273 // Next two instructions are conditional on the answer being -0.
8092 __ mov(rhs, Operand(Smi::FromInt(constant_rhs_)), LeaveCC, eq); 8274 __ mov(rhs, Operand(Smi::FromInt(constant_rhs_)), LeaveCC, eq);
8093 __ b(eq, &smi_is_unsuitable); 8275 __ b(eq, &lhs_is_unsuitable);
8094 // We need to subtract the dividend. Eg. -3 % 4 == -3. 8276 // We need to subtract the dividend. Eg. -3 % 4 == -3.
8095 __ sub(result, rhs, Operand(Smi::FromInt(constant_rhs_))); 8277 __ sub(result, rhs, Operand(Smi::FromInt(constant_rhs_)));
8096 } else { 8278 } else {
8097 ASSERT(op_ == Token::DIV); 8279 ASSERT(op_ == Token::DIV);
8098 __ tst(lhs, 8280 __ tst(lhs,
8099 Operand(0x80000000u | ((constant_rhs_ << kSmiTagSize) - 1))); 8281 Operand(0x80000000u | ((constant_rhs_ << kSmiTagSize) - 1)));
8100 __ b(ne, &smi_is_unsuitable); // Go slow on negative or remainder. 8282 __ b(ne, &lhs_is_unsuitable); // Go slow on negative or remainder.
8101 int shift = 0; 8283 int shift = 0;
8102 int d = constant_rhs_; 8284 int d = constant_rhs_;
8103 while ((d & 1) == 0) { 8285 while ((d & 1) == 0) {
8104 d >>= 1; 8286 d >>= 1;
8105 shift++; 8287 shift++;
8106 } 8288 }
8107 __ mov(r0, Operand(lhs, LSR, shift)); 8289 __ mov(r0, Operand(lhs, LSR, shift));
8108 __ bic(r0, r0, Operand(kSmiTagMask)); 8290 __ bic(r0, r0, Operand(kSmiTagMask));
8109 } 8291 }
8110 } else { 8292 } else {
8111 // Not a power of 2. 8293 // Not a power of 2.
8112 __ tst(lhs, Operand(0x80000000u)); 8294 __ tst(lhs, Operand(0x80000000u));
8113 __ b(ne, &smi_is_unsuitable); 8295 __ b(ne, &lhs_is_unsuitable);
8114 // Find a fixed point reciprocal of the divisor so we can divide by 8296 // Find a fixed point reciprocal of the divisor so we can divide by
8115 // multiplying. 8297 // multiplying.
8116 double divisor = 1.0 / constant_rhs_; 8298 double divisor = 1.0 / constant_rhs_;
8117 int shift = 32; 8299 int shift = 32;
8118 double scale = 4294967296.0; // 1 << 32. 8300 double scale = 4294967296.0; // 1 << 32.
8119 uint32_t mul; 8301 uint32_t mul;
8120 // Maximise the precision of the fixed point reciprocal. 8302 // Maximise the precision of the fixed point reciprocal.
8121 while (true) { 8303 while (true) {
8122 mul = static_cast<uint32_t>(scale * divisor); 8304 mul = static_cast<uint32_t>(scale * divisor);
8123 if (mul >= 0x7fffffff) break; 8305 if (mul >= 0x7fffffff) break;
(...skipping 14 matching lines...) Expand all
8138 MultiplyByKnownInt2(masm, 8320 MultiplyByKnownInt2(masm,
8139 scratch, 8321 scratch,
8140 scratch2, 8322 scratch2,
8141 rhs, 8323 rhs,
8142 constant_rhs_, 8324 constant_rhs_,
8143 &required_scratch_shift); 8325 &required_scratch_shift);
8144 // scratch << required_scratch_shift is now the Smi tagged rhs * 8326 // scratch << required_scratch_shift is now the Smi tagged rhs *
8145 // (lhs / rhs) where / indicates integer division. 8327 // (lhs / rhs) where / indicates integer division.
8146 if (op_ == Token::DIV) { 8328 if (op_ == Token::DIV) {
8147 __ cmp(lhs, Operand(scratch, LSL, required_scratch_shift)); 8329 __ cmp(lhs, Operand(scratch, LSL, required_scratch_shift));
8148 __ b(ne, &smi_is_unsuitable); // There was a remainder. 8330 __ b(ne, &lhs_is_unsuitable); // There was a remainder.
8149 __ mov(result, Operand(scratch2, LSL, kSmiTagSize)); 8331 __ mov(result, Operand(scratch2, LSL, kSmiTagSize));
8150 } else { 8332 } else {
8151 ASSERT(op_ == Token::MOD); 8333 ASSERT(op_ == Token::MOD);
8152 __ sub(result, lhs, Operand(scratch, LSL, required_scratch_shift)); 8334 __ sub(result, lhs, Operand(scratch, LSL, required_scratch_shift));
8153 } 8335 }
8154 } 8336 }
8155 __ Ret(); 8337 __ Ret();
8156 __ bind(&smi_is_unsuitable); 8338 __ bind(&lhs_is_unsuitable);
8157 } else if (op_ == Token::MOD && 8339 } else if (op_ == Token::MOD &&
8158 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS && 8340 runtime_operands_type_ != BinaryOpIC::HEAP_NUMBERS &&
8159 runtime_operands_type_ != BinaryOpIC::STRINGS) { 8341 runtime_operands_type_ != BinaryOpIC::STRINGS) {
8160 // Do generate a bit of smi code for modulus even though the default for 8342 // Do generate a bit of smi code for modulus even though the default for
8161 // modulus is not to do it, but as the ARM processor has no coprocessor 8343 // modulus is not to do it, but as the ARM processor has no coprocessor
8162 // support for modulus checking for smis makes sense. 8344 // support for modulus checking for smis makes sense. We can handle
8345 // 1 to 25 times any power of 2. This covers over half the numbers from
8346 // 1 to 100 including all of the first 25. (Actually the constants < 10
8347 // are handled above by reciprocal multiplication. We only get here for
8348 // those cases if the right hand side is not a constant or for cases
8349 // like 192 which is 3*2^6 and ends up in the 3 case in the integer mod
8350 // stub.)
8163 Label slow; 8351 Label slow;
8352 Label not_power_of_2;
8164 ASSERT(!ShouldGenerateSmiCode()); 8353 ASSERT(!ShouldGenerateSmiCode());
8165 ASSERT(kSmiTag == 0); // Adjust code below. 8354 ASSERT(kSmiTag == 0); // Adjust code below.
8166 // Check for two positive smis. 8355 // Check for two positive smis.
8167 __ orr(smi_test_reg, lhs, Operand(rhs)); 8356 __ orr(smi_test_reg, lhs, Operand(rhs));
8168 __ tst(smi_test_reg, Operand(0x80000000u | kSmiTagMask)); 8357 __ tst(smi_test_reg, Operand(0x80000000u | kSmiTagMask));
8169 __ b(ne, &slow); 8358 __ b(ne, &slow);
8170 // Check that rhs is a power of two and not zero. 8359 // Check that rhs is a power of two and not zero.
8360 Register mask_bits = r3;
8171 __ sub(scratch, rhs, Operand(1), SetCC); 8361 __ sub(scratch, rhs, Operand(1), SetCC);
8172 __ b(mi, &slow); 8362 __ b(mi, &slow);
8173 __ tst(rhs, scratch); 8363 __ and_(mask_bits, rhs, Operand(scratch), SetCC);
8174 __ b(ne, &slow); 8364 __ b(ne, &not_power_of_2);
8175 // Calculate power of two modulus. 8365 // Calculate power of two modulus.
8176 __ and_(result, lhs, Operand(scratch)); 8366 __ and_(result, lhs, Operand(scratch));
8177 __ Ret(); 8367 __ Ret();
8368
8369 __ bind(&not_power_of_2);
8370 __ eor(scratch, scratch, Operand(mask_bits));
8371 // At least two bits are set in the modulus. The high one(s) are in
8372 // mask_bits and the low one is scratch + 1.
8373 __ and_(mask_bits, scratch, Operand(lhs));
8374 Register shift_distance = scratch;
8375 scratch = no_reg;
8376
8377 // The rhs consists of a power of 2 multiplied by some odd number.
8378 // The power-of-2 part we handle by putting the corresponding bits
8379 // from the lhs in the mask_bits register, and the power in the
8380 // shift_distance register. Shift distance is never 0 due to Smi
8381 // tagging.
8382 __ CountLeadingZeros(r4, shift_distance, shift_distance);
8383 __ rsb(shift_distance, r4, Operand(32));
8384
8385 // Now we need to find out what the odd number is. The last bit is
8386 // always 1.
8387 Register odd_number = r4;
8388 __ mov(odd_number, Operand(rhs, LSR, shift_distance));
8389 __ cmp(odd_number, Operand(25));
8390 __ b(gt, &slow);
8391
8392 IntegerModStub stub(
8393 result, shift_distance, odd_number, mask_bits, lhs, r5);
8394 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); // Tail call.
8395
8178 __ bind(&slow); 8396 __ bind(&slow);
8179 } 8397 }
8180 HandleBinaryOpSlowCases( 8398 HandleBinaryOpSlowCases(
8181 masm, 8399 masm,
8182 &not_smi, 8400 &not_smi,
8183 lhs, 8401 lhs,
8184 rhs, 8402 rhs,
8185 op_ == Token::MOD ? Builtins::MOD : Builtins::DIV); 8403 op_ == Token::MOD ? Builtins::MOD : Builtins::DIV);
8186 break; 8404 break;
8187 } 8405 }
(...skipping 2517 matching lines...) Expand 10 before | Expand all | Expand 10 after
10705 __ bind(&string_add_runtime); 10923 __ bind(&string_add_runtime);
10706 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 10924 __ TailCallRuntime(Runtime::kStringAdd, 2, 1);
10707 } 10925 }
10708 10926
10709 10927
10710 #undef __ 10928 #undef __
10711 10929
10712 } } // namespace v8::internal 10930 } } // namespace v8::internal
10713 10931
10714 #endif // V8_TARGET_ARCH_ARM 10932 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/ic-arm.cc » ('j') | test/mjsunit/mod.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698