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

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

Issue 506052: Optimize bitops with non-Smi inputs. Instead of converting both inputs... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 11 years 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/codegen.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 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 736 matching lines...) Expand 10 before | Expand all | Expand 10 after
747 // be either smi or heap number objects (fp values). Requirements: 747 // be either smi or heap number objects (fp values). Requirements:
748 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as 748 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as
749 // floating point numbers on FPU stack. 749 // floating point numbers on FPU stack.
750 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); 750 static void LoadFloatOperands(MacroAssembler* masm, Register scratch);
751 // Test if operands are smi or number objects (fp). Requirements: 751 // Test if operands are smi or number objects (fp). Requirements:
752 // operand_1 in eax, operand_2 in edx; falls through on float 752 // operand_1 in eax, operand_2 in edx; falls through on float
753 // operands, jumps to the non_float label otherwise. 753 // operands, jumps to the non_float label otherwise.
754 static void CheckFloatOperands(MacroAssembler* masm, 754 static void CheckFloatOperands(MacroAssembler* masm,
755 Label* non_float, 755 Label* non_float,
756 Register scratch); 756 Register scratch);
757 // Takes the operands in edx and eax and loads them as integers in eax
758 // and ecx.
759 static void LoadAsIntegers(MacroAssembler* masm,
760 Label* operand_conversion_failure);
757 // Test if operands are numbers (smi or HeapNumber objects), and load 761 // Test if operands are numbers (smi or HeapNumber objects), and load
758 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 762 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if
759 // either operand is not a number. Operands are in edx and eax. 763 // either operand is not a number. Operands are in edx and eax.
760 // Leaves operands unchanged. 764 // Leaves operands unchanged.
761 static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); 765 static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers);
762 }; 766 };
763 767
764 768
765 const char* GenericBinaryOpStub::GetName() { 769 const char* GenericBinaryOpStub::GetName() {
766 if (name_ != NULL) return name_; 770 if (name_ != NULL) return name_;
767 const int len = 100; 771 const int kMaxNameLength = 100;
768 name_ = Bootstrapper::AllocateAutoDeletedArray(len); 772 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength);
769 if (name_ == NULL) return "OOM"; 773 if (name_ == NULL) return "OOM";
770 const char* op_name = Token::Name(op_); 774 const char* op_name = Token::Name(op_);
771 const char* overwrite_name; 775 const char* overwrite_name;
772 switch (mode_) { 776 switch (mode_) {
773 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 777 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
774 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 778 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
775 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 779 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
776 default: overwrite_name = "UnknownOverwrite"; break; 780 default: overwrite_name = "UnknownOverwrite"; break;
777 } 781 }
778 782
779 OS::SNPrintF(Vector<char>(name_, len), 783 OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
780 "GenericBinaryOpStub_%s_%s%s_%s%s", 784 "GenericBinaryOpStub_%s_%s%s_%s%s",
781 op_name, 785 op_name,
782 overwrite_name, 786 overwrite_name,
783 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", 787 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
784 args_in_registers_ ? "RegArgs" : "StackArgs", 788 args_in_registers_ ? "RegArgs" : "StackArgs",
785 args_reversed_ ? "_R" : ""); 789 args_reversed_ ? "_R" : "");
786 return name_; 790 return name_;
787 } 791 }
788 792
789 793
(...skipping 6170 matching lines...) Expand 10 before | Expand all | Expand 10 after
6960 case Token::MOD: { 6964 case Token::MOD: {
6961 // For MOD we go directly to runtime in the non-smi case. 6965 // For MOD we go directly to runtime in the non-smi case.
6962 break; 6966 break;
6963 } 6967 }
6964 case Token::BIT_OR: 6968 case Token::BIT_OR:
6965 case Token::BIT_AND: 6969 case Token::BIT_AND:
6966 case Token::BIT_XOR: 6970 case Token::BIT_XOR:
6967 case Token::SAR: 6971 case Token::SAR:
6968 case Token::SHL: 6972 case Token::SHL:
6969 case Token::SHR: { 6973 case Token::SHR: {
6970 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); 6974 Label non_smi_result, skip_allocation;
6971 FloatingPointHelper::LoadFloatOperands(masm, ecx); 6975 Label operand_conversion_failure;
6972 6976 FloatingPointHelper::LoadAsIntegers(
6973 Label skip_allocation, non_smi_result, operand_conversion_failure; 6977 masm,
6974 6978 &operand_conversion_failure);
6975 // Reserve space for converted numbers.
6976 __ sub(Operand(esp), Immediate(2 * kPointerSize));
6977
6978 if (use_sse3_) {
6979 // Truncate the operands to 32-bit integers and check for
6980 // exceptions in doing so.
6981 CpuFeatures::Scope scope(SSE3);
6982 __ fisttp_s(Operand(esp, 0 * kPointerSize));
6983 __ fisttp_s(Operand(esp, 1 * kPointerSize));
6984 __ fnstsw_ax();
6985 __ test(eax, Immediate(1));
6986 __ j(not_zero, &operand_conversion_failure);
6987 } else {
6988 // Check if right operand is int32.
6989 __ fist_s(Operand(esp, 0 * kPointerSize));
6990 __ fild_s(Operand(esp, 0 * kPointerSize));
6991 __ FCmp();
6992 __ j(not_zero, &operand_conversion_failure);
6993 __ j(parity_even, &operand_conversion_failure);
6994
6995 // Check if left operand is int32.
6996 __ fist_s(Operand(esp, 1 * kPointerSize));
6997 __ fild_s(Operand(esp, 1 * kPointerSize));
6998 __ FCmp();
6999 __ j(not_zero, &operand_conversion_failure);
7000 __ j(parity_even, &operand_conversion_failure);
7001 }
7002
7003 // Get int32 operands and perform bitop.
7004 __ pop(ecx);
7005 __ pop(eax);
7006 switch (op_) { 6979 switch (op_) {
7007 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; 6980 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break;
7008 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; 6981 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
7009 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; 6982 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break;
7010 case Token::SAR: __ sar_cl(eax); break; 6983 case Token::SAR: __ sar_cl(eax); break;
7011 case Token::SHL: __ shl_cl(eax); break; 6984 case Token::SHL: __ shl_cl(eax); break;
7012 case Token::SHR: __ shr_cl(eax); break; 6985 case Token::SHR: __ shr_cl(eax); break;
7013 default: UNREACHABLE(); 6986 default: UNREACHABLE();
7014 } 6987 }
7015 if (op_ == Token::SHR) { 6988 if (op_ == Token::SHR) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
7047 break; 7020 break;
7048 default: UNREACHABLE(); 7021 default: UNREACHABLE();
7049 } 7022 }
7050 // Store the result in the HeapNumber and return. 7023 // Store the result in the HeapNumber and return.
7051 __ mov(Operand(esp, 1 * kPointerSize), ebx); 7024 __ mov(Operand(esp, 1 * kPointerSize), ebx);
7052 __ fild_s(Operand(esp, 1 * kPointerSize)); 7025 __ fild_s(Operand(esp, 1 * kPointerSize));
7053 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 7026 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
7054 GenerateReturn(masm); 7027 GenerateReturn(masm);
7055 } 7028 }
7056 7029
7057 // Clear the FPU exception flag and reset the stack before calling 7030 // Go to runtime for non-number inputs.
7058 // the runtime system.
7059 __ bind(&operand_conversion_failure); 7031 __ bind(&operand_conversion_failure);
7060 __ add(Operand(esp), Immediate(2 * kPointerSize));
7061 if (use_sse3_) {
7062 // If we've used the SSE3 instructions for truncating the
7063 // floating point values to integers and it failed, we have a
7064 // pending #IA exception. Clear it.
7065 __ fnclex();
7066 } else {
7067 // The non-SSE3 variant does early bailout if the right
7068 // operand isn't a 32-bit integer, so we may have a single
7069 // value on the FPU stack we need to get rid of.
7070 __ ffree(0);
7071 }
7072
7073 // SHR should return uint32 - go to runtime for non-smi/negative result. 7032 // SHR should return uint32 - go to runtime for non-smi/negative result.
7074 if (op_ == Token::SHR) { 7033 if (op_ == Token::SHR) {
7075 __ bind(&non_smi_result); 7034 __ bind(&non_smi_result);
7076 } 7035 }
7077 __ mov(eax, Operand(esp, 1 * kPointerSize)); 7036 __ mov(eax, Operand(esp, 1 * kPointerSize));
7078 __ mov(edx, Operand(esp, 2 * kPointerSize)); 7037 __ mov(edx, Operand(esp, 2 * kPointerSize));
7079 break; 7038 break;
7080 } 7039 }
7081 default: UNREACHABLE(); break; 7040 default: UNREACHABLE(); break;
7082 } 7041 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
7186 // If arguments are not passed in registers remove them from the stack before 7145 // If arguments are not passed in registers remove them from the stack before
7187 // returning. 7146 // returning.
7188 if (!HasArgumentsInRegisters()) { 7147 if (!HasArgumentsInRegisters()) {
7189 __ ret(2 * kPointerSize); // Remove both operands 7148 __ ret(2 * kPointerSize); // Remove both operands
7190 } else { 7149 } else {
7191 __ ret(0); 7150 __ ret(0);
7192 } 7151 }
7193 } 7152 }
7194 7153
7195 7154
7155 // Get the integer part of a heap number. Surprisingly, all this bit twiddling
7156 // is faster than using the built-in instructions on floating point registers.
7157 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the
7158 // trashed registers.
7159 void IntegerConvert(MacroAssembler* masm,
7160 Register source,
7161 Label* conversion_failure) {
7162 Label done, right_exponent, normal_exponent;
7163 Register scratch = ebx;
7164 Register scratch2 = edi;
7165 // Get exponent word.
7166 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset));
7167 // Get exponent alone in scratch2.
7168 __ mov(scratch2, scratch);
7169 __ and_(scratch2, HeapNumber::kExponentMask);
7170 // Load ecx with zero. We use this either for the final shift or
7171 // for the answer.
7172 __ mov(ecx, Immediate(0));
Lasse Reichstein 2009/12/17 16:35:50 Use xor to zero.
7173 // Check whether the exponent matches a 32 bit signed int that is not a Smi.
Lasse Reichstein 2009/12/17 16:35:50 "is not a Smi" -> "cannot be represented as a smi"
7174 // A non-Smi integer is 1.xxx * 2^30 so the exponent is 30 (biased). This is
Lasse Reichstein 2009/12/17 16:35:50 "A non-smi 32-bit integer is ..."
7175 // the exponent that we are fastest at and also the highest exponent we can
7176 // handle here.
7177 const uint32_t non_smi_exponent =
7178 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
7179 __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
7180 // If we have a match of the int32-but-not-Smi exponent then skip some logic.
7181 __ j(equal, &right_exponent);
7182 // If the exponent is higher than that then go to slow case. This catches
7183 // numbers that don't fit in a signed int32, infinities and NaNs.
7184 __ j(less, &normal_exponent);
7185
7186 // Handle a big exponent. The only reason we have this code is that the >>>
7187 // operator has a tendency to generate numbers with an exponent of 31.
7188 const uint32_t big_non_smi_exponent =
7189 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
7190 __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
7191 __ j(not_equal, conversion_failure);
7192 // We have the big exponent from >>>.
Lasse Reichstein 2009/12/17 16:35:50 ... or from some other operation that gives a resu
7193 // Get the top bits of the mantissa.
7194 __ mov(scratch2, scratch);
7195 __ and_(scratch2, HeapNumber::kMantissaMask);
7196 // Put back the implicit 1.
7197 __ or_(scratch2, 1 << HeapNumber::kExponentShift);
7198 // Shift up the mantissa bits to take up the space the exponent used to
7199 // take. We just orred in the implicit bit so that took care of one and
7200 // we want to use the full unsigned range so we subtract 1 bit from the shift
7201 // distance.
Lasse Reichstein 2009/12/17 16:35:50 Change last sentence to (something like): We have
7202 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1;
7203 __ shl(scratch2, big_shift_distance);
7204 // Get the second half of the double.
7205 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
7206 // Shift down 21 bits to get the last 11 bits.
Lasse Reichstein 2009/12/17 16:35:50 Explain, or replace, the constants: 21 = big_shi
7207 __ shr(ecx, 32 - big_shift_distance);
7208 __ or_(ecx, Operand(scratch2));
7209 // We have the answer in ecx, but we may need to negate it.
7210 __ mov(scratch2, Immediate(0));
7211 __ cmp(scratch2, Operand(scratch));
7212 __ j(less_equal, &done);
7213 __ neg(ecx);
Lasse Reichstein 2009/12/17 16:35:50 Slightly shorter: test(scratch, scratch) j(positiv
7214 __ jmp(&done);
7215
7216 // End of handling for big exponent.
Lasse Reichstein 2009/12/17 16:35:50 You could wrap the entire big-exponent section in
7217 __ bind(&normal_exponent);
7218 // Exponent word in scratch, exponent part of exponent word in scratch2.
7219 // Zero in ecx.
7220 // We know the exponent is smaller than 30 (biased). If it is less than
7221 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
7222 // it rounds to zero.
7223 const uint32_t zero_exponent =
7224 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
Lasse Reichstein 2009/12/17 16:35:50 I think (0 + HeapNumber::kExponentBias) is more re
7225 __ sub(Operand(scratch2), Immediate(zero_exponent));
7226 // ecx already has a Smi zero.
7227 __ j(less, &done);
7228
7229 // We have a shifted exponent between 0 and 30 in scratch2.
7230 __ shr(scratch2, HeapNumber::kExponentShift);
7231 __ mov(ecx, Immediate(30));
7232 __ sub(ecx, Operand(scratch2));
Lasse Reichstein 2009/12/17 16:35:50 Complex rewrite: If you make ecx one larger here (
Erik Corry 2009/12/18 09:33:36 Nice idea, but it ruins the fast case for zero shi
7233
7234 __ bind(&right_exponent);
7235 // Here ecx is the shift, scratch is the exponent word.
7236 // Get the top bits of the mantissa.
7237 __ and_(scratch, HeapNumber::kMantissaMask);
7238 // Put back the implicit 1.
7239 __ or_(scratch, 1 << HeapNumber::kExponentShift);
7240 // Shift up the mantissa bits to take up the space the exponent used to
7241 // take. We just orred in the implicit bit so that took care of one and
7242 // we want to leave the sign bit 0 so we subtract 2 bits from the shift
Lasse Reichstein 2009/12/17 16:35:50 "leave the sign bit 0" -> "leave a zero sign bit"
7243 // distance.
7244 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
7245 __ shl(scratch, shift_distance);
7246 // Get the second half of the double. For some exponents we don't
7247 // actually need this because the bits get shifted out again, but
7248 // it's probably slower to test than just to do it.
Lasse Reichstein 2009/12/17 16:35:50 True. The load is probably from the first level ca
7249 __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
7250 // Shift down 22 bits to get the last 10 bits.
Lasse Reichstein 2009/12/17 16:35:50 Explain or replace constants.
7251 __ shr(scratch2, 32 - shift_distance);
7252 __ or_(scratch2, Operand(scratch));
7253 // Move down according to the exponent.
7254 __ shr_cl(scratch2);
7255 // Now the unsigned answer is in scratch2. We need to move it to ecx and
7256 // we may need to fix the sign.
7257 Label negative;
7258 __ mov(ecx, Immediate(0));
7259 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
7260 __ j(greater, &negative);
7261 __ mov(ecx, scratch2);
7262 __ jmp(&done);
7263 __ bind(&negative);
7264 __ sub(ecx, Operand(scratch2));
7265 __ bind(&done);
7266 }
7267
Lasse Reichstein 2009/12/17 16:35:50 Only reviewed until here.
Lasse Reichstein 2009/12/18 08:06:45 But there wasn't much more, I can see now.
7268
7269 // Input: edx, eax are the left and right objects of a bit op.
7270 // Output: eax, ecx are left and right integers for a bit op.
7271 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
7272 Label* conversion_failure) {
7273 // Check float operands.
7274 Label arg1_is_object, arg2_is_object, load_arg2;
7275 Label done;
7276
7277 __ test(edx, Immediate(kSmiTagMask));
7278 __ j(not_zero, &arg1_is_object);
7279 __ sar(edx, kSmiTagSize);
7280 __ jmp(&load_arg2);
7281
7282 __ bind(&arg1_is_object);
7283 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
7284 __ cmp(ebx, Factory::heap_number_map());
7285 __ j(not_equal, conversion_failure);
7286 // Get the untagged integer version of the edx heap number in ecx.
7287 IntegerConvert(masm, edx, conversion_failure);
7288 __ mov(edx, ecx);
7289
7290 // Here edx has the untagged integer, eax has a Smi or a heap number.
7291 __ bind(&load_arg2);
7292 // Test if arg2 is a Smi.
7293 __ test(eax, Immediate(kSmiTagMask));
7294 __ j(not_zero, &arg2_is_object);
7295 __ sar(eax, kSmiTagSize);
7296 __ mov(ecx, eax);
7297 __ jmp(&done);
7298
7299 __ bind(&arg2_is_object);
7300 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
7301 __ cmp(ebx, Factory::heap_number_map());
7302 __ j(not_equal, conversion_failure);
7303 // Get the untagged integer version of the eax heap number in ecx.
7304 IntegerConvert(masm, eax, conversion_failure);
7305 __ bind(&done);
7306 __ mov(eax, edx);
7307 }
7308
7309
7196 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 7310 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
7197 Register number) { 7311 Register number) {
7198 Label load_smi, done; 7312 Label load_smi, done;
7199 7313
7200 __ test(number, Immediate(kSmiTagMask)); 7314 __ test(number, Immediate(kSmiTagMask));
7201 __ j(zero, &load_smi, not_taken); 7315 __ j(zero, &load_smi, not_taken);
7202 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 7316 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset));
7203 __ jmp(&done); 7317 __ jmp(&done);
7204 7318
7205 __ bind(&load_smi); 7319 __ bind(&load_smi);
(...skipping 1252 matching lines...) Expand 10 before | Expand all | Expand 10 after
8458 __ add(Operand(dest), Immediate(2)); 8572 __ add(Operand(dest), Immediate(2));
8459 } 8573 }
8460 __ sub(Operand(count), Immediate(1)); 8574 __ sub(Operand(count), Immediate(1));
8461 __ j(not_zero, &loop); 8575 __ j(not_zero, &loop);
8462 } 8576 }
8463 8577
8464 8578
8465 #undef __ 8579 #undef __
8466 8580
8467 } } // namespace v8::internal 8581 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698