|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "jit/shared/MacroAssembler-x86-shared.h" |
|
8 |
|
9 #include "jit/IonFrames.h" |
|
10 #include "jit/IonMacroAssembler.h" |
|
11 |
|
12 using namespace js; |
|
13 using namespace js::jit; |
|
14 |
|
15 void |
|
16 MacroAssembler::PushRegsInMask(RegisterSet set) |
|
17 { |
|
18 int32_t diffF = set.fpus().size() * sizeof(double); |
|
19 int32_t diffG = set.gprs().size() * sizeof(intptr_t); |
|
20 |
|
21 // On x86, always use push to push the integer registers, as it's fast |
|
22 // on modern hardware and it's a small instruction. |
|
23 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { |
|
24 diffG -= sizeof(intptr_t); |
|
25 Push(*iter); |
|
26 } |
|
27 JS_ASSERT(diffG == 0); |
|
28 |
|
29 reserveStack(diffF); |
|
30 for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) { |
|
31 diffF -= sizeof(double); |
|
32 storeDouble(*iter, Address(StackPointer, diffF)); |
|
33 } |
|
34 JS_ASSERT(diffF == 0); |
|
35 } |
|
36 |
|
37 void |
|
38 MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore) |
|
39 { |
|
40 int32_t diffG = set.gprs().size() * sizeof(intptr_t); |
|
41 int32_t diffF = set.fpus().size() * sizeof(double); |
|
42 const int32_t reservedG = diffG; |
|
43 const int32_t reservedF = diffF; |
|
44 |
|
45 for (FloatRegisterBackwardIterator iter(set.fpus()); iter.more(); iter++) { |
|
46 diffF -= sizeof(double); |
|
47 if (!ignore.has(*iter)) |
|
48 loadDouble(Address(StackPointer, diffF), *iter); |
|
49 } |
|
50 freeStack(reservedF); |
|
51 JS_ASSERT(diffF == 0); |
|
52 |
|
53 // On x86, use pop to pop the integer registers, if we're not going to |
|
54 // ignore any slots, as it's fast on modern hardware and it's a small |
|
55 // instruction. |
|
56 if (ignore.empty(false)) { |
|
57 for (GeneralRegisterForwardIterator iter(set.gprs()); iter.more(); iter++) { |
|
58 diffG -= sizeof(intptr_t); |
|
59 Pop(*iter); |
|
60 } |
|
61 } else { |
|
62 for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) { |
|
63 diffG -= sizeof(intptr_t); |
|
64 if (!ignore.has(*iter)) |
|
65 loadPtr(Address(StackPointer, diffG), *iter); |
|
66 } |
|
67 freeStack(reservedG); |
|
68 } |
|
69 JS_ASSERT(diffG == 0); |
|
70 } |
|
71 |
|
72 // Note: this function clobbers the input register. |
|
73 void |
|
74 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output) |
|
75 { |
|
76 JS_ASSERT(input != ScratchFloatReg); |
|
77 Label positive, done; |
|
78 |
|
79 // <= 0 or NaN --> 0 |
|
80 zeroDouble(ScratchFloatReg); |
|
81 branchDouble(DoubleGreaterThan, input, ScratchFloatReg, &positive); |
|
82 { |
|
83 move32(Imm32(0), output); |
|
84 jump(&done); |
|
85 } |
|
86 |
|
87 bind(&positive); |
|
88 |
|
89 // Add 0.5 and truncate. |
|
90 loadConstantDouble(0.5, ScratchFloatReg); |
|
91 addDouble(ScratchFloatReg, input); |
|
92 |
|
93 Label outOfRange; |
|
94 |
|
95 // Truncate to int32 and ensure the result <= 255. This relies on the |
|
96 // processor setting output to a value > 255 for doubles outside the int32 |
|
97 // range (for instance 0x80000000). |
|
98 cvttsd2si(input, output); |
|
99 branch32(Assembler::Above, output, Imm32(255), &outOfRange); |
|
100 { |
|
101 // Check if we had a tie. |
|
102 convertInt32ToDouble(output, ScratchFloatReg); |
|
103 branchDouble(DoubleNotEqual, input, ScratchFloatReg, &done); |
|
104 |
|
105 // It was a tie. Mask out the ones bit to get an even value. |
|
106 // See also js_TypedArray_uint8_clamp_double. |
|
107 and32(Imm32(~1), output); |
|
108 jump(&done); |
|
109 } |
|
110 |
|
111 // > 255 --> 255 |
|
112 bind(&outOfRange); |
|
113 { |
|
114 move32(Imm32(255), output); |
|
115 } |
|
116 |
|
117 bind(&done); |
|
118 } |
|
119 |
|
120 // Builds an exit frame on the stack, with a return address to an internal |
|
121 // non-function. Returns offset to be passed to markSafepointAt(). |
|
122 bool |
|
123 MacroAssemblerX86Shared::buildFakeExitFrame(const Register &scratch, uint32_t *offset) |
|
124 { |
|
125 mozilla::DebugOnly<uint32_t> initialDepth = framePushed(); |
|
126 |
|
127 CodeLabel cl; |
|
128 mov(cl.dest(), scratch); |
|
129 |
|
130 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); |
|
131 Push(Imm32(descriptor)); |
|
132 Push(scratch); |
|
133 |
|
134 bind(cl.src()); |
|
135 *offset = currentOffset(); |
|
136 |
|
137 JS_ASSERT(framePushed() == initialDepth + IonExitFrameLayout::Size()); |
|
138 return addCodeLabel(cl); |
|
139 } |
|
140 |
|
141 void |
|
142 MacroAssemblerX86Shared::callWithExitFrame(JitCode *target) |
|
143 { |
|
144 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); |
|
145 Push(Imm32(descriptor)); |
|
146 call(target); |
|
147 } |
|
148 |
|
149 bool |
|
150 MacroAssemblerX86Shared::buildOOLFakeExitFrame(void *fakeReturnAddr) |
|
151 { |
|
152 uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS); |
|
153 Push(Imm32(descriptor)); |
|
154 Push(ImmPtr(fakeReturnAddr)); |
|
155 return true; |
|
156 } |
|
157 |
|
158 void |
|
159 MacroAssemblerX86Shared::branchNegativeZero(const FloatRegister ®, |
|
160 const Register &scratch, |
|
161 Label *label) |
|
162 { |
|
163 // Determines whether the low double contained in the XMM register reg |
|
164 // is equal to -0.0. |
|
165 |
|
166 #if defined(JS_CODEGEN_X86) |
|
167 Label nonZero; |
|
168 |
|
169 // Compare to zero. Lets through {0, -0}. |
|
170 xorpd(ScratchFloatReg, ScratchFloatReg); |
|
171 |
|
172 // If reg is non-zero, jump to nonZero. |
|
173 branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero); |
|
174 |
|
175 // Input register is either zero or negative zero. Retrieve sign of input. |
|
176 movmskpd(reg, scratch); |
|
177 |
|
178 // If reg is 1 or 3, input is negative zero. |
|
179 // If reg is 0 or 2, input is a normal zero. |
|
180 branchTest32(NonZero, scratch, Imm32(1), label); |
|
181 |
|
182 bind(&nonZero); |
|
183 #elif defined(JS_CODEGEN_X64) |
|
184 movq(reg, scratch); |
|
185 cmpq(scratch, Imm32(1)); |
|
186 j(Overflow, label); |
|
187 #endif |
|
188 } |
|
189 |
|
190 void |
|
191 MacroAssemblerX86Shared::branchNegativeZeroFloat32(const FloatRegister ®, |
|
192 const Register &scratch, |
|
193 Label *label) |
|
194 { |
|
195 movd(reg, scratch); |
|
196 cmpl(scratch, Imm32(1)); |
|
197 j(Overflow, label); |
|
198 } |