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::doubleToUInt(LValue value) |
337 | { |
338 | PatchpointValue* result = patchpoint(Int32); |
339 | result->append(value, ValueRep::SomeRegister); |
340 | result->setGenerator( |
341 | [] (CCallHelpers& jit, const StackmapGenerationParams& params) { |
342 | jit.truncateDoubleToUint32(params[1].fpr(), params[0].gpr()); |
343 | }); |
344 | result->effects = Effects::none(); |
345 | return result; |
346 | } |
347 | |
348 | LValue Output::signExt32To64(LValue value) |
349 | { |
350 | return m_block->appendNew<B3::Value>(m_proc, B3::SExt32, origin(), value); |
351 | } |
352 | |
353 | LValue Output::signExt32ToPtr(LValue value) |
354 | { |
355 | return signExt32To64(value); |
356 | } |
357 | |
358 | LValue Output::zeroExt(LValue value, LType type) |
359 | { |
360 | if (value->type() == type) |
361 | return value; |
362 | if (value->hasInt32()) |
363 | return m_block->appendIntConstant(m_proc, origin(), Int64, static_cast<uint64_t>(static_cast<uint32_t>(value->asInt32()))); |
364 | return m_block->appendNew<B3::Value>(m_proc, B3::ZExt32, origin(), value); |
365 | } |
366 | |
367 | LValue Output::intToDouble(LValue value) |
368 | { |
369 | return m_block->appendNew<B3::Value>(m_proc, B3::IToD, origin(), value); |
370 | } |
371 | |
372 | LValue Output::unsignedToDouble(LValue value) |
373 | { |
374 | return intToDouble(zeroExt(value, Int64)); |
375 | } |
376 | |
377 | LValue Output::castToInt32(LValue value) |
378 | { |
379 | if (value->type() == Int32) |
380 | return value; |
381 | if (value->hasInt64()) |
382 | return constInt32(static_cast<int32_t>(value->asInt64())); |
383 | return m_block->appendNew<B3::Value>(m_proc, B3::Trunc, origin(), value); |
384 | } |
385 | |
386 | LValue Output::doubleToFloat(LValue value) |
387 | { |
388 | return m_block->appendNew<B3::Value>(m_proc, B3::DoubleToFloat, origin(), value); |
389 | } |
390 | |
391 | LValue Output::floatToDouble(LValue value) |
392 | { |
393 | return m_block->appendNew<B3::Value>(m_proc, B3::FloatToDouble, origin(), value); |
394 | } |
395 | |
396 | LValue Output::load(TypedPointer pointer, LType type) |
397 | { |
398 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load, type, origin(), pointer.value()); |
399 | m_heaps->decorateMemory(pointer.heap(), load); |
400 | return load; |
401 | } |
402 | |
403 | LValue Output::load8SignExt32(TypedPointer pointer) |
404 | { |
405 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8S, Int32, origin(), pointer.value()); |
406 | m_heaps->decorateMemory(pointer.heap(), load); |
407 | return load; |
408 | } |
409 | |
410 | LValue Output::load8ZeroExt32(TypedPointer pointer) |
411 | { |
412 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8Z, Int32, origin(), pointer.value()); |
413 | m_heaps->decorateMemory(pointer.heap(), load); |
414 | return load; |
415 | } |
416 | |
417 | LValue Output::load16SignExt32(TypedPointer pointer) |
418 | { |
419 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16S, Int32, origin(), pointer.value()); |
420 | m_heaps->decorateMemory(pointer.heap(), load); |
421 | return load; |
422 | } |
423 | |
424 | LValue Output::load16ZeroExt32(TypedPointer pointer) |
425 | { |
426 | LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16Z, Int32, origin(), pointer.value()); |
427 | m_heaps->decorateMemory(pointer.heap(), load); |
428 | return load; |
429 | } |
430 | |
431 | LValue Output::store(LValue value, TypedPointer pointer) |
432 | { |
433 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store, origin(), value, pointer.value()); |
434 | m_heaps->decorateMemory(pointer.heap(), store); |
435 | return store; |
436 | } |
437 | |
438 | FenceValue* Output::fence(const AbstractHeap* read, const AbstractHeap* write) |
439 | { |
440 | FenceValue* result = m_block->appendNew<FenceValue>(m_proc, origin()); |
441 | m_heaps->decorateFenceRead(read, result); |
442 | m_heaps->decorateFenceWrite(write, result); |
443 | return result; |
444 | } |
445 | |
446 | LValue Output::store32As8(LValue value, TypedPointer pointer) |
447 | { |
448 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store8, origin(), value, pointer.value()); |
449 | m_heaps->decorateMemory(pointer.heap(), store); |
450 | return store; |
451 | } |
452 | |
453 | LValue Output::store32As16(LValue value, TypedPointer pointer) |
454 | { |
455 | LValue store = m_block->appendNew<MemoryValue>(m_proc, Store16, origin(), value, pointer.value()); |
456 | m_heaps->decorateMemory(pointer.heap(), store); |
457 | return store; |
458 | } |
459 | |
460 | LValue Output::baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset) |
461 | { |
462 | LValue accumulatedOffset; |
463 | |
464 | switch (scale) { |
465 | case ScaleOne: |
466 | accumulatedOffset = index; |
467 | break; |
468 | case ScaleTwo: |
469 | accumulatedOffset = shl(index, intPtrOne); |
470 | break; |
471 | case ScaleFour: |
472 | accumulatedOffset = shl(index, intPtrTwo); |
473 | break; |
474 | case ScaleEight: |
475 | case ScalePtr: |
476 | accumulatedOffset = shl(index, intPtrThree); |
477 | break; |
478 | } |
479 | |
480 | if (offset) |
481 | accumulatedOffset = add(accumulatedOffset, constIntPtr(offset)); |
482 | |
483 | return add(base, accumulatedOffset); |
484 | } |
485 | |
486 | LValue Output::equal(LValue left, LValue right) |
487 | { |
488 | TriState result = left->equalConstant(right); |
489 | if (result != MixedTriState) |
490 | return constBool(result == TrueTriState); |
491 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), left, right); |
492 | } |
493 | |
494 | LValue Output::notEqual(LValue left, LValue right) |
495 | { |
496 | TriState result = left->notEqualConstant(right); |
497 | if (result != MixedTriState) |
498 | return constBool(result == TrueTriState); |
499 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), left, right); |
500 | } |
501 | |
502 | LValue Output::above(LValue left, LValue right) |
503 | { |
504 | TriState result = left->aboveConstant(right); |
505 | if (result != MixedTriState) |
506 | return constBool(result == TrueTriState); |
507 | return m_block->appendNew<B3::Value>(m_proc, B3::Above, origin(), left, right); |
508 | } |
509 | |
510 | LValue Output::aboveOrEqual(LValue left, LValue right) |
511 | { |
512 | TriState result = left->aboveEqualConstant(right); |
513 | if (result != MixedTriState) |
514 | return constBool(result == TrueTriState); |
515 | return m_block->appendNew<B3::Value>(m_proc, B3::AboveEqual, origin(), left, right); |
516 | } |
517 | |
518 | LValue Output::below(LValue left, LValue right) |
519 | { |
520 | TriState result = left->belowConstant(right); |
521 | if (result != MixedTriState) |
522 | return constBool(result == TrueTriState); |
523 | return m_block->appendNew<B3::Value>(m_proc, B3::Below, origin(), left, right); |
524 | } |
525 | |
526 | LValue Output::belowOrEqual(LValue left, LValue right) |
527 | { |
528 | TriState result = left->belowEqualConstant(right); |
529 | if (result != MixedTriState) |
530 | return constBool(result == TrueTriState); |
531 | return m_block->appendNew<B3::Value>(m_proc, B3::BelowEqual, origin(), left, right); |
532 | } |
533 | |
534 | LValue Output::greaterThan(LValue left, LValue right) |
535 | { |
536 | TriState result = left->greaterThanConstant(right); |
537 | if (result != MixedTriState) |
538 | return constBool(result == TrueTriState); |
539 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterThan, origin(), left, right); |
540 | } |
541 | |
542 | LValue Output::greaterThanOrEqual(LValue left, LValue right) |
543 | { |
544 | TriState result = left->greaterEqualConstant(right); |
545 | if (result != MixedTriState) |
546 | return constBool(result == TrueTriState); |
547 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterEqual, origin(), left, right); |
548 | } |
549 | |
550 | LValue Output::lessThan(LValue left, LValue right) |
551 | { |
552 | TriState result = left->lessThanConstant(right); |
553 | if (result != MixedTriState) |
554 | return constBool(result == TrueTriState); |
555 | return m_block->appendNew<B3::Value>(m_proc, B3::LessThan, origin(), left, right); |
556 | } |
557 | |
558 | LValue Output::lessThanOrEqual(LValue left, LValue right) |
559 | { |
560 | TriState result = left->lessEqualConstant(right); |
561 | if (result != MixedTriState) |
562 | return constBool(result == TrueTriState); |
563 | return m_block->appendNew<B3::Value>(m_proc, B3::LessEqual, origin(), left, right); |
564 | } |
565 | |
566 | LValue Output::doubleEqual(LValue left, LValue right) |
567 | { |
568 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), left, right); |
569 | } |
570 | |
571 | LValue Output::doubleEqualOrUnordered(LValue left, LValue right) |
572 | { |
573 | return m_block->appendNew<B3::Value>(m_proc, B3::EqualOrUnordered, origin(), left, right); |
574 | } |
575 | |
576 | LValue Output::doubleNotEqualOrUnordered(LValue left, LValue right) |
577 | { |
578 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), left, right); |
579 | } |
580 | |
581 | LValue Output::doubleLessThan(LValue left, LValue right) |
582 | { |
583 | return m_block->appendNew<B3::Value>(m_proc, B3::LessThan, origin(), left, right); |
584 | } |
585 | |
586 | LValue Output::doubleLessThanOrEqual(LValue left, LValue right) |
587 | { |
588 | return m_block->appendNew<B3::Value>(m_proc, B3::LessEqual, origin(), left, right); |
589 | } |
590 | |
591 | LValue Output::doubleGreaterThan(LValue left, LValue right) |
592 | { |
593 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterThan, origin(), left, right); |
594 | } |
595 | |
596 | LValue Output::doubleGreaterThanOrEqual(LValue left, LValue right) |
597 | { |
598 | return m_block->appendNew<B3::Value>(m_proc, B3::GreaterEqual, origin(), left, right); |
599 | } |
600 | |
601 | LValue Output::doubleNotEqualAndOrdered(LValue left, LValue right) |
602 | { |
603 | return logicalNot(doubleEqualOrUnordered(left, right)); |
604 | } |
605 | |
606 | LValue Output::doubleLessThanOrUnordered(LValue left, LValue right) |
607 | { |
608 | return logicalNot(doubleGreaterThanOrEqual(left, right)); |
609 | } |
610 | |
611 | LValue Output::doubleLessThanOrEqualOrUnordered(LValue left, LValue right) |
612 | { |
613 | return logicalNot(doubleGreaterThan(left, right)); |
614 | } |
615 | |
616 | LValue Output::doubleGreaterThanOrUnordered(LValue left, LValue right) |
617 | { |
618 | return logicalNot(doubleLessThanOrEqual(left, right)); |
619 | } |
620 | |
621 | LValue Output::doubleGreaterThanOrEqualOrUnordered(LValue left, LValue right) |
622 | { |
623 | return logicalNot(doubleLessThan(left, right)); |
624 | } |
625 | |
626 | LValue Output::isZero32(LValue value) |
627 | { |
628 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int32Zero); |
629 | } |
630 | |
631 | LValue Output::notZero32(LValue value) |
632 | { |
633 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), value, int32Zero); |
634 | } |
635 | |
636 | LValue Output::isZero64(LValue value) |
637 | { |
638 | return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int64Zero); |
639 | } |
640 | |
641 | LValue Output::notZero64(LValue value) |
642 | { |
643 | return m_block->appendNew<B3::Value>(m_proc, B3::NotEqual, origin(), value, int64Zero); |
644 | } |
645 | |
646 | LValue Output::select(LValue value, LValue taken, LValue notTaken) |
647 | { |
648 | if (value->hasInt32()) { |
649 | if (value->asInt32()) |
650 | return taken; |
651 | else |
652 | return notTaken; |
653 | } |
654 | return m_block->appendNew<B3::Value>(m_proc, B3::Select, origin(), value, taken, notTaken); |
655 | } |
656 | |
657 | LValue Output::atomicXchgAdd(LValue operand, TypedPointer pointer, Width width) |
658 | { |
659 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgAdd, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
660 | m_heaps->decorateMemory(pointer.heap(), result); |
661 | return result; |
662 | } |
663 | |
664 | LValue Output::atomicXchgAnd(LValue operand, TypedPointer pointer, Width width) |
665 | { |
666 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgAnd, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
667 | m_heaps->decorateMemory(pointer.heap(), result); |
668 | return result; |
669 | } |
670 | |
671 | LValue Output::atomicXchgOr(LValue operand, TypedPointer pointer, Width width) |
672 | { |
673 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgOr, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
674 | m_heaps->decorateMemory(pointer.heap(), result); |
675 | return result; |
676 | } |
677 | |
678 | LValue Output::atomicXchgSub(LValue operand, TypedPointer pointer, Width width) |
679 | { |
680 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgSub, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
681 | m_heaps->decorateMemory(pointer.heap(), result); |
682 | return result; |
683 | } |
684 | |
685 | LValue Output::atomicXchgXor(LValue operand, TypedPointer pointer, Width width) |
686 | { |
687 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchgXor, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
688 | m_heaps->decorateMemory(pointer.heap(), result); |
689 | return result; |
690 | } |
691 | |
692 | LValue Output::atomicXchg(LValue operand, TypedPointer pointer, Width width) |
693 | { |
694 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicXchg, origin(), width, operand, pointer.value(), 0, HeapRange(), HeapRange()); |
695 | m_heaps->decorateMemory(pointer.heap(), result); |
696 | return result; |
697 | } |
698 | |
699 | LValue Output::atomicStrongCAS(LValue expected, LValue newValue, TypedPointer pointer, Width width) |
700 | { |
701 | LValue result = m_block->appendNew<AtomicValue>(m_proc, AtomicStrongCAS, origin(), width, expected, newValue, pointer.value(), 0, HeapRange(), HeapRange()); |
702 | m_heaps->decorateMemory(pointer.heap(), result); |
703 | return result; |
704 | } |
705 | |
706 | void Output::jump(LBasicBlock destination) |
707 | { |
708 | m_block->appendNewControlValue(m_proc, B3::Jump, origin(), B3::FrequentedBlock(destination)); |
709 | } |
710 | |
711 | void Output::branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight) |
712 | { |
713 | m_block->appendNewControlValue( |
714 | m_proc, B3::Branch, origin(), condition, |
715 | FrequentedBlock(taken, takenWeight.frequencyClass()), |
716 | FrequentedBlock(notTaken, notTakenWeight.frequencyClass())); |
717 | } |
718 | |
719 | void Output::check(LValue condition, WeightedTarget taken, Weight notTakenWeight) |
720 | { |
721 | LBasicBlock continuation = newBlock(); |
722 | branch(condition, taken, WeightedTarget(continuation, notTakenWeight)); |
723 | appendTo(continuation); |
724 | } |
725 | |
726 | void Output::check(LValue condition, WeightedTarget taken) |
727 | { |
728 | check(condition, taken, taken.weight().inverse()); |
729 | } |
730 | |
731 | void Output::ret(LValue value) |
732 | { |
733 | m_block->appendNewControlValue(m_proc, B3::Return, origin(), value); |
734 | } |
735 | |
736 | void Output::unreachable() |
737 | { |
738 | m_block->appendNewControlValue(m_proc, B3::Oops, origin()); |
739 | } |
740 | |
741 | void Output::appendSuccessor(WeightedTarget target) |
742 | { |
743 | m_block->appendSuccessor(target.frequentedBlock()); |
744 | } |
745 | |
746 | CheckValue* Output::speculate(LValue value) |
747 | { |
748 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::Check, origin(), value); |
749 | } |
750 | |
751 | CheckValue* Output::speculateAdd(LValue left, LValue right) |
752 | { |
753 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckAdd, origin(), left, right); |
754 | } |
755 | |
756 | CheckValue* Output::speculateSub(LValue left, LValue right) |
757 | { |
758 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckSub, origin(), left, right); |
759 | } |
760 | |
761 | CheckValue* Output::speculateMul(LValue left, LValue right) |
762 | { |
763 | return m_block->appendNew<B3::CheckValue>(m_proc, B3::CheckMul, origin(), left, right); |
764 | } |
765 | |
766 | PatchpointValue* Output::patchpoint(LType type) |
767 | { |
768 | return m_block->appendNew<B3::PatchpointValue>(m_proc, type, origin()); |
769 | } |
770 | |
771 | void Output::trap() |
772 | { |
773 | m_block->appendNewControlValue(m_proc, B3::Oops, origin()); |
774 | } |
775 | |
776 | ValueFromBlock Output::anchor(LValue value) |
777 | { |
778 | B3::UpsilonValue* upsilon = m_block->appendNew<B3::UpsilonValue>(m_proc, origin(), value); |
779 | return ValueFromBlock(upsilon, m_block); |
780 | } |
781 | |
782 | LValue Output::bitCast(LValue value, LType type) |
783 | { |
784 | ASSERT_UNUSED(type, type == Int64 || type == Double); |
785 | return m_block->appendNew<B3::Value>(m_proc, B3::BitwiseCast, origin(), value); |
786 | } |
787 | |
788 | LValue Output::fround(LValue doubleValue) |
789 | { |
790 | return floatToDouble(doubleToFloat(doubleValue)); |
791 | } |
792 | |
793 | LValue Output::load(TypedPointer pointer, LoadType type) |
794 | { |
795 | switch (type) { |
796 | case Load8SignExt32: |
797 | return load8SignExt32(pointer); |
798 | case Load8ZeroExt32: |
799 | return load8ZeroExt32(pointer); |
800 | case Load16SignExt32: |
801 | return load8SignExt32(pointer); |
802 | case Load16ZeroExt32: |
803 | return load8ZeroExt32(pointer); |
804 | case Load32: |
805 | return load32(pointer); |
806 | case Load64: |
807 | return load64(pointer); |
808 | case LoadPtr: |
809 | return loadPtr(pointer); |
810 | case LoadFloat: |
811 | return loadFloat(pointer); |
812 | case LoadDouble: |
813 | return loadDouble(pointer); |
814 | } |
815 | RELEASE_ASSERT_NOT_REACHED(); |
816 | return nullptr; |
817 | } |
818 | |
819 | LValue Output::store(LValue value, TypedPointer pointer, StoreType type) |
820 | { |
821 | switch (type) { |
822 | case Store32As8: |
823 | return store32As8(value, pointer); |
824 | case Store32As16: |
825 | return store32As16(value, pointer); |
826 | case Store32: |
827 | return store32(value, pointer); |
828 | case Store64: |
829 | return store64(value, pointer); |
830 | case StorePtr: |
831 | return storePtr(value, pointer); |
832 | case StoreFloat: |
833 | return storeFloat(value, pointer); |
834 | case StoreDouble: |
835 | return storeDouble(value, pointer); |
836 | } |
837 | RELEASE_ASSERT_NOT_REACHED(); |
838 | return nullptr; |
839 | } |
840 | |
841 | TypedPointer Output::absolute(const void* address) |
842 | { |
843 | return TypedPointer(m_heaps->absolute[address], constIntPtr(address)); |
844 | } |
845 | |
846 | void Output::incrementSuperSamplerCount() |
847 | { |
848 | TypedPointer counter = absolute(bitwise_cast<void*>(&g_superSamplerCount)); |
849 | store32(add(load32(counter), int32One), counter); |
850 | } |
851 | |
852 | void Output::decrementSuperSamplerCount() |
853 | { |
854 | TypedPointer counter = absolute(bitwise_cast<void*>(&g_superSamplerCount)); |
855 | store32(sub(load32(counter), int32One), counter); |
856 | } |
857 | |
858 | void Output::addIncomingToPhi(LValue phi, ValueFromBlock value) |
859 | { |
860 | if (value) |
861 | value.value()->as<B3::UpsilonValue>()->setPhi(phi); |
862 | } |
863 | |
864 | void Output::entrySwitch(const Vector<LBasicBlock>& cases) |
865 | { |
866 | RELEASE_ASSERT(cases.size() == m_proc.numEntrypoints()); |
867 | m_block->appendNew<Value>(m_proc, EntrySwitch, origin()); |
868 | for (LBasicBlock block : cases) |
869 | m_block->appendSuccessor(FrequentedBlock(block)); |
870 | } |
871 | |
872 | } } // namespace JSC::FTL |
873 | |
874 | #endif // ENABLE(FTL_JIT) |
875 | |
876 | |