1 | /* |
2 | * Copyright (C) 2013-2017 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "FTLOutput.h" |
28 | |
29 | #if ENABLE(FTL_JIT) |
30 | |
31 | #include "B3ArgumentRegValue.h" |
32 | #include "B3AtomicValue.h" |
33 | #include "B3BasicBlockInlines.h" |
34 | #include "B3CCallValue.h" |
35 | #include "B3Const32Value.h" |
36 | #include "B3ConstPtrValue.h" |
37 | #include "B3FenceValue.h" |
38 | #include "B3MathExtras.h" |
39 | #include "B3MemoryValue.h" |
40 | #include "B3SlotBaseValue.h" |
41 | #include "B3StackmapGenerationParams.h" |
42 | #include "B3SwitchValue.h" |
43 | #include "B3UpsilonValue.h" |
44 | #include "B3ValueInlines.h" |
45 | #include "SuperSampler.h" |
46 | |
47 | namespace JSC { namespace FTL { |
48 | |
49 | using namespace B3; |
50 | |
51 | Output::Output(State& state) |
52 | : m_proc(*state.proc) |
53 | { |
54 | } |
55 | |
56 | Output::~Output() |
57 | { |
58 | } |
59 | |
60 | void Output::initialize(AbstractHeapRepository& heaps) |
61 | { |
62 | m_heaps = &heaps; |
63 | } |
64 | |
65 | LBasicBlock Output::newBlock() |
66 | { |
67 | LBasicBlock result = m_proc.addBlock(m_frequency); |
68 | |
69 | if (!m_nextBlock) |
70 | m_blockOrder.append(result); |
71 | else |
72 | m_blockOrder.insertBefore(m_nextBlock, result); |
73 | |
74 | return result; |
75 | } |
76 | |
77 | void Output::applyBlockOrder() |
78 | { |
79 | m_proc.setBlockOrder(m_blockOrder); |
80 | } |
81 | |
82 | LBasicBlock Output::appendTo(LBasicBlock block, LBasicBlock nextBlock) |
83 | { |
84 | appendTo(block); |
85 | return insertNewBlocksBefore(nextBlock); |
86 | } |
87 | |
88 | void Output::appendTo(LBasicBlock block) |
89 | { |
90 | m_block = block; |
91 | } |
92 | |
93 | LValue Output::framePointer() |
94 | { |
95 | return m_block->appendNew<B3::Value>(m_proc, B3::FramePointer, origin()); |
96 | } |
97 | |
98 | SlotBaseValue* Output::lockedStackSlot(size_t bytes) |
99 | { |
100 | return m_block->appendNew<SlotBaseValue>(m_proc, origin(), m_proc.addStackSlot(bytes)); |
101 | } |
102 | |
103 | LValue Output::constBool(bool value) |
104 | { |
105 | if (value) |
106 | return booleanTrue; |
107 | return booleanFalse; |
108 | } |
109 | |
110 | LValue Output::constInt32(int32_t value) |
111 | { |
112 | return m_block->appendNew<B3::Const32Value>(m_proc, origin(), value); |
113 | } |
114 | |
115 | LValue Output::constInt64(int64_t value) |
116 | { |
117 | return m_block->appendNew<B3::Const64Value>(m_proc, origin(), value); |
118 | } |
119 | |
120 | LValue Output::constDouble(double value) |
121 | { |
122 | return m_block->appendNew<B3::ConstDoubleValue>(m_proc, origin(), value); |
123 | } |
124 | |
125 | LValue Output::phi(LType type) |
126 | { |
127 | return m_block->appendNew<B3::Value>(m_proc, B3::Phi, type, origin()); |
128 | } |
129 | |
130 | LValue Output::opaque(LValue value) |
131 | { |
132 | return m_block->appendNew<Value>(m_proc, Opaque, origin(), value); |
133 | } |
134 | |
135 | LValue Output::add(LValue left, LValue right) |
136 | { |
137 | if (Value* result = left->addConstant(m_proc, right)) { |
138 | m_block->append(result); |
139 | return result; |
140 | } |
141 | return m_block->appendNew<B3::Value>(m_proc, B3::Add, origin(), left, right); |
142 | } |
143 | |
144 | LValue Output::sub(LValue left, LValue right) |
145 | { |
146 | return m_block->appendNew<B3::Value>(m_proc, B3::Sub, origin(), left, right); |
147 | } |
148 | |
149 | LValue Output::mul(LValue left, LValue right) |
150 | { |
151 | return m_block->appendNew<B3::Value>(m_proc, B3::Mul, origin(), left, right); |
152 | } |
153 | |
154 | LValue Output::div(LValue left, LValue right) |
155 | { |
156 | return m_block->appendNew<B3::Value>(m_proc, B3::Div, origin(), left, right); |
157 | } |
158 | |
159 | LValue Output::chillDiv(LValue left, LValue right) |
160 | { |
161 | return m_block->appendNew<B3::Value>(m_proc, chill(B3::Div), origin(), left, right); |
162 | } |
163 | |
164 | LValue Output::mod(LValue left, LValue right) |
165 | { |
166 | return m_block->appendNew<B3::Value>(m_proc, B3::Mod, origin(), left, right); |
167 | } |
168 | |
169 | LValue Output::chillMod(LValue left, LValue right) |
170 | { |
171 | return m_block->appendNew<B3::Value>(m_proc, chill(B3::Mod), origin(), left, right); |
172 | } |
173 | |
174 | LValue Output::neg(LValue value) |
175 | { |
176 | return m_block->appendNew<Value>(m_proc, B3::Neg, origin(), value); |
177 | } |
178 | |
179 | LValue Output::doubleAdd(LValue left, LValue right) |
180 | { |
181 | return m_block->appendNew<B3::Value>(m_proc, B3::Add, origin(), left, right); |
182 | } |
183 | |
184 | LValue Output::doubleSub(LValue left, LValue right) |
185 | { |
186 | return m_block->appendNew<B3::Value>(m_proc, B3::Sub, origin(), left, right); |
187 | } |
188 | |
189 | LValue Output::doubleMul(LValue left, LValue right) |
190 | { |
191 | return m_block->appendNew<B3::Value>(m_proc, B3::Mul, origin(), left, right); |
192 | } |
193 | |
194 | LValue Output::doubleDiv(LValue left, LValue right) |
195 | { |
196 | return m_block->appendNew<B3::Value>(m_proc, B3::Div, origin(), left, right); |
197 | } |
198 | |
199 | LValue Output::doubleMod(LValue left, LValue right) |
200 | { |
201 | return m_block->appendNew<B3::Value>(m_proc, B3::Mod, origin(), left, right); |
202 | } |
203 | |
204 | LValue Output::bitAnd(LValue left, LValue right) |
205 | { |
206 | return m_block->appendNew<B3::Value>(m_proc, B3::BitAnd, origin(), left, right); |
207 | } |
208 | |
209 | LValue Output::bitOr(LValue left, LValue right) |
210 | { |
211 | return m_block->appendNew<B3::Value>(m_proc, B3::BitOr, origin(), left, right); |
212 | } |
213 | |
214 | LValue Output::bitXor(LValue left, LValue right) |
215 | { |
216 | return m_block->appendNew<B3::Value>(m_proc, B3::BitXor, origin(), left, right); |
217 | } |
218 | |
219 | LValue Output::shl(LValue left, LValue right) |
220 | { |
221 | right = castToInt32(right); |
222 | if (Value* result = left->shlConstant(m_proc, right)) { |
223 | m_block->append(result); |
224 | return result; |
225 | } |
226 | return m_block->appendNew<B3::Value>(m_proc, B3::Shl, origin(), left, right); |
227 | } |
228 | |
229 | LValue Output::aShr(LValue left, LValue right) |
230 | { |
231 | right = castToInt32(right); |
232 | if (Value* result = left->sShrConstant(m_proc, right)) { |
233 | m_block->append(result); |
234 | return result; |
235 | } |
236 | return m_block->appendNew<B3::Value>(m_proc, B3::SShr, origin(), left, right); |
237 | } |
238 | |
239 | LValue Output::lShr(LValue left, LValue right) |
240 | { |
241 | right = castToInt32(right); |
242 | if (Value* result = left->zShrConstant(m_proc, right)) { |
243 | m_block->append(result); |
244 | return result; |
245 | } |
246 | return m_block->appendNew<B3::Value>(m_proc, B3::ZShr, origin(), left, right); |
247 | } |
248 | |
249 | LValue Output::bitNot(LValue value) |
250 | { |
251 | return m_block->appendNew<B3::Value>(m_proc, B3::BitXor, origin(), |
252 | value, |
253 | m_block->appendIntConstant(m_proc, origin(), value->type(), -1)); |
254 | } |
255 | |
256 | LValue Output::logicalNot(LValue value) |
257 | { |
258 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int32Zero); |
259 | } |
260 | |
261 | LValue Output::ctlz32(LValue operand) |
262 | { |
263 | return m_block->appendNew<B3::Value>(m_proc, B3::Clz, origin(), operand); |
264 | } |
265 | |
266 | LValue Output::doubleAbs(LValue value) |
267 | { |
268 | return m_block->appendNew<B3::Value>(m_proc, B3::Abs, origin(), value); |
269 | } |
270 | |
271 | LValue Output::doubleCeil(LValue operand) |
272 | { |
273 | return m_block->appendNew<B3::Value>(m_proc, B3::Ceil, origin(), operand); |
274 | } |
275 | |
276 | LValue Output::doubleFloor(LValue operand) |
277 | { |
278 | return m_block->appendNew<B3::Value>(m_proc, B3::Floor, origin(), operand); |
279 | } |
280 | |
281 | LValue Output::doubleTrunc(LValue value) |
282 | { |
283 | if (MacroAssembler::supportsFloatingPointRounding()) { |
284 | PatchpointValue* result = patchpoint(Double); |
285 | result->append(value, ValueRep::SomeRegister); |
286 | result->setGenerator( |
287 | [] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
288 | jit.roundTowardZeroDouble(params[1].fpr(), params[0].fpr()); |
289 | }); |
290 | result->effects = Effects::none(); |
291 | return result; |
292 | } |
293 | double (*truncDouble)(double) = trunc; |
294 | return callWithoutSideEffects(Double, truncDouble, value); |
295 | } |
296 | |
297 | LValue Output::doubleUnary(DFG::Arith::UnaryType type, LValue value) |
298 | { |
299 | double (*unaryFunction)(double) = DFG::arithUnaryFunction(type); |
300 | return callWithoutSideEffects(B3::Double, unaryFunction, value); |
301 | } |
302 | |
303 | LValue Output::doublePow(LValue xOperand, LValue yOperand) |
304 | { |
305 | double (*powDouble)(double, double) = pow; |
306 | return callWithoutSideEffects(B3::Double, powDouble, xOperand, yOperand); |
307 | } |
308 | |
309 | LValue Output::doublePowi(LValue x, LValue y) |
310 | { |
311 | // FIXME: powDoubleInt32() should be inlined here since Output knows about block layout and |
312 | // should be involved in any operation that creates blocks. |
313 | // https://bugs.webkit.org/show_bug.cgi?id=152223 |
314 | auto result = powDoubleInt32(m_proc, m_block, origin(), x, y); |
315 | m_block = result.first; |
316 | return result.second; |
317 | } |
318 | |
319 | LValue Output::doubleSqrt(LValue value) |
320 | { |
321 | return m_block->appendNew<B3::Value>(m_proc, B3::Sqrt, origin(), value); |
322 | } |
323 | |
324 | LValue Output::doubleToInt(LValue value) |
325 | { |
326 | PatchpointValue* result = patchpoint(Int32); |
327 | result->append(value, ValueRep::SomeRegister); |
328 | result->setGenerator( |
329 | [] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
330 | jit.truncateDoubleToInt32(params[1].fpr(), params[0].gpr()); |
331 | }); |
332 | result->effects = Effects::none(); |
333 | return result; |
334 | } |
335 | |
336 | LValue Output::doubleToInt64(LValue value) |
337 | { |
338 | PatchpointValue* result = patchpoint(Int64); |
339 | result->append(value, ValueRep::SomeRegister); |
340 | result->setGenerator( |
341 | [] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
342 | jit.truncateDoubleToInt64(params[1].fpr(), params[0].gpr()); |
343 | }); |
344 | result->effects = Effects::none(); |
345 | return result; |
346 | } |
347 | |
348 | LValue Output::doubleToUInt(LValue value) |
349 | { |
350 | PatchpointValue* result = patchpoint(Int32); |
351 | result->append(value, ValueRep::SomeRegister); |
352 | result->setGenerator( |
353 | [] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
354 | jit.truncateDoubleToUint32(params[1].fpr(), params[0].gpr()); |
355 | }); |
356 | result->effects = Effects::none(); |
357 | return result; |
358 | } |
359 | |
360 | LValue Output::signExt32To64(LValue value) |
361 | { |
362 | return m_block->appendNew<B3::Value>(m_proc, B3::SExt32, origin(), value); |
363 | } |
364 | |
365 | LValue Output::signExt32ToPtr(LValue value) |
366 | { |
367 | return signExt32To64(value); |
368 | } |
369 | |
370 | LValue Output::zeroExt(LValue value, LType type) |
371 | { |
372 | if (value->type() == type) |
373 | return value; |
374 | if (value->hasInt32()) |
375 | return m_block->appendIntConstant(m_proc, origin(), Int64, static_cast<uint64_t>(static_cast<uint32_t>(value->asInt32()))); |
376 | return m_block->appendNew<B3::Value>(m_proc, B3::ZExt32, origin(), value); |
377 | } |
378 | |
379 | LValue Output::intToDouble(LValue value) |
380 | { |
381 | return m_block->appendNew<B3::Value>(m_proc, B3::IToD, origin(), value); |
382 | } |
383 | |
384 | LValue Output::unsignedToDouble(LValue value) |
385 | { |
386 | return intToDouble(zeroExt(value, Int64)); |
387 | } |
388 | |
389 | LValue Output::castToInt32(LValue value) |
390 | { |
391 | if (value->type() == Int32) |
392 | return value; |
393 | if (value->hasInt64()) |
394 | return constInt32(static_cast<int32_t>(value->asInt64())); |
395 | return m_block->appendNew<B3::Value>(m_proc, B3::Trunc, origin(), value); |
396 | } |
397 | |
398 | LValue Output::doubleToFloat(LValue value) |
399 | { |
400 | return m_block->appendNew<B3::Value>(m_proc, B3::DoubleToFloat, origin(), value); |
401 | } |
402 | |
403 | LValue Output::floatToDouble(LValue value) |
404 | { |
405 | return m_block->appendNew<B3::Value>(m_proc, B3::FloatToDouble, origin(), value); |
406 | } |
407 | |
408 | LValue Output::load(TypedPointer pointer, LType type) |
409 | { |
410 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load, type, origin(), pointer.value()); |
411 | m_heaps->decorateMemory(pointer.heap(), load); |
412 | return load; |
413 | } |
414 | |
415 | LValue Output::load8SignExt32(TypedPointer pointer) |
416 | { |
417 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8S, Int32, origin(), pointer.value()); |
418 | m_heaps->decorateMemory(pointer.heap(), load); |
419 | return load; |
420 | } |
421 | |
422 | LValue Output::load8ZeroExt32(TypedPointer pointer) |
423 | { |
424 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8Z, Int32, origin(), pointer.value()); |
425 | m_heaps->decorateMemory(pointer.heap(), load); |
426 | return load; |
427 | } |
428 | |
429 | LValue Output::load16SignExt32(TypedPointer pointer) |
430 | { |
431 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16S, Int32, origin(), pointer.value()); |
432 | m_heaps->decorateMemory(pointer.heap(), load); |
433 | return load; |
434 | } |
435 | |
436 | LValue Output::load16ZeroExt32(TypedPointer pointer) |
437 | { |
438 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16Z, Int32, origin(), pointer.value()); |
439 | m_heaps->decorateMemory(pointer.heap(), load); |
440 | return load; |
441 | } |
442 | |
443 | LValue Output::store(LValue value, TypedPointer pointer) |
444 | { |
445 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store, origin(), value, pointer.value()); |
446 | m_heaps->decorateMemory(pointer.heap(), store); |
447 | return store; |
448 | } |
449 | |
450 | FenceValue* Output::fence(const AbstractHeap* read, const AbstractHeap* write) |
451 | { |
452 | FenceValue* result = m_block->appendNew<FenceValue>(m_proc, origin()); |
453 | m_heaps->decorateFenceRead(read, result); |
454 | m_heaps->decorateFenceWrite(write, result); |
455 | return result; |
456 | } |
457 | |
458 | LValue Output::store32As8(LValue value, TypedPointer pointer) |
459 | { |
460 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store8, origin(), value, pointer.value()); |
461 | m_heaps->decorateMemory(pointer.heap(), store); |
462 | return store; |
463 | } |
464 | |
465 | LValue Output::store32As16(LValue value, TypedPointer pointer) |
466 | { |
467 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store16, origin(), value, pointer.value()); |
468 | m_heaps->decorateMemory(pointer.heap(), store); |
469 | return store; |
470 | } |
471 | |
472 | LValue Output::baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset) |
473 | { |
474 | LValue accumulatedOffset; |
475 | |
476 | switch (scale) { |
477 | case ScaleOne: |
478 | accumulatedOffset = index; |
479 | break; |
480 | case ScaleTwo: |
481 | accumulatedOffset = shl(index, intPtrOne); |
482 | break; |
483 | case ScaleFour: |
484 | accumulatedOffset = shl(index, intPtrTwo); |
485 | break; |
486 | case ScaleEight: |
487 | case ScalePtr: |
488 | accumulatedOffset = shl(index, intPtrThree); |
489 | break; |
490 | } |
491 | |
492 | if (offset) |
493 | accumulatedOffset = add(accumulatedOffset, constIntPtr(offset)); |
494 | |
495 | return add(base, accumulatedOffset); |
496 | } |
497 | |
498 | LValue Output::equal(LValue left, LValue right) |
499 | { |
500 | TriState result = left->equalConstant(right); |
501 | if (result != MixedTriState) |
502 | return constBool(result == TrueTriState); |
503 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), left, right); |
504 | } |
505 | |
506 | LValue Output::notEqual(LValue left, LValue right) |
507 | { |
508 | TriState result = left->notEqualConstant(right); |
509 | if (result != MixedTriState) |
510 | return constBool(result == TrueTriState); |
511 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), left, right); |
512 | } |
513 | |
514 | LValue Output::above(LValue left, LValue right) |
515 | { |
516 | TriState result = left->aboveConstant(right); |
517 | if (result != MixedTriState) |
518 | return constBool(result == TrueTriState); |
519 | return m_block->appendNew<B3::Value>(m_proc, B3::Above, origin(), left, right); |
520 | } |
521 | |
522 | LValue Output::aboveOrEqual(LValue left, LValue right) |
523 | { |
524 | TriState result = left->aboveEqualConstant(right); |
525 | if (result != MixedTriState) |
526 | return constBool(result == TrueTriState); |
527 | return m_block->appendNew<B3::Value>(m_proc, B3::AboveEqual, origin(), left, right); |
528 | } |
529 | |
530 | LValue Output::below(LValue left, LValue right) |
531 | { |
532 | TriState result = left->belowConstant(right); |
533 | if (result != MixedTriState) |
534 | return constBool(result == TrueTriState); |
535 | return m_block->appendNew<B3::Value>(m_proc, B3::Below, origin(), left, right); |
536 | } |
537 | |
538 | LValue Output::belowOrEqual(LValue left, LValue right) |
539 | { |
540 | TriState result = left->belowEqualConstant(right); |
541 | if (result != MixedTriState) |
542 | return constBool(result == TrueTriState); |
543 | return m_block->appendNew<B3::Value>(m_proc, B3::BelowEqual, origin(), left, right); |
544 | } |
545 | |
546 | LValue Output::greaterThan(LValue left, LValue right) |
547 | { |
548 | TriState result = left->greaterThanConstant(right); |
549 | if (result != MixedTriState) |
550 | return constBool(result == TrueTriState); |
551 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterThan, origin(), left, right); |
552 | } |
553 | |
554 | LValue Output::greaterThanOrEqual(LValue left, LValue right) |
555 | { |
556 | TriState result = left->greaterEqualConstant(right); |
557 | if (result != MixedTriState) |
558 | return constBool(result == TrueTriState); |
559 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterEqual, origin(), left, right); |
560 | } |
561 | |
562 | LValue Output::lessThan(LValue left, LValue right) |
563 | { |
564 | TriState result = left->lessThanConstant(right); |
565 | if (result != MixedTriState) |
566 | return constBool(result == TrueTriState); |
567 | return m_block->appendNew<B3::Value>(m_proc, B3::LessThan, origin(), left, right); |
568 | } |
569 | |
570 | LValue Output::lessThanOrEqual(LValue left, LValue right) |
571 | { |
572 | TriState result = left->lessEqualConstant(right); |
573 | if (result != MixedTriState) |
574 | return constBool(result == TrueTriState); |
575 | return m_block->appendNew<B3::Value>(m_proc, B3::LessEqual, origin(), left, right); |
576 | } |
577 | |
578 | LValue Output::doubleEqual(LValue left, LValue right) |
579 | { |
580 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), left, right); |
581 | } |
582 | |
583 | LValue Output::doubleEqualOrUnordered(LValue left, LValue right) |
584 | { |
585 | return m_block->appendNew<B3::Value>(m_proc, B3::EqualOrUnordered, origin(), left, right); |
586 | } |
587 | |
588 | LValue Output::doubleNotEqualOrUnordered(LValue left, LValue right) |
589 | { |
590 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), left, right); |
591 | } |
592 | |
593 | LValue Output::doubleLessThan(LValue left, LValue right) |
594 | { |
595 | return m_block->appendNew<B3::Value>(m_proc, B3::LessThan, origin(), left, right); |
596 | } |
597 | |
598 | LValue Output::doubleLessThanOrEqual(LValue left, LValue right) |
599 | { |
600 | return m_block->appendNew<B3::Value>(m_proc, B3::LessEqual, origin(), left, right); |
601 | } |
602 | |
603 | LValue Output::doubleGreaterThan(LValue left, LValue right) |
604 | { |
605 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterThan, origin(), left, right); |
606 | } |
607 | |
608 | LValue Output::doubleGreaterThanOrEqual(LValue left, LValue right) |
609 | { |
610 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterEqual, origin(), left, right); |
611 | } |
612 | |
613 | LValue Output::doubleNotEqualAndOrdered(LValue left, LValue right) |
614 | { |
615 | return logicalNot(doubleEqualOrUnordered(left, right)); |
616 | } |
617 | |
618 | LValue Output::doubleLessThanOrUnordered(LValue left, LValue right) |
619 | { |
620 | return logicalNot(doubleGreaterThanOrEqual(left, right)); |
621 | } |
622 | |
623 | LValue Output::doubleLessThanOrEqualOrUnordered(LValue left, LValue right) |
624 | { |
625 | return logicalNot(doubleGreaterThan(left, right)); |
626 | } |
627 | |
628 | LValue Output::doubleGreaterThanOrUnordered(LValue left, LValue right) |
629 | { |
630 | return logicalNot(doubleLessThanOrEqual(left, right)); |
631 | } |
632 | |
633 | LValue Output::doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) |
634 | { |
635 | return logicalNot(doubleLessThan(left, right)); |
636 | } |
637 | |
638 | LValue Output::isZero32(LValue value) |
639 | { |
640 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int32Zero); |
641 | } |
642 | |
643 | LValue Output::notZero32(LValue value) |
644 | { |
645 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), value, int32Zero); |
646 | } |
647 | |
648 | LValue Output::isZero64(LValue value) |
649 | { |
650 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int64Zero); |
651 | } |
652 | |
653 | LValue Output::notZero64(LValue value) |
654 | { |
655 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), value, int64Zero); |
656 | } |
657 | |
658 | LValue Output::select(LValue value, LValue taken, LValue notTaken) |
659 | { |
660 | if (value->hasInt32()) { |
661 | if (value->asInt32()) |
662 | return taken; |
663 | else |
664 | return notTaken; |
665 | } |
666 | return m_block->appendNew<B3::Value>(m_proc, B3::Select, origin(), value, taken, notTaken); |
667 | } |
668 | |
669 | LValue Output::atomicXchgAdd(LValue operand, TypedPointer pointer, Width width) |
670 | { |
671 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgAdd, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
672 | m_heaps->decorateMemory(pointer.heap(), result); |
673 | return result; |
674 | } |
675 | |
676 | LValue Output::atomicXchgAnd(LValue operand, TypedPointer pointer, Width width) |
677 | { |
678 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgAnd, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
679 | m_heaps->decorateMemory(pointer.heap(), result); |
680 | return result; |
681 | } |
682 | |
683 | LValue Output::atomicXchgOr(LValue operand, TypedPointer pointer, Width width) |
684 | { |
685 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgOr, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
686 | m_heaps->decorateMemory(pointer.heap(), result); |
687 | return result; |
688 | } |
689 | |
690 | LValue Output::atomicXchgSub(LValue operand, TypedPointer pointer, Width width) |
691 | { |
692 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgSub, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
693 | m_heaps->decorateMemory(pointer.heap(), result); |
694 | return result; |
695 | } |
696 | |
697 | LValue Output::atomicXchgXor(LValue operand, TypedPointer pointer, Width width) |
698 | { |
699 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgXor, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
700 | m_heaps->decorateMemory(pointer.heap(), result); |
701 | return result; |
702 | } |
703 | |
704 | LValue Output::atomicXchg(LValue operand, TypedPointer pointer, Width width) |
705 | { |
706 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchg, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
707 | m_heaps->decorateMemory(pointer.heap(), result); |
708 | return result; |
709 | } |
710 | |
711 | LValue Output::atomicStrongCAS(LValue expected, LValue newValue, TypedPointer pointer, Width width) |
712 | { |
713 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicStrongCAS, origin(), width, expected, newValue, pointer.value(), 0, HeapRange(), HeapRange()); |
714 | m_heaps->decorateMemory(pointer.heap(), result); |
715 | return result; |
716 | } |
717 | |
718 | void Output::jump(LBasicBlock destination) |
719 | { |
720 | m_block->appendNewControlValue(m_proc, B3::Jump, origin(), B3::FrequentedBlock(destination)); |
721 | } |
722 | |
723 | void Output::branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight) |
724 | { |
725 | m_block->appendNewControlValue( |
726 | m_proc, B3::Branch, origin(), condition, |
727 | FrequentedBlock(taken, takenWeight.frequencyClass()), |
728 | FrequentedBlock(notTaken, notTakenWeight.frequencyClass())); |
729 | } |
730 | |
731 | void Output::check(LValue condition, WeightedTarget taken, Weight notTakenWeight) |
732 | { |
733 | LBasicBlock continuation = newBlock(); |
734 | branch(condition, taken, WeightedTarget(continuation, notTakenWeight)); |
735 | appendTo(continuation); |
736 | } |
737 | |
738 | void Output::check(LValue condition, WeightedTarget taken) |
739 | { |
740 | check(condition, taken, taken.weight().inverse()); |
741 | } |
742 | |
743 | void Output::ret(LValue value) |
744 | { |
745 | m_block->appendNewControlValue(m_proc, B3::Return, origin(), value); |
746 | } |
747 | |
748 | void Output::unreachable() |
749 | { |
750 | m_block->appendNewControlValue(m_proc, B3::Oops, origin()); |
751 | } |
752 | |
753 | void Output::appendSuccessor(WeightedTarget target) |
754 | { |
755 | m_block->appendSuccessor(target.frequentedBlock()); |
756 | } |
757 | |
758 | CheckValue* Output::speculate(LValue value) |
759 | { |
760 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::Check, origin(), value); |
761 | } |
762 | |
763 | CheckValue* Output::speculateAdd(LValue left, LValue right) |
764 | { |
765 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckAdd, origin(), left, right); |
766 | } |
767 | |
768 | CheckValue* Output::speculateSub(LValue left, LValue right) |
769 | { |
770 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckSub, origin(), left, right); |
771 | } |
772 | |
773 | CheckValue* Output::speculateMul(LValue left, LValue right) |
774 | { |
775 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckMul, origin(), left, right); |
776 | } |
777 | |
778 | PatchpointValue* Output::patchpoint(LType type) |
779 | { |
780 | return m_block->appendNew<B3::PatchpointValue>(m_proc, type, origin()); |
781 | } |
782 | |
783 | void Output::trap() |
784 | { |
785 | m_block->appendNewControlValue(m_proc, B3::Oops, origin()); |
786 | } |
787 | |
788 | ValueFromBlock Output::anchor(LValue value) |
789 | { |
790 | B3::UpsilonValue* upsilon = m_block->appendNew<B3::UpsilonValue>(m_proc, origin(), value); |
791 | return ValueFromBlock(upsilon, m_block); |
792 | } |
793 | |
794 | LValue Output::bitCast(LValue value, LType type) |
795 | { |
796 | ASSERT_UNUSED(type, type == Int64 || type == Double); |
797 | return m_block->appendNew<B3::Value>(m_proc, B3::BitwiseCast, origin(), value); |
798 | } |
799 | |
800 | LValue Output::fround(LValue doubleValue) |
801 | { |
802 | return floatToDouble(doubleToFloat(doubleValue)); |
803 | } |
804 | |
805 | LValue Output::load(TypedPointer pointer, LoadType type) |
806 | { |
807 | switch (type) { |
808 | case Load8SignExt32: |
809 | return load8SignExt32(pointer); |
810 | case Load8ZeroExt32: |
811 | return load8ZeroExt32(pointer); |
812 | case Load16SignExt32: |
813 | return load8SignExt32(pointer); |
814 | case Load16ZeroExt32: |
815 | return load8ZeroExt32(pointer); |
816 | case Load32: |
817 | return load32(pointer); |
818 | case Load64: |
819 | return load64(pointer); |
820 | case LoadPtr: |
821 | return loadPtr(pointer); |
822 | case LoadFloat: |
823 | return loadFloat(pointer); |
824 | case LoadDouble: |
825 | return loadDouble(pointer); |
826 | } |
827 | RELEASE_ASSERT_NOT_REACHED(); |
828 | return nullptr; |
829 | } |
830 | |
831 | LValue Output::store(LValue value, TypedPointer pointer, StoreType type) |
832 | { |
833 | switch (type) { |
834 | case Store32As8: |
835 | return store32As8(value, pointer); |
836 | case Store32As16: |
837 | return store32As16(value, pointer); |
838 | case Store32: |
839 | return store32(value, pointer); |
840 | case Store64: |
841 | return store64(value, pointer); |
842 | case StorePtr: |
843 | return storePtr(value, pointer); |
844 | case StoreFloat: |
845 | return storeFloat(value, pointer); |
846 | case StoreDouble: |
847 | return storeDouble(value, pointer); |
848 | } |
849 | RELEASE_ASSERT_NOT_REACHED(); |
850 | return nullptr; |
851 | } |
852 | |
853 | TypedPointer Output::absolute(const void* address) |
854 | { |
855 | return TypedPointer(m_heaps->absolute[address], constIntPtr(address)); |
856 | } |
857 | |
858 | void Output::incrementSuperSamplerCount() |
859 | { |
860 | TypedPointer counter = absolute(bitwise_cast<void*>(&g_superSamplerCount)); |
861 | store32(add(load32(counter), int32One), counter); |
862 | } |
863 | |
864 | void Output::decrementSuperSamplerCount() |
865 | { |
866 | TypedPointer counter = absolute(bitwise_cast<void*>(&g_superSamplerCount)); |
867 | store32(sub(load32(counter), int32One), counter); |
868 | } |
869 | |
870 | void Output::addIncomingToPhi(LValue phi, ValueFromBlock value) |
871 | { |
872 | if (value) |
873 | value.value()->as<B3::UpsilonValue>()->setPhi(phi); |
874 | } |
875 | |
876 | void Output::entrySwitch(const Vector<LBasicBlock>& cases) |
877 | { |
878 | RELEASE_ASSERT(cases.size() == m_proc.numEntrypoints()); |
879 | m_block->appendNew<Value>(m_proc, EntrySwitch, origin()); |
880 | for (LBasicBlock block : cases) |
881 | m_block->appendSuccessor(FrequentedBlock(block)); |
882 | } |
883 | |
884 | } } // namespace JSC::FTL |
885 | |
886 | #endif // ENABLE(FTL_JIT) |
887 | |
888 | |