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

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

Issue 2862004: Avoid redundant smi check in x64 loading of floats into SSE2 registers. (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
« no previous file with comments | « no previous file | 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 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 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 Token::Value op_; 255 Token::Value op_;
256 Register dst_; 256 Register dst_;
257 Smi* value_; 257 Smi* value_;
258 Register src_; 258 Register src_;
259 OverwriteMode overwrite_mode_; 259 OverwriteMode overwrite_mode_;
260 }; 260 };
261 261
262 262
263 class FloatingPointHelper : public AllStatic { 263 class FloatingPointHelper : public AllStatic {
264 public: 264 public:
265 // Code pattern for loading a floating point value. Input value must 265 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
266 // be either a smi or a heap number object (fp value). Requirements: 266 // If the operands are not both numbers, jump to not_numbers.
267 // operand on TOS+1. Returns operand as floating point number on FPU 267 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis.
268 // stack. 268 // NumberOperands assumes both are smis or heap numbers.
269 static void LoadFloatOperand(MacroAssembler* masm, Register scratch); 269 static void LoadSSE2SmiOperands(MacroAssembler* masm);
270 270 static void LoadSSE2NumberOperands(MacroAssembler* masm);
271 // Code pattern for loading a floating point value. Input value must 271 static void LoadSSE2UnknownOperands(MacroAssembler* masm,
272 // be either a smi or a heap number object (fp value). Requirements: 272 Label* not_numbers);
273 // operand in src register. Returns operand as floating point number
274 // in XMM register. May destroy src register.
275 static void LoadFloatOperand(MacroAssembler* masm,
276 Register src,
277 XMMRegister dst);
278
279 // Code pattern for loading a possible number into a XMM register.
280 // If the contents of src is not a number, control branches to
281 // the Label not_number. If contents of src is a smi or a heap number
282 // object (fp value), it is loaded into the XMM register as a double.
283 // The register src is not changed, and src may not be kScratchRegister.
284 static void LoadFloatOperand(MacroAssembler* masm,
285 Register src,
286 XMMRegister dst,
287 Label *not_number);
288
289 // Code pattern for loading floating point values. Input values must
290 // be either smi or heap number objects (fp values). Requirements:
291 // operand_1 in rdx, operand_2 in rax; Returns operands as
292 // floating point numbers in XMM registers.
293 static void LoadFloatOperands(MacroAssembler* masm,
294 XMMRegister dst1,
295 XMMRegister dst2);
296
297 // Similar to LoadFloatOperands, assumes that the operands are smis.
298 static void LoadFloatOperandsFromSmis(MacroAssembler* masm,
299 XMMRegister dst1,
300 XMMRegister dst2);
301
302 // Code pattern for loading floating point values onto the fp stack.
303 // Input values must be either smi or heap number objects (fp values).
304 // Requirements:
305 // Register version: operands in registers lhs and rhs.
306 // Stack version: operands on TOS+1 and TOS+2.
307 // Returns operands as floating point numbers on fp stack.
308 static void LoadFloatOperands(MacroAssembler* masm,
309 Register lhs,
310 Register rhs);
311
312 // Test if operands are smi or number objects (fp). Requirements:
313 // operand_1 in rax, operand_2 in rdx; falls through on float or smi
314 // operands, jumps to the non_float label otherwise.
315 static void CheckNumberOperands(MacroAssembler* masm,
316 Label* non_float);
317 // As CheckNumberOperands above, but expects the HeapNumber map in
318 // a register.
319 static void CheckNumberOperands(MacroAssembler* masm,
320 Label* non_float,
321 Register heap_number_map);
322 273
323 // Takes the operands in rdx and rax and loads them as integers in rax 274 // Takes the operands in rdx and rax and loads them as integers in rax
324 // and rcx. 275 // and rcx.
325 static void LoadAsIntegers(MacroAssembler* masm, 276 static void LoadAsIntegers(MacroAssembler* masm,
326 Label* operand_conversion_failure, 277 Label* operand_conversion_failure);
327 Register heap_number_map);
328 }; 278 };
329 279
330 280
331 // ----------------------------------------------------------------------------- 281 // -----------------------------------------------------------------------------
332 // CodeGenerator implementation. 282 // CodeGenerator implementation.
333 283
334 CodeGenerator::CodeGenerator(MacroAssembler* masm) 284 CodeGenerator::CodeGenerator(MacroAssembler* masm)
335 : deferred_(8), 285 : deferred_(8),
336 masm_(masm), 286 masm_(masm),
337 info_(NULL), 287 info_(NULL),
(...skipping 8767 matching lines...) Expand 10 before | Expand all | Expand 10 after
9105 // Push arguments below the return address to prepare jump to builtin. 9055 // Push arguments below the return address to prepare jump to builtin.
9106 __ pop(rcx); 9056 __ pop(rcx);
9107 __ push(rax); 9057 __ push(rax);
9108 __ push(rdx); 9058 __ push(rdx);
9109 __ push(rcx); 9059 __ push(rcx);
9110 9060
9111 // Generate the number comparison code. 9061 // Generate the number comparison code.
9112 if (include_number_compare_) { 9062 if (include_number_compare_) {
9113 Label non_number_comparison; 9063 Label non_number_comparison;
9114 Label unordered; 9064 Label unordered;
9115 FloatingPointHelper::LoadFloatOperand(masm, rdx, xmm0, 9065 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &non_number_comparison);
9116 &non_number_comparison);
9117 FloatingPointHelper::LoadFloatOperand(masm, rax, xmm1,
9118 &non_number_comparison);
9119
9120 __ ucomisd(xmm0, xmm1); 9066 __ ucomisd(xmm0, xmm1);
9121 9067
9122 // Don't base result on EFLAGS when a NaN is involved. 9068 // Don't base result on EFLAGS when a NaN is involved.
9123 __ j(parity_even, &unordered); 9069 __ j(parity_even, &unordered);
9124 // Return a result of -1, 0, or 1, based on EFLAGS. 9070 // Return a result of -1, 0, or 1, based on EFLAGS.
9125 __ movq(rax, Immediate(0)); // equal 9071 __ movq(rax, Immediate(0)); // equal
9126 __ movq(rcx, Immediate(1)); 9072 __ movq(rcx, Immediate(1));
9127 __ cmovq(above, rax, rcx); 9073 __ cmovq(above, rax, rcx);
9128 __ movq(rcx, Immediate(-1)); 9074 __ movq(rcx, Immediate(-1));
9129 __ cmovq(below, rax, rcx); 9075 __ cmovq(below, rax, rcx);
(...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after
9966 // temporarily store that in a register. 9912 // temporarily store that in a register.
9967 __ pop(rax); 9913 __ pop(rax);
9968 __ Push(Smi::FromInt(0)); 9914 __ Push(Smi::FromInt(0));
9969 __ push(rax); 9915 __ push(rax);
9970 9916
9971 // Do tail-call to runtime routine. 9917 // Do tail-call to runtime routine.
9972 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); 9918 __ TailCallRuntime(Runtime::kStackGuard, 1, 1);
9973 } 9919 }
9974 9920
9975 9921
9976 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 9922 void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) {
9977 Register number) { 9923 __ SmiToInteger32(kScratchRegister, rdx);
9978 Label load_smi, done; 9924 __ cvtlsi2sd(xmm0, kScratchRegister);
9925 __ SmiToInteger32(kScratchRegister, rax);
9926 __ cvtlsi2sd(xmm1, kScratchRegister);
9927 }
9979 9928
9980 __ JumpIfSmi(number, &load_smi); 9929
9981 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 9930 void FloatingPointHelper::LoadSSE2NumberOperands(MacroAssembler* masm) {
9931 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, done;
9932 // Load operand in rdx into xmm0.
9933 __ JumpIfSmi(rdx, &load_smi_rdx);
9934 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
9935 // Load operand in rax into xmm1.
9936 __ JumpIfSmi(rax, &load_smi_rax);
9937 __ bind(&load_nonsmi_rax);
9938 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
9982 __ jmp(&done); 9939 __ jmp(&done);
9983 9940
9984 __ bind(&load_smi); 9941 __ bind(&load_smi_rdx);
9985 __ SmiToInteger32(number, number); 9942 __ SmiToInteger32(kScratchRegister, rdx);
9986 __ push(number); 9943 __ cvtlsi2sd(xmm0, kScratchRegister);
9987 __ fild_s(Operand(rsp, 0)); 9944 __ JumpIfNotSmi(rax, &load_nonsmi_rax);
9988 __ pop(number); 9945
9946 __ bind(&load_smi_rax);
9947 __ SmiToInteger32(kScratchRegister, rax);
9948 __ cvtlsi2sd(xmm1, kScratchRegister);
9989 9949
9990 __ bind(&done); 9950 __ bind(&done);
9991 } 9951 }
9992 9952
9993 9953
9994 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 9954 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm,
9995 Register src, 9955 Label* not_numbers) {
9996 XMMRegister dst) { 9956 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done;
9997 ASSERT(!src.is(kScratchRegister)); 9957 // Load operand in rdx into xmm0, or branch to not_numbers.
9998 Label load_smi, done; 9958 __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex);
9959 __ JumpIfSmi(rdx, &load_smi_rdx);
9960 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx);
9961 __ j(not_equal, not_numbers); // Argument in rdx is not a number.
9962 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
9963 // Load operand in rax into xmm1, or branch to not_numbers.
9964 __ JumpIfSmi(rax, &load_smi_rax);
9999 9965
10000 __ JumpIfSmi(src, &load_smi); 9966 __ bind(&load_nonsmi_rax);
10001 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset)); 9967 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), rcx);
9968 __ j(not_equal, not_numbers);
9969 __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
10002 __ jmp(&done); 9970 __ jmp(&done);
10003 9971
10004 __ bind(&load_smi); 9972 __ bind(&load_smi_rdx);
10005 __ SmiToInteger32(kScratchRegister, src); 9973 __ SmiToInteger32(kScratchRegister, rdx);
10006 __ cvtlsi2sd(dst, kScratchRegister); 9974 __ cvtlsi2sd(xmm0, kScratchRegister);
9975 __ JumpIfNotSmi(rax, &load_nonsmi_rax);
10007 9976
9977 __ bind(&load_smi_rax);
9978 __ SmiToInteger32(kScratchRegister, rax);
9979 __ cvtlsi2sd(xmm1, kScratchRegister);
10008 __ bind(&done); 9980 __ bind(&done);
10009 } 9981 }
10010 9982
10011 9983
10012 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
10013 Register src,
10014 XMMRegister dst,
10015 Label* not_number) {
10016 Label load_smi, done;
10017 ASSERT(!src.is(kScratchRegister));
10018 __ JumpIfSmi(src, &load_smi);
10019 __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
10020 __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister);
10021 __ j(not_equal, not_number);
10022 __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset));
10023 __ jmp(&done);
10024
10025 __ bind(&load_smi);
10026 __ SmiToInteger32(kScratchRegister, src);
10027 __ cvtlsi2sd(dst, kScratchRegister);
10028
10029 __ bind(&done);
10030 }
10031
10032
10033 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
10034 XMMRegister dst1,
10035 XMMRegister dst2) {
10036 LoadFloatOperand(masm, rdx, dst1);
10037 LoadFloatOperand(masm, rax, dst2);
10038 }
10039
10040
10041 void FloatingPointHelper::LoadFloatOperandsFromSmis(MacroAssembler* masm,
10042 XMMRegister dst1,
10043 XMMRegister dst2) {
10044 __ SmiToInteger32(kScratchRegister, rdx);
10045 __ cvtlsi2sd(dst1, kScratchRegister);
10046 __ SmiToInteger32(kScratchRegister, rax);
10047 __ cvtlsi2sd(dst2, kScratchRegister);
10048 }
10049
10050
10051 // Input: rdx, rax are the left and right objects of a bit op. 9984 // Input: rdx, rax are the left and right objects of a bit op.
10052 // Output: rax, rcx are left and right integers for a bit op. 9985 // Output: rax, rcx are left and right integers for a bit op.
10053 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, 9986 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
10054 Label* conversion_failure, 9987 Label* conversion_failure) {
10055 Register heap_number_map) {
10056 // Check float operands. 9988 // Check float operands.
10057 Label arg1_is_object, check_undefined_arg1; 9989 Label arg1_is_object, check_undefined_arg1;
10058 Label arg2_is_object, check_undefined_arg2; 9990 Label arg2_is_object, check_undefined_arg2;
10059 Label load_arg2, done; 9991 Label load_arg2, done;
10060 9992
10061 __ JumpIfNotSmi(rdx, &arg1_is_object); 9993 __ JumpIfNotSmi(rdx, &arg1_is_object);
10062 __ SmiToInteger32(rdx, rdx); 9994 __ SmiToInteger32(rdx, rdx);
10063 __ jmp(&load_arg2); 9995 __ jmp(&load_arg2);
10064 9996
10065 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 9997 // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
10066 __ bind(&check_undefined_arg1); 9998 __ bind(&check_undefined_arg1);
10067 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); 9999 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
10068 __ j(not_equal, conversion_failure); 10000 __ j(not_equal, conversion_failure);
10069 __ movl(rdx, Immediate(0)); 10001 __ movl(rdx, Immediate(0));
10070 __ jmp(&load_arg2); 10002 __ jmp(&load_arg2);
10071 10003
10072 __ bind(&arg1_is_object); 10004 __ bind(&arg1_is_object);
10073 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); 10005 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
10006 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
10074 __ j(not_equal, &check_undefined_arg1); 10007 __ j(not_equal, &check_undefined_arg1);
10075 // Get the untagged integer version of the edx heap number in rcx. 10008 // Get the untagged integer version of the edx heap number in rcx.
10076 IntegerConvert(masm, rdx, rdx); 10009 IntegerConvert(masm, rdx, rdx);
10077 10010
10078 // Here rdx has the untagged integer, rax has a Smi or a heap number. 10011 // Here rdx has the untagged integer, rax has a Smi or a heap number.
10079 __ bind(&load_arg2); 10012 __ bind(&load_arg2);
10080 // Test if arg2 is a Smi. 10013 // Test if arg2 is a Smi.
10081 __ JumpIfNotSmi(rax, &arg2_is_object); 10014 __ JumpIfNotSmi(rax, &arg2_is_object);
10082 __ SmiToInteger32(rax, rax); 10015 __ SmiToInteger32(rax, rax);
10083 __ movl(rcx, rax); 10016 __ movl(rcx, rax);
10084 __ jmp(&done); 10017 __ jmp(&done);
10085 10018
10086 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 10019 // If the argument is undefined it converts to zero (ECMA-262, section 9.5).
10087 __ bind(&check_undefined_arg2); 10020 __ bind(&check_undefined_arg2);
10088 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); 10021 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
10089 __ j(not_equal, conversion_failure); 10022 __ j(not_equal, conversion_failure);
10090 __ movl(rcx, Immediate(0)); 10023 __ movl(rcx, Immediate(0));
10091 __ jmp(&done); 10024 __ jmp(&done);
10092 10025
10093 __ bind(&arg2_is_object); 10026 __ bind(&arg2_is_object);
10094 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); 10027 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
10028 __ CompareRoot(rbx, Heap::kHeapNumberMapRootIndex);
10095 __ j(not_equal, &check_undefined_arg2); 10029 __ j(not_equal, &check_undefined_arg2);
10096 // Get the untagged integer version of the eax heap number in ecx. 10030 // Get the untagged integer version of the eax heap number in ecx.
10097 IntegerConvert(masm, rcx, rax); 10031 IntegerConvert(masm, rcx, rax);
10098 __ bind(&done); 10032 __ bind(&done);
10099 __ movl(rax, rdx); 10033 __ movl(rax, rdx);
10100 } 10034 }
10101 10035
10102 10036
10103 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
10104 Register lhs,
10105 Register rhs) {
10106 Label load_smi_lhs, load_smi_rhs, done_load_lhs, done;
10107 __ JumpIfSmi(lhs, &load_smi_lhs);
10108 __ fld_d(FieldOperand(lhs, HeapNumber::kValueOffset));
10109 __ bind(&done_load_lhs);
10110
10111 __ JumpIfSmi(rhs, &load_smi_rhs);
10112 __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset));
10113 __ jmp(&done);
10114
10115 __ bind(&load_smi_lhs);
10116 __ SmiToInteger64(kScratchRegister, lhs);
10117 __ push(kScratchRegister);
10118 __ fild_d(Operand(rsp, 0));
10119 __ pop(kScratchRegister);
10120 __ jmp(&done_load_lhs);
10121
10122 __ bind(&load_smi_rhs);
10123 __ SmiToInteger64(kScratchRegister, rhs);
10124 __ push(kScratchRegister);
10125 __ fild_d(Operand(rsp, 0));
10126 __ pop(kScratchRegister);
10127
10128 __ bind(&done);
10129 }
10130
10131
10132 void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm,
10133 Label* non_float) {
10134 Label test_other, done;
10135 // Test if both operands are numbers (heap_numbers or smis).
10136 // If not, jump to label non_float.
10137 __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK
10138 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), Factory::heap_number_map());
10139 __ j(not_equal, non_float); // The argument in rdx is not a number.
10140
10141 __ bind(&test_other);
10142 __ JumpIfSmi(rax, &done); // argument in rax is OK
10143 __ Cmp(FieldOperand(rax, HeapObject::kMapOffset), Factory::heap_number_map());
10144 __ j(not_equal, non_float); // The argument in rax is not a number.
10145
10146 // Fall-through: Both operands are numbers.
10147 __ bind(&done);
10148 }
10149
10150
10151 void FloatingPointHelper::CheckNumberOperands(MacroAssembler* masm,
10152 Label* non_float,
10153 Register heap_number_map) {
10154 Label test_other, done;
10155 // Test if both operands are numbers (heap_numbers or smis).
10156 // If not, jump to label non_float.
10157 __ JumpIfSmi(rdx, &test_other); // argument in rdx is OK
10158 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map);
10159 __ j(not_equal, non_float); // The argument in rdx is not a number.
10160
10161 __ bind(&test_other);
10162 __ JumpIfSmi(rax, &done); // argument in rax is OK
10163 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map);
10164 __ j(not_equal, non_float); // The argument in rax is not a number.
10165
10166 // Fall-through: Both operands are numbers.
10167 __ bind(&done);
10168 }
10169
10170
10171 const char* GenericBinaryOpStub::GetName() { 10037 const char* GenericBinaryOpStub::GetName() {
10172 if (name_ != NULL) return name_; 10038 if (name_ != NULL) return name_;
10173 const int len = 100; 10039 const int len = 100;
10174 name_ = Bootstrapper::AllocateAutoDeletedArray(len); 10040 name_ = Bootstrapper::AllocateAutoDeletedArray(len);
10175 if (name_ == NULL) return "OOM"; 10041 if (name_ == NULL) return "OOM";
10176 const char* op_name = Token::Name(op_); 10042 const char* op_name = Token::Name(op_);
10177 const char* overwrite_name; 10043 const char* overwrite_name;
10178 switch (mode_) { 10044 switch (mode_) {
10179 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 10045 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
10180 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 10046 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
10467 case Token::MUL: 10333 case Token::MUL:
10468 case Token::DIV: { 10334 case Token::DIV: {
10469 ASSERT(use_fp_on_smis.is_linked()); 10335 ASSERT(use_fp_on_smis.is_linked());
10470 __ bind(&use_fp_on_smis); 10336 __ bind(&use_fp_on_smis);
10471 if (op_ == Token::DIV) { 10337 if (op_ == Token::DIV) {
10472 __ movq(rdx, rax); 10338 __ movq(rdx, rax);
10473 __ movq(rax, rbx); 10339 __ movq(rax, rbx);
10474 } 10340 }
10475 // left is rdx, right is rax. 10341 // left is rdx, right is rax.
10476 __ AllocateHeapNumber(rbx, rcx, slow); 10342 __ AllocateHeapNumber(rbx, rcx, slow);
10477 FloatingPointHelper::LoadFloatOperandsFromSmis(masm, xmm4, xmm5); 10343 FloatingPointHelper::LoadSSE2SmiOperands(masm);
10478 switch (op_) { 10344 switch (op_) {
10479 case Token::ADD: __ addsd(xmm4, xmm5); break; 10345 case Token::ADD: __ addsd(xmm0, xmm1); break;
10480 case Token::SUB: __ subsd(xmm4, xmm5); break; 10346 case Token::SUB: __ subsd(xmm0, xmm1); break;
10481 case Token::MUL: __ mulsd(xmm4, xmm5); break; 10347 case Token::MUL: __ mulsd(xmm0, xmm1); break;
10482 case Token::DIV: __ divsd(xmm4, xmm5); break; 10348 case Token::DIV: __ divsd(xmm0, xmm1); break;
10483 default: UNREACHABLE(); 10349 default: UNREACHABLE();
10484 } 10350 }
10485 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm4); 10351 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
10486 __ movq(rax, rbx); 10352 __ movq(rax, rbx);
10487 GenerateReturn(masm); 10353 GenerateReturn(masm);
10488 } 10354 }
10489 default: 10355 default:
10490 break; 10356 break;
10491 } 10357 }
10492 10358
10493 // 6. Non-smi operands, fall out to the non-smi code with the operands in 10359 // 6. Non-smi operands, fall out to the non-smi code with the operands in
10494 // rdx and rax. 10360 // rdx and rax.
10495 Comment done_comment(masm, "-- Enter non-smi code"); 10361 Comment done_comment(masm, "-- Enter non-smi code");
(...skipping 24 matching lines...) Expand all
10520 10386
10521 if (ShouldGenerateSmiCode()) { 10387 if (ShouldGenerateSmiCode()) {
10522 GenerateSmiCode(masm, &call_runtime); 10388 GenerateSmiCode(masm, &call_runtime);
10523 } else if (op_ != Token::MOD) { 10389 } else if (op_ != Token::MOD) {
10524 if (!HasArgsInRegisters()) { 10390 if (!HasArgsInRegisters()) {
10525 GenerateLoadArguments(masm); 10391 GenerateLoadArguments(masm);
10526 } 10392 }
10527 } 10393 }
10528 // Floating point case. 10394 // Floating point case.
10529 if (ShouldGenerateFPCode()) { 10395 if (ShouldGenerateFPCode()) {
10530 // Load the HeapNumber map here and use it throughout the FP code.
10531 Register heap_number_map = r9;
10532 switch (op_) { 10396 switch (op_) {
10533 case Token::ADD: 10397 case Token::ADD:
10534 case Token::SUB: 10398 case Token::SUB:
10535 case Token::MUL: 10399 case Token::MUL:
10536 case Token::DIV: { 10400 case Token::DIV: {
10537 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && 10401 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
10538 HasSmiCodeInStub()) { 10402 HasSmiCodeInStub()) {
10539 // Execution reaches this point when the first non-smi argument occurs 10403 // Execution reaches this point when the first non-smi argument occurs
10540 // (and only if smi code is generated). This is the right moment to 10404 // (and only if smi code is generated). This is the right moment to
10541 // patch to HEAP_NUMBERS state. The transition is attempted only for 10405 // patch to HEAP_NUMBERS state. The transition is attempted only for
10542 // the four basic operations. The stub stays in the DEFAULT state 10406 // the four basic operations. The stub stays in the DEFAULT state
10543 // forever for all other operations (also if smi code is skipped). 10407 // forever for all other operations (also if smi code is skipped).
10544 GenerateTypeTransition(masm); 10408 GenerateTypeTransition(masm);
10545 } 10409 }
10546 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
10547 10410
10548 Label not_floats; 10411 Label not_floats;
10549 // rax: y 10412 // rax: y
10550 // rdx: x 10413 // rdx: x
10551 if (static_operands_type_.IsNumber() && FLAG_debug_code) { 10414 ASSERT(!static_operands_type_.IsSmi());
10552 // Assert at runtime that inputs are only numbers. 10415 if (static_operands_type_.IsNumber()) {
10553 __ AbortIfNotNumber(rdx); 10416 if (FLAG_debug_code) {
10554 __ AbortIfNotNumber(rax); 10417 // Assert at runtime that inputs are only numbers.
10418 __ AbortIfNotNumber(rdx);
10419 __ AbortIfNotNumber(rax);
10420 }
10421 FloatingPointHelper::LoadSSE2NumberOperands(masm);
10555 } else { 10422 } else {
10556 if (FLAG_debug_code) { 10423 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &call_runtime);
10557 __ AbortIfNotRootValue(heap_number_map,
10558 Heap::kHeapNumberMapRootIndex,
10559 "HeapNumberMap register clobbered.");
10560 }
10561 FloatingPointHelper::CheckNumberOperands(masm,
10562 &call_runtime,
10563 heap_number_map);
10564 } 10424 }
10565 // Fast-case: Both operands are numbers.
10566 // xmm4 and xmm5 are volatile XMM registers.
10567 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5);
10568 10425
10569 switch (op_) { 10426 switch (op_) {
10570 case Token::ADD: __ addsd(xmm4, xmm5); break; 10427 case Token::ADD: __ addsd(xmm0, xmm1); break;
10571 case Token::SUB: __ subsd(xmm4, xmm5); break; 10428 case Token::SUB: __ subsd(xmm0, xmm1); break;
10572 case Token::MUL: __ mulsd(xmm4, xmm5); break; 10429 case Token::MUL: __ mulsd(xmm0, xmm1); break;
10573 case Token::DIV: __ divsd(xmm4, xmm5); break; 10430 case Token::DIV: __ divsd(xmm0, xmm1); break;
10574 default: UNREACHABLE(); 10431 default: UNREACHABLE();
10575 } 10432 }
10576 // Allocate a heap number, if needed. 10433 // Allocate a heap number, if needed.
10577 Label skip_allocation; 10434 Label skip_allocation;
10578 OverwriteMode mode = mode_; 10435 OverwriteMode mode = mode_;
10579 if (HasArgsReversed()) { 10436 if (HasArgsReversed()) {
10580 if (mode == OVERWRITE_RIGHT) { 10437 if (mode == OVERWRITE_RIGHT) {
10581 mode = OVERWRITE_LEFT; 10438 mode = OVERWRITE_LEFT;
10582 } else if (mode == OVERWRITE_LEFT) { 10439 } else if (mode == OVERWRITE_LEFT) {
10583 mode = OVERWRITE_RIGHT; 10440 mode = OVERWRITE_RIGHT;
10584 } 10441 }
10585 } 10442 }
10586 switch (mode) { 10443 switch (mode) {
10587 // TODO(lrn): Allocate this when we first see that the
10588 // left register is a smi (and load it into xmm4).
10589 case OVERWRITE_LEFT: 10444 case OVERWRITE_LEFT:
10590 __ JumpIfNotSmi(rdx, &skip_allocation); 10445 __ JumpIfNotSmi(rdx, &skip_allocation);
10591 // Allocate heap number in new space. 10446 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
10592 __ AllocateInNewSpace(HeapNumber::kSize,
10593 rbx,
10594 rcx,
10595 no_reg,
10596 &call_runtime,
10597 TAG_OBJECT);
10598 if (FLAG_debug_code) {
10599 __ AbortIfNotRootValue(heap_number_map,
10600 Heap::kHeapNumberMapRootIndex,
10601 "HeapNumberMap register clobbered.");
10602 }
10603 __ movq(FieldOperand(rbx, HeapObject::kMapOffset),
10604 heap_number_map);
10605 __ movq(rdx, rbx); 10447 __ movq(rdx, rbx);
10606 __ bind(&skip_allocation); 10448 __ bind(&skip_allocation);
10607 __ movq(rax, rdx); 10449 __ movq(rax, rdx);
10608 break; 10450 break;
10609 case OVERWRITE_RIGHT: 10451 case OVERWRITE_RIGHT:
10610 // If the argument in rax is already an object, we skip the 10452 // If the argument in rax is already an object, we skip the
10611 // allocation of a heap number. 10453 // allocation of a heap number.
10612 // TODO(lrn): Allocate the heap number when we first see that the
10613 // right register is a smi (and load it into xmm5).
10614 __ JumpIfNotSmi(rax, &skip_allocation); 10454 __ JumpIfNotSmi(rax, &skip_allocation);
10615 // Fall through! 10455 // Fall through!
10616 case NO_OVERWRITE: 10456 case NO_OVERWRITE:
10617 // Allocate a heap number for the result. Keep rax and rdx intact 10457 // Allocate a heap number for the result. Keep rax and rdx intact
10618 // for the possible runtime call. 10458 // for the possible runtime call.
10619 __ AllocateInNewSpace(HeapNumber::kSize, 10459 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
10620 rbx,
10621 rcx,
10622 no_reg,
10623 &call_runtime,
10624 TAG_OBJECT);
10625 if (FLAG_debug_code) {
10626 __ AbortIfNotRootValue(heap_number_map,
10627 Heap::kHeapNumberMapRootIndex,
10628 "HeapNumberMap register clobbered.");
10629 }
10630 __ movq(FieldOperand(rbx, HeapObject::kMapOffset),
10631 heap_number_map);
10632 __ movq(rax, rbx); 10460 __ movq(rax, rbx);
10633 __ bind(&skip_allocation); 10461 __ bind(&skip_allocation);
10634 break; 10462 break;
10635 default: UNREACHABLE(); 10463 default: UNREACHABLE();
10636 } 10464 }
10637 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); 10465 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
10638 GenerateReturn(masm); 10466 GenerateReturn(masm);
10639 __ bind(&not_floats); 10467 __ bind(&not_floats);
10640 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && 10468 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
10641 !HasSmiCodeInStub()) { 10469 !HasSmiCodeInStub()) {
10642 // Execution reaches this point when the first non-number argument 10470 // Execution reaches this point when the first non-number argument
10643 // occurs (and only if smi code is skipped from the stub, otherwise 10471 // occurs (and only if smi code is skipped from the stub, otherwise
10644 // the patching has already been done earlier in this case branch). 10472 // the patching has already been done earlier in this case branch).
10645 // A perfect moment to try patching to STRINGS for ADD operation. 10473 // A perfect moment to try patching to STRINGS for ADD operation.
10646 if (op_ == Token::ADD) { 10474 if (op_ == Token::ADD) {
10647 GenerateTypeTransition(masm); 10475 GenerateTypeTransition(masm);
10648 } 10476 }
10649 } 10477 }
10650 break; 10478 break;
10651 } 10479 }
10652 case Token::MOD: { 10480 case Token::MOD: {
10653 // For MOD we go directly to runtime in the non-smi case. 10481 // For MOD we go directly to runtime in the non-smi case.
10654 break; 10482 break;
10655 } 10483 }
10656 case Token::BIT_OR: 10484 case Token::BIT_OR:
10657 case Token::BIT_AND: 10485 case Token::BIT_AND:
10658 case Token::BIT_XOR: 10486 case Token::BIT_XOR:
10659 case Token::SAR: 10487 case Token::SAR:
10660 case Token::SHL: 10488 case Token::SHL:
10661 case Token::SHR: { 10489 case Token::SHR: {
10662 Label skip_allocation, non_smi_shr_result; 10490 Label skip_allocation, non_smi_result;
10663 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 10491 FloatingPointHelper::LoadAsIntegers(masm, &call_runtime);
10664 FloatingPointHelper::LoadAsIntegers(masm,
10665 &call_runtime,
10666 heap_number_map);
10667 switch (op_) { 10492 switch (op_) {
10668 case Token::BIT_OR: __ orl(rax, rcx); break; 10493 case Token::BIT_OR: __ orl(rax, rcx); break;
10669 case Token::BIT_AND: __ andl(rax, rcx); break; 10494 case Token::BIT_AND: __ andl(rax, rcx); break;
10670 case Token::BIT_XOR: __ xorl(rax, rcx); break; 10495 case Token::BIT_XOR: __ xorl(rax, rcx); break;
10671 case Token::SAR: __ sarl_cl(rax); break; 10496 case Token::SAR: __ sarl_cl(rax); break;
10672 case Token::SHL: __ shll_cl(rax); break; 10497 case Token::SHL: __ shll_cl(rax); break;
10673 case Token::SHR: __ shrl_cl(rax); break; 10498 case Token::SHR: __ shrl_cl(rax); break;
10674 default: UNREACHABLE(); 10499 default: UNREACHABLE();
10675 } 10500 }
10676 if (op_ == Token::SHR) { 10501 if (op_ == Token::SHR) {
10677 // Check if result is negative. This can only happen for a shift 10502 // Check if result is negative. This can only happen for a shift
10678 // by zero. 10503 // by zero, which also doesn't update the sign flag.
10679 __ testl(rax, rax); 10504 __ testl(rax, rax);
10680 __ j(negative, &non_smi_shr_result); 10505 __ j(negative, &non_smi_result);
10681 } 10506 }
10682 STATIC_ASSERT(kSmiValueSize == 32); 10507 __ JumpIfNotValidSmiValue(rax, &non_smi_result);
10683 // Tag smi result and return. 10508 // Tag smi result, if possible, and return.
10684 __ Integer32ToSmi(rax, rax); 10509 __ Integer32ToSmi(rax, rax);
10685 GenerateReturn(masm); 10510 GenerateReturn(masm);
10686 10511
10687 // All bit-ops except SHR return a signed int32 that can be 10512 // All ops except SHR return a signed int32 that we load in
10688 // returned immediately as a smi. 10513 // a HeapNumber.
10689 if (op_ == Token::SHR) { 10514 if (op_ != Token::SHR && non_smi_result.is_linked()) {
10690 ASSERT(non_smi_shr_result.is_linked()); 10515 __ bind(&non_smi_result);
10691 __ bind(&non_smi_shr_result);
10692 // Allocate a heap number if needed. 10516 // Allocate a heap number if needed.
10693 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). 10517 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result
10694 switch (mode_) { 10518 switch (mode_) {
10695 case OVERWRITE_LEFT: 10519 case OVERWRITE_LEFT:
10696 case OVERWRITE_RIGHT: 10520 case OVERWRITE_RIGHT:
10697 // If the operand was an object, we skip the 10521 // If the operand was an object, we skip the
10698 // allocation of a heap number. 10522 // allocation of a heap number.
10699 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? 10523 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
10700 1 * kPointerSize : 2 * kPointerSize)); 10524 1 * kPointerSize : 2 * kPointerSize));
10701 __ JumpIfNotSmi(rax, &skip_allocation); 10525 __ JumpIfNotSmi(rax, &skip_allocation);
10702 // Fall through! 10526 // Fall through!
10703 case NO_OVERWRITE: 10527 case NO_OVERWRITE:
10704 // Allocate heap number in new space. 10528 __ AllocateHeapNumber(rax, rcx, &call_runtime);
10705 __ AllocateInNewSpace(HeapNumber::kSize,
10706 rax,
10707 rcx,
10708 no_reg,
10709 &call_runtime,
10710 TAG_OBJECT);
10711 // Set the map.
10712 if (FLAG_debug_code) {
10713 __ AbortIfNotRootValue(heap_number_map,
10714 Heap::kHeapNumberMapRootIndex,
10715 "HeapNumberMap register clobbered.");
10716 }
10717 __ movq(FieldOperand(rax, HeapObject::kMapOffset),
10718 heap_number_map);
10719 __ bind(&skip_allocation); 10529 __ bind(&skip_allocation);
10720 break; 10530 break;
10721 default: UNREACHABLE(); 10531 default: UNREACHABLE();
10722 } 10532 }
10723 // Store the result in the HeapNumber and return. 10533 // Store the result in the HeapNumber and return.
10724 __ cvtqsi2sd(xmm0, rbx); 10534 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
10725 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); 10535 __ fild_s(Operand(rsp, 1 * kPointerSize));
10536 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset));
10726 GenerateReturn(masm); 10537 GenerateReturn(masm);
10727 } 10538 }
10728 10539
10540 // SHR should return uint32 - go to runtime for non-smi/negative result.
10541 if (op_ == Token::SHR) {
10542 __ bind(&non_smi_result);
10543 }
10729 break; 10544 break;
10730 } 10545 }
10731 default: UNREACHABLE(); break; 10546 default: UNREACHABLE(); break;
10732 } 10547 }
10733 } 10548 }
10734 10549
10735 // If all else fails, use the runtime system to get the correct 10550 // If all else fails, use the runtime system to get the correct
10736 // result. If arguments was passed in registers now place them on the 10551 // result. If arguments was passed in registers now place them on the
10737 // stack in the correct order below the return address. 10552 // stack in the correct order below the return address.
10738 __ bind(&call_runtime); 10553 __ bind(&call_runtime);
(...skipping 12 matching lines...) Expand all
10751 rhs = rdx; 10566 rhs = rdx;
10752 } else { 10567 } else {
10753 lhs = rdx; 10568 lhs = rdx;
10754 rhs = rax; 10569 rhs = rax;
10755 } 10570 }
10756 10571
10757 // Test for string arguments before calling runtime. 10572 // Test for string arguments before calling runtime.
10758 Label not_strings, both_strings, not_string1, string1, string1_smi2; 10573 Label not_strings, both_strings, not_string1, string1, string1_smi2;
10759 10574
10760 // If this stub has already generated FP-specific code then the arguments 10575 // If this stub has already generated FP-specific code then the arguments
10761 // are already in rdx, rax. 10576 // are already in rdx, rax
10762 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { 10577 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
10763 GenerateLoadArguments(masm); 10578 GenerateLoadArguments(masm);
10764 } 10579 }
10765 10580
10766 Condition is_smi; 10581 Condition is_smi;
10767 is_smi = masm->CheckSmi(lhs); 10582 is_smi = masm->CheckSmi(lhs);
10768 __ j(is_smi, &not_string1); 10583 __ j(is_smi, &not_string1);
10769 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8); 10584 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8);
10770 __ j(above_equal, &not_string1); 10585 __ j(above_equal, &not_string1);
10771 10586
(...skipping 1260 matching lines...) Expand 10 before | Expand all | Expand 10 after
12032 } 11847 }
12033 11848
12034 #endif 11849 #endif
12035 11850
12036 11851
12037 #undef __ 11852 #undef __
12038 11853
12039 } } // namespace v8::internal 11854 } } // namespace v8::internal
12040 11855
12041 #endif // V8_TARGET_ARCH_X64 11856 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698