1 # Copyright (C) 2012 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
28 # The CLoop llint backend is initially based on the ARMv7 backend, and
29 # then further enhanced with a few instructions from the x86 backend to
30 # support building for X64 targets. Hence, the shape of the generated
31 # code and the usage convention of registers will look a lot like the
34 def cloopMapType(type
)
46 when :nativeFunc; ".nativeFunc"
48 when :castToDouble; ".castToDouble"
49 when :castToInt64; ".castToInt64"
50 when :opcode; ".opcode"
52 raise "Unsupported type"
57 class SpecialRegister
< NoChildren
61 def clValue(type
=:int)
62 @name +
cloopMapType(type
)
66 C_LOOP_SCRATCH_FPR
= SpecialRegister
.new("d6")
94 raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
97 def clValue(type
=:int)
98 clDump +
cloopMapType(type
)
118 raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
121 def clValue(type
=:int)
122 clDump +
cloopMapType(type
)
130 def clValue(type
=:int)
131 # There is a case of a very large unsigned number (0x8000000000000000)
132 # which we wish to encode. Unfortunately, the C/C++ compiler
133 # complains if we express that number as a positive decimal integer.
134 # Hence, for positive values, we just convert the number into hex form
135 # to keep the compiler happy.
137 # However, for negative values, the to_s(16) hex conversion method does
138 # not strip the "-" sign resulting in a meaningless "0x-..." valueStr.
139 # To workaround this, we simply don't encode negative numbers as hex.
141 valueStr
= (value
< 0) ? "#{value}" : "0x#{value.to_s(16)}"
144 when :int8; "int8_t(#{valueStr})"
145 when :int32; "int32_t(#{valueStr})"
146 when :int64; "int64_t(#{valueStr})"
147 when :int; "intptr_t(#{valueStr})"
148 when :uint8; "uint8_t(#{valueStr})"
149 when :uint32; "uint32_t(#{valueStr})"
150 when :uint64; "uint64_t(#{valueStr})"
151 when :uint; "uintptr_t(#{valueStr})"
153 raise "Not implemented immediate of type: #{type}"
160 "[#{base.clDump}, #{offset.value}]"
162 def clValue(type
=:int)
164 when :int8; int8MemRef
165 when :int32; int32MemRef
166 when :int64; int64MemRef
168 when :uint8; uint8MemRef
169 when :uint32; uint32MemRef
170 when :uint64; uint64MemRef
171 when :uint; uintMemRef
172 when :opcode; opcodeMemRef
173 when :nativeFunc; nativeFuncMemRef
175 raise "Unexpected Address type: #{type}"
179 if base
.is_a
? RegisterID
and base
.name
== "sp"
180 offsetValue
= "#{offset.value}"
181 "(ASSERT(#{offsetValue} == offsetof(JITStackFrame, vm)), &sp->vm)"
182 elsif offset
.value
== 0
183 "#{base.clValue(:int8Ptr)}"
184 elsif offset
.value
> 0
185 "#{base.clValue(:int8Ptr)} + #{offset.value}"
187 "#{base.clValue(:int8Ptr)} - #{-offset.value}"
191 "*CAST
<int8_t
*>(#{pointerExpr})"
194 "*CAST
<int16_t
*>(#{pointerExpr})"
197 "*CAST
<int32_t
*>(#{pointerExpr})"
200 "*CAST
<int64_t
*>(#{pointerExpr})"
203 "*CAST
<intptr_t
*>(#{pointerExpr})"
206 "*CAST
<uint8_t
*>(#{pointerExpr})"
209 "*CAST
<uint16_t
*>(#{pointerExpr})"
212 "*CAST
<uint32_t
*>(#{pointerExpr})"
215 "*CAST
<uint64_t
*>(#{pointerExpr})"
218 "*CAST
<uintptr_t
*>(#{pointerExpr})"
221 "*CAST
<NativeFunction
*>(#{pointerExpr})"
224 "*CAST
<Opcode
*>(#{pointerExpr})"
227 "*CAST
<double
*>(#{pointerExpr})"
233 "[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
235 def clValue(type=:int)
237 when :int8; int8MemRef
238 when :int32; int32MemRef
239 when :int64; int64MemRef
241 when :uint8; uint8MemRef
242 when :uint32; uint32MemRef
243 when :uint64; uint64MemRef
244 when :uint; uintMemRef
245 when :opcode; opcodeMemRef
247 raise "Unexpected BaseIndex type
: #{type}"
251 if base.is_a? RegisterID and base.name == "sp
"
252 offsetValue = "(#{index.clValue} << #{scaleShift}) +
#{offset.clValue})"
253 "(ASSERT(#{offsetValue} == offsetof(JITStackFrame
, vm
)), &sp-
>vm
)"
255 "#{base.clValue(:int8Ptr)} +
(#{index.clValue} << #{scaleShift}) +
#{offset.clValue}"
259 "*CAST
<int8_t
*>(#{pointerExpr})"
262 "*CAST
<int16_t
*>(#{pointerExpr})"
265 "*CAST
<int32_t
*>(#{pointerExpr})"
268 "*CAST
<int64_t
*>(#{pointerExpr})"
271 "*CAST
<intptr_t
*>(#{pointerExpr})"
274 "*CAST
<uint8_t
*>(#{pointerExpr})"
277 "*CAST
<uint16_t
*>(#{pointerExpr})"
280 "*CAST
<uint32_t
*>(#{pointerExpr})"
283 "*CAST
<uint64_t
*>(#{pointerExpr})"
286 "*CAST
<uintptr_t
*>(#{pointerExpr})"
289 "*CAST
<Opcode
*>(#{pointerExpr})"
292 "*CAST
<double
*>(#{pointerExpr})"
296 class AbsoluteAddress
298 "#{codeOriginString}"
311 def cloopEmitLea(destination, type)
312 if destination == base
313 $asm.putc "#{destination.clValue(:int8Ptr)} +
= #{offset.clValue(type)};"
315 $asm.putc "#{destination.clValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} +
#{offset.clValue(type)};"
321 def cloopEmitLea(destination, type)
322 raise "Malformed BaseIndex
, offset should be zero at
#{codeOriginString}" unless offset.value == 0
323 $asm.putc "#{destination.clValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} +
(#{index.clValue} << #{scaleShift});"
328 # Actual lowering code follows.
332 def getModifiedListC_LOOP
335 # Verify that we will only see instructions and labels.
338 unless node.is_a? Instruction or
340 node.is_a? LocalLabel or
342 raise "Unexpected
#{node.inspect} at
#{node.codeOrigin}"
350 def clOperands(operands)
351 operands.map{|v| v.clDump}.join(", ")
355 def cloopEmitOperation(operands, type, operator)
356 raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || \
357 type == :int64 || type == :uint64 || type == :double
358 if operands.size == 3
359 $asm.putc "#{operands[2].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
360 if operands[2].is_a? RegisterID and (type == :int32 or type == :uint32)
361 $asm.putc "#{operands[2].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
364 raise unless operands.size == 2
365 raise unless not operands[1].is_a? Immediate
366 $asm.putc "#{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
367 if operands[1].is_a? RegisterID and (type == :int32 or type == :uint32)
368 $asm.putc "#{operands[1].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
373 def cloopEmitShiftOperation(operands, type, operator)
374 raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
375 if operands.size == 3
376 $asm.putc "#{operands[2].clValue(type)} = #{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:int)} & 0x1f);"
377 if operands[2].is_a? RegisterID and (type == :int32 or type == :uint32)
378 $asm.putc "#{operands[2].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
381 raise unless operands.size == 2
382 raise unless not operands[1].is_a? Immediate
383 $asm.putc "#{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:int)} & 0x1f);"
384 if operands[1].is_a? RegisterID and (type == :int32 or type == :uint32)
385 $asm.putc "#{operands[1].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
390 def cloopEmitUnaryOperation(operands, type, operator)
391 raise unless type == :int || type == :uint || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
392 raise unless operands.size == 1
393 raise unless not operands[0].is_a? Immediate
394 $asm.putc "#{operands[0].clValue(type)} = #{operator}#{operands[0].clValue(type)};"
395 if operands[0].is_a? RegisterID and (type == :int32 or type == :uint32)
396 $asm.putc "#{operands[0].clDump}.clearHighWord();" # Just clear it. It does nothing on the 32-bit port.
400 def cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, condition)
401 $asm.putc "if (std
::isnan(#{operands[0].clValue(:double)}) || isnan(#{operands[1].clValue(:double)})"
402 $asm.putc " || (#{operands[0].clValue(:double)} #{condition} #{operands[1].clValue(:double)}))"
403 $asm.putc " goto
#{operands[2].cLabel};"
407 def cloopEmitCompareAndSet(operands, type, comparator)
408 # The result is a boolean. Hence, it doesn't need to be based on the type
409 # of the arguments being compared.
410 $asm.putc "#{operands[2].clValue} = (#{operands[0].clValue(type)} #{comparator} #{op2 = operands[1].clValue(type)});"
414 def cloopEmitCompareAndBranch(operands, type, comparator)
415 $asm.putc "if (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)})"
416 $asm.putc " goto
#{operands[2].cLabel};"
420 # conditionTest should contain a string that provides a comparator and a RHS
422 def cloopGenerateConditionExpression(operands, type, conditionTest)
423 op1 = operands[0].clValue(type)
425 # The operands must consist of 2 or 3 values.
427 when 2 # Just test op1 against the conditionTest.
429 when 3 # Mask op1 with op2 before testing against the conditionTest.
430 lhs = "(#{op1} & #{operands[1].clValue(type)})"
432 raise "Expected
2 or 3 operands but got
#{operands.size} at
#{codeOriginString}"
435 "#{lhs} #{conditionTest}"
438 # conditionTest should contain a string that provides a comparator and a RHS
440 def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
441 conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
442 $asm.putc "if (#{conditionExpr})"
443 $asm.putc " goto
#{branchTarget};"
446 def cloopEmitTestSet(operands, type, conditionTest)
447 # The result is a boolean condition. Hence, the result type is always an
448 # int. The passed in type is only used for the values being tested in
449 # the condition test.
450 conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
451 $asm.putc "#{operands[-1].clValue} = (#{conditionExpr});"
454 def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
456 when :int; tempType = "intptr_t
"
457 when :int32; tempType = "int32_t
"
458 when :int64; tempType = "int64_t
"
460 raise "Unimplemented type
"
463 op1 = operands[0].clValue(type)
464 op2 = operands[1].clValue(type)
467 $asm.putc " #{tempType} temp
= #{op2} #{operator} #{op1};"
468 $asm.putc " #{op2} = temp
;"
469 $asm.putc " if (temp
#{conditionTest})"
470 $asm.putc " goto
#{operands[2].cLabel};"
474 def cloopAddOverflowTest(operands, type)
478 signBit = "SIGN_BIT32
"
480 raise "Unimplemented type
"
483 $asm.putc " #{tempType} a
= #{operands[0].clValue(type)};"
484 $asm.putc " #{tempType} b
= #{operands[1].clValue(type)};"
485 $asm.putc " // sign(b
) sign(a
) | Overflows
if:"
486 $asm.putc " // 0 0 | sign(b+a
) = 1 (pos + pos !
= neg
)"
487 $asm.putc " // 0 1 | never
"
488 $asm.putc " // 1 0 | never
"
489 $asm.putc " // 1 1 | sign(b+a
) = 0 (neg + neg !
= pos
)"
490 "((#{signBit}(b
) == #{signBit}(a
)) && (#{signBit}(b+a
) !
= #{signBit}(a
)))"
493 def cloopSubOverflowTest(operands, type)
497 signBit = "SIGN_BIT32
"
499 raise "Unimplemented type
"
502 $asm.putc " #{tempType} a
= #{operands[0].clValue(type)};"
503 $asm.putc " #{tempType} b
= #{operands[1].clValue(type)};"
504 $asm.putc " // sign(b
) sign(a
) | Overflows
if:"
505 $asm.putc " // 0 0 | never
"
506 $asm.putc " // 0 1 | sign(b-a
) = 1 (pos
- neg !
= pos
)"
507 $asm.putc " // 1 0 | sign(b-a
) = 0 (neg
- pos !
= pos
)"
508 $asm.putc " // 1 1 | never
"
509 "((#{signBit}(b
) !
= #{signBit}(a
)) && (#{signBit}(b-a
) == #{signBit}(a
)))"
512 def cloopMulOverflowTest(operands, type)
515 tempType = "uint32_t
"
517 raise "Unimplemented type
"
519 $asm.putc " #{tempType} a
= #{operands[0].clValue(type)};"
520 $asm.putc " #{tempType} b
= #{operands[1].clValue(type)};"
524 def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
527 # Emit the overflow test based on the operands and the type:
529 when "+
"; overflowTest = cloopAddOverflowTest(operands, type)
530 when "-"; overflowTest = cloopSubOverflowTest(operands, type)
531 when "*"; overflowTest = cloopMulOverflowTest(operands, type)
533 raise "Unimplemented opeartor
"
536 $asm.putc " bool didOverflow
= #{overflowTest};"
537 $asm.putc " #{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
538 $asm.putc " if (didOverflow
)"
539 $asm.putc " goto
#{operands[2].cLabel};"
543 # operands: callTarget, currentFrame, currentPC
544 def cloopEmitCallSlowPath(operands)
546 $asm.putc " ExecState
* exec
= CAST
<ExecState
*>(#{operands[1].clValue(:voidPtr)});"
547 $asm.putc " Instruction
* pc
= CAST
<Instruction
*>(#{operands[2].clValue(:voidPtr)});"
548 $asm.putc " SlowPathReturnType result
= #{operands[0].cLabel}(exec
, pc
);"
549 $asm.putc " LLInt
::decodeResult(result
, t0
.instruction
, t1
.execState
);"
555 $asm.codeOrigin codeOriginString if $enableCodeOriginComments
556 $asm.annotation annotation if $enableInstrAnnotations && (opcode != "cloopDo")
560 cloopEmitOperation(operands
, :int32, "+")
562 cloopEmitOperation(operands, :int64, "+
")
564 cloopEmitOperation(operands, :int, "+
")
567 cloopEmitOperation(operands, :int32, "&")
569 cloopEmitOperation(operands, :int64, "&")
571 cloopEmitOperation(operands, :int, "&")
574 cloopEmitOperation(operands, :int32, "|")
576 cloopEmitOperation(operands, :int64, "|")
578 cloopEmitOperation(operands, :int, "|")
581 cloopEmitOperation(operands, :int32, "^
")
583 cloopEmitOperation(operands, :int64, "^
")
585 cloopEmitOperation(operands, :int, "^
")
588 cloopEmitShiftOperation(operands, :int32, "<<")
590 cloopEmitShiftOperation(operands, :int64, "<<")
592 cloopEmitShiftOperation(operands, :int, "<<")
595 cloopEmitShiftOperation(operands, :int32, ">>")
597 cloopEmitShiftOperation(operands, :int64, ">>")
599 cloopEmitShiftOperation(operands, :int, ">>")
602 cloopEmitShiftOperation(operands, :uint32, ">>")
604 cloopEmitShiftOperation(operands, :uint64, ">>")
606 cloopEmitShiftOperation(operands, :uint, ">>")
609 cloopEmitOperation(operands, :int32, "*")
611 cloopEmitOperation(operands, :int64, "*")
613 cloopEmitOperation(operands, :int, "*")
616 cloopEmitOperation(operands, :int32, "-")
618 cloopEmitOperation(operands, :int64, "-")
620 cloopEmitOperation(operands, :int, "-")
623 cloopEmitUnaryOperation(operands, :int32, "-")
625 cloopEmitUnaryOperation(operands, :int64, "-")
627 cloopEmitUnaryOperation(operands, :int, "-")
630 cloopEmitUnaryOperation(operands, :int32, "!
")
633 $asm.putc "#{operands[1].clValue(:uint)} = #{operands[0].uint32MemRef};"
634 # There's no need to call clearHighWord() here because the above will
635 # automatically take care of 0 extension.
637 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int32MemRef};"
639 $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].int64MemRef};"
641 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].intMemRef};"
643 $asm.putc "#{operands[1].int32MemRef} = #{operands[0].clValue(:int32)};"
645 $asm.putc "#{operands[1].int64MemRef} = #{operands[0].clValue(:int64)};"
647 $asm.putc "#{operands[1].intMemRef} = #{operands[0].clValue(:int)};"
649 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].uint8MemRef};"
651 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int8MemRef};"
653 $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};"
655 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].uint16MemRef};"
657 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int16MemRef};"
659 $asm.putc "*#{operands[1].uint16MemRef} = #{operands[0].clValue(:int16)};"
661 $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].dblMemRef};"
663 $asm.putc "#{operands[1].dblMemRef} = #{operands[0].clValue(:double)};"
666 cloopEmitOperation(operands, :double, "+
")
668 cloopEmitOperation(operands, :double, "/")
670 cloopEmitOperation(operands, :double, "-")
672 cloopEmitOperation(operands, :double, "*")
674 # Convert an int value to its double equivalent, and store it in a double register.
676 $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].clValue(:int32)};"
679 cloopEmitCompareAndBranch(operands, :double, "==")
681 cloopEmitCompareAndBranch(operands, :double, "!
=")
683 cloopEmitCompareAndBranch(operands, :double, ">");
685 cloopEmitCompareAndBranch(operands, :double, ">=");
687 cloopEmitCompareAndBranch(operands, :double, "<");
689 cloopEmitCompareAndBranch(operands, :double, "<=");
692 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "==")
694 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "!
=")
696 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">")
698 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">=")
700 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<")
702 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<=")
705 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].clValue(:double)};"
706 $asm.putc "#{operands[1].clDump}.clearHighWord();"
708 when "bcd2i
" # operands: srcDbl dstInt slowPath
710 $asm.putc " double d
= #{operands[0].clValue(:double)};"
711 $asm.putc " const int32_t asInt32
= int32_t(d
);"
712 $asm.putc " if (asInt32 !
= d
|| (!asInt32
&& std
::signbit(d
))) // true for -0.0"
713 $asm.putc " goto
#{operands[2].cLabel};"
714 $asm.putc " #{operands[1].clValue} = asInt32
;"
715 $asm.putc " #{operands[1].clDump}.clearHighWord();"
719 $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].clValue(:int)};"
721 $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].clValue(:int32)};"
723 $asm.putc "#{operands[1].clValue(:uint64)} = #{operands[0].clValue(:uint32)};"
727 cloopEmitCompareAndBranch(operands, :int8, "==")
729 cloopEmitCompareAndBranch(operands, :int32, "==")
731 cloopEmitCompareAndBranch(operands, :int64, "==")
733 cloopEmitCompareAndBranch(operands, :int, "==")
736 cloopEmitCompareAndBranch(operands, :int8, "!
=")
738 cloopEmitCompareAndBranch(operands, :int32, "!
=")
740 cloopEmitCompareAndBranch(operands, :int64, "!
=")
742 cloopEmitCompareAndBranch(operands, :int, "!
=")
745 cloopEmitCompareAndBranch(operands, :uint8, ">")
747 cloopEmitCompareAndBranch(operands, :uint32, ">")
749 cloopEmitCompareAndBranch(operands, :uint64, ">")
751 cloopEmitCompareAndBranch(operands, :uint, ">")
754 cloopEmitCompareAndBranch(operands, :uint8, ">=")
756 cloopEmitCompareAndBranch(operands, :uint32, ">=")
758 cloopEmitCompareAndBranch(operands, :uint64, ">=")
760 cloopEmitCompareAndBranch(operands, :uint, ">=")
763 cloopEmitCompareAndBranch(operands, :uint8, "<")
765 cloopEmitCompareAndBranch(operands, :uint32, "<")
767 cloopEmitCompareAndBranch(operands, :uint64, "<")
769 cloopEmitCompareAndBranch(operands, :uint, "<")
772 cloopEmitCompareAndBranch(operands, :uint8, "<=")
774 cloopEmitCompareAndBranch(operands, :uint32, "<=")
776 cloopEmitCompareAndBranch(operands, :uint64, "<=")
778 cloopEmitCompareAndBranch(operands, :uint, "<=")
781 cloopEmitCompareAndBranch(operands, :int8, ">")
783 cloopEmitCompareAndBranch(operands, :int32, ">")
785 cloopEmitCompareAndBranch(operands, :int64, ">")
787 cloopEmitCompareAndBranch(operands, :int, ">")
790 cloopEmitCompareAndBranch(operands, :int8, ">=")
792 cloopEmitCompareAndBranch(operands, :int32, ">=")
794 cloopEmitCompareAndBranch(operands, :int64, ">=")
796 cloopEmitCompareAndBranch(operands, :int, ">=")
799 cloopEmitCompareAndBranch(operands, :int8, "<")
801 cloopEmitCompareAndBranch(operands, :int32, "<")
803 cloopEmitCompareAndBranch(operands, :int64, "<")
805 cloopEmitCompareAndBranch(operands, :int, "<")
808 cloopEmitCompareAndBranch(operands, :int8, "<=")
810 cloopEmitCompareAndBranch(operands, :int32, "<=")
812 cloopEmitCompareAndBranch(operands, :int64, "<=")
814 cloopEmitCompareAndBranch(operands, :int, "<=")
817 cloopEmitTestAndBranchIf(operands, :int8, "== 0", operands[-1].cLabel)
819 cloopEmitTestAndBranchIf(operands, :int32, "== 0", operands[-1].cLabel)
821 cloopEmitTestAndBranchIf(operands, :int64, "== 0", operands[-1].cLabel)
823 cloopEmitTestAndBranchIf(operands, :int, "== 0", operands[-1].cLabel)
826 cloopEmitTestAndBranchIf(operands, :int8, "!
= 0", operands[-1].cLabel)
828 cloopEmitTestAndBranchIf(operands, :int32, "!
= 0", operands[-1].cLabel)
830 cloopEmitTestAndBranchIf(operands, :int64, "!
= 0", operands[-1].cLabel)
832 cloopEmitTestAndBranchIf(operands, :int, "!
= 0", operands[-1].cLabel)
835 cloopEmitTestAndBranchIf(operands, :int8, "< 0", operands[-1].cLabel)
837 cloopEmitTestAndBranchIf(operands, :int32, "< 0", operands[-1].cLabel)
839 cloopEmitTestAndBranchIf(operands, :int64, "< 0", operands[-1].cLabel)
841 cloopEmitTestAndBranchIf(operands, :int, "< 0", operands[-1].cLabel)
843 # For jmp, we do not want to assume that we have COMPUTED_GOTO support.
844 # Fortunately, the only times we should ever encounter indirect jmps is
845 # when the jmp target is a CLoop opcode (by design).
847 # Hence, we check if the jmp target is a known label reference. If so,
848 # we can emit a goto directly. If it is not a known target, then we set
849 # the target in the opcode, and dispatch to it via whatever dispatch
850 # mechanism is in used.
852 if operands[0].is_a? LocalLabelReference or operands[0].is_a? LabelReference
853 # Handles jumps local or global labels.
854 $asm.putc "goto
#{operands[0].cLabel};"
856 # Handles jumps to some computed target.
857 # NOTE: must be an opcode handler or a llint glue helper.
858 $asm.putc "opcode
= #{operands[0].clValue(:opcode)};"
859 $asm.putc "DISPATCH_OPCODE();"
863 $asm.putc "CRASH(); // generic call instruction
not supported by design!
"
865 $asm.putc "CRASH(); // break instruction
not implemented
."
867 $asm.putc "goto doReturnHelper
;"
870 cloopEmitCompareAndSet(operands, :uint8, "==")
872 cloopEmitCompareAndSet(operands, :uint32, "==")
874 cloopEmitCompareAndSet(operands, :uint64, "==")
876 cloopEmitCompareAndSet(operands, :uint, "==")
879 cloopEmitCompareAndSet(operands, :uint8, "!
=")
881 cloopEmitCompareAndSet(operands, :uint32, "!
=")
883 cloopEmitCompareAndSet(operands, :uint64, "!
=")
885 cloopEmitCompareAndSet(operands, :uint, "!
=")
888 cloopEmitCompareAndSet(operands, :uint8, ">")
890 cloopEmitCompareAndSet(operands, :uint32, ">")
892 cloopEmitCompareAndSet(operands, :uint64, ">")
894 cloopEmitCompareAndSet(operands, :uint, ">")
897 cloopEmitCompareAndSet(operands, :uint8, ">=")
899 cloopEmitCompareAndSet(operands, :uint32, ">=")
901 cloopEmitCompareAndSet(operands, :uint64, ">=")
903 cloopEmitCompareAndSet(operands, :uint, ">=")
906 cloopEmitCompareAndSet(operands, :uint8, "<")
908 cloopEmitCompareAndSet(operands, :uint32, "<")
910 cloopEmitCompareAndSet(operands, :uint64, "<")
912 cloopEmitCompareAndSet(operands, :uint, "<")
915 cloopEmitCompareAndSet(operands, :uint8, "<=")
917 cloopEmitCompareAndSet(operands, :uint32, "<=")
919 cloopEmitCompareAndSet(operands, :uint64, "<=")
921 cloopEmitCompareAndSet(operands, :uint, "<=")
924 cloopEmitCompareAndSet(operands, :int8, ">")
926 cloopEmitCompareAndSet(operands, :int32, ">")
928 cloopEmitCompareAndSet(operands, :int64, ">")
930 cloopEmitCompareAndSet(operands, :int, ">")
933 cloopEmitCompareAndSet(operands, :int8, ">=")
935 cloopEmitCompareAndSet(operands, :int32, ">=")
937 cloopEmitCompareAndSet(operands, :int64, ">=")
939 cloopEmitCompareAndSet(operands, :int, ">=")
942 cloopEmitCompareAndSet(operands, :int8, "<")
944 cloopEmitCompareAndSet(operands, :int32, "<")
946 cloopEmitCompareAndSet(operands, :int64, "<")
948 cloopEmitCompareAndSet(operands, :int, "<")
951 cloopEmitCompareAndSet(operands, :int8, "<=")
953 cloopEmitCompareAndSet(operands, :int32, "<=")
955 cloopEmitCompareAndSet(operands, :int64, "<=")
957 cloopEmitCompareAndSet(operands, :int, "<=")
960 cloopEmitTestSet(operands, :int8, "< 0")
962 cloopEmitTestSet(operands, :int32, "< 0")
964 cloopEmitTestSet(operands, :int64, "< 0")
966 cloopEmitTestSet(operands, :int, "< 0")
969 cloopEmitTestSet(operands, :int8, "== 0")
971 cloopEmitTestSet(operands, :int32, "== 0")
973 cloopEmitTestSet(operands, :int64, "== 0")
975 cloopEmitTestSet(operands, :int, "== 0")
978 cloopEmitTestSet(operands, :int8, "!
= 0")
980 cloopEmitTestSet(operands, :int32, "!
= 0")
982 cloopEmitTestSet(operands, :int64, "!
= 0")
984 cloopEmitTestSet(operands, :int, "!
= 0")
986 # 64-bit instruction: cdqi (based on X64)
987 # Sign extends the lower 32 bits of t0, but put the sign extension into
988 # the lower 32 bits of t1. Leave the upper 32 bits of t0 and t1 unchanged.
991 $asm.putc " int64_t temp
= t0
.i32
; // sign
extend the low
32bit
"
992 $asm.putc " t0
.i32
= temp
; // low word
"
993 $asm.putc " t0
.clearHighWord();"
994 $asm.putc " t1
.i32
= uint64_t(temp
) >> 32; // high word
"
995 $asm.putc " t1
.clearHighWord();"
998 # 64-bit instruction: idivi op1 (based on X64)
999 # Divide a 64-bit integer numerator by the specified denominator.
1000 # The numerator is specified in t0 and t1 as follows:
1001 # 1. low 32 bits of the numerator is in the low 32 bits of t0.
1002 # 2. high 32 bits of the numerator is in the low 32 bits of t1.
1004 # The resultant quotient is a signed 32-bit int, and is to be stored
1005 # in the lower 32 bits of t0.
1006 # The resultant remainder is a signed 32-bit int, and is to be stored
1007 # in the lower 32 bits of t1.
1009 # Divide t1,t0 (EDX,EAX) by the specified arg, and store the remainder in t1,
1010 # and quotient in t0:
1012 $asm.putc " int64_t dividend
= (int64_t(t1
.u32
) << 32) | t0
.u32
;"
1013 $asm.putc " int64_t divisor
= #{operands[0].clValue(:int)};"
1014 $asm.putc " t1
.i32
= dividend
% divisor
; // remainder
"
1015 $asm.putc " t1
.clearHighWord();"
1016 $asm.putc " t0
.i32
= dividend
/ divisor; // quotient
"
1017 $asm.putc " t0
.clearHighWord();"
1020 # 32-bit instruction: fii2d int32LoOp int32HiOp dblOp (based on ARMv7)
1021 # Decode 2 32-bit ints (low and high) into a 64-bit double.
1023 $asm.putc "#{operands[2].clValue(:double)} = Ints2Double(#{operands[0].clValue(:uint32)}, #{operands[1].clValue(:uint32)});"
1025 # 32-bit instruction: f2dii dblOp int32LoOp int32HiOp (based on ARMv7)
1026 # Encode a 64-bit double into 2 32-bit ints (low and high).
1028 $asm.putc "Double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clValue(:uint32)}, #{operands[2].clValue(:uint32)});"
1030 # 64-bit instruction: fq2d int64Op dblOp (based on X64)
1031 # Copy a bit-encoded double in a 64-bit int register to a double register.
1033 $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].clValue(:castToDouble)};"
1035 # 64-bit instruction: fd2q dblOp int64Op (based on X64 instruction set)
1036 # Copy a double as a bit-encoded double into a 64-bit int register.
1038 $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].clValue(:castToInt64)};"
1041 operands[0].cloopEmitLea(operands[1], :int32)
1043 operands[0].cloopEmitLea(operands[1], :int)
1046 cloopEmitOpAndBranchIfOverflow(operands, "+
", :int32)
1048 cloopEmitOpAndBranchIfOverflow(operands, "-", :int32)
1050 cloopEmitOpAndBranchIfOverflow(operands, "*", :int32)
1053 cloopEmitOpAndBranch(operands, "+
", :int32, "< 0")
1055 cloopEmitOpAndBranch(operands, "+
", :int32, "== 0")
1057 cloopEmitOpAndBranch(operands, "+
", :int32, "!
= 0")
1060 cloopEmitOpAndBranch(operands, "+
", :int64, "< 0")
1062 cloopEmitOpAndBranch(operands, "+
", :int64, "== 0")
1064 cloopEmitOpAndBranch(operands, "+
", :int64, "!
= 0")
1067 cloopEmitOpAndBranch(operands, "+
", :int, "< 0")
1069 cloopEmitOpAndBranch(operands, "+
", :int, "== 0")
1071 cloopEmitOpAndBranch(operands, "+
", :int, "!
= 0")
1074 cloopEmitOpAndBranch(operands, "-", :int32, "< 0")
1076 cloopEmitOpAndBranch(operands, "-", :int32, "== 0")
1078 cloopEmitOpAndBranch(operands, "-", :int32, "!
= 0")
1081 cloopEmitOpAndBranch(operands, "|", :int32, "< 0")
1083 cloopEmitOpAndBranch(operands, "|", :int32, "== 0")
1085 cloopEmitOpAndBranch(operands, "|", :int32, "!
= 0")
1087 # A convenience and compact call to crash because we don't want to use
1088 # the generic llint crash mechanism which relies on the availability
1089 # of the call instruction (which cannot be implemented in a generic
1090 # way, and can be abused if we made it just work for this special case).
1091 # Using a special cloopCrash instruction is cleaner.
1093 $asm.putc "CRASH();"
1095 # We can't rely on the llint JS call mechanism which actually makes
1096 # use of the call instruction. Instead, we just implement JS calls
1097 # as an opcode dispatch.
1098 when "cloopCallJSFunction
"
1099 $asm.putc "opcode
= #{operands[0].clValue(:opcode)};"
1100 $asm.putc "DISPATCH_OPCODE();"
1102 # We can't do generic function calls with an arbitrary set of args, but
1103 # fortunately we don't have to here. All native function calls always
1104 # have a fixed prototype of 1 args: the passed ExecState.
1105 when "cloopCallNative
"
1106 $asm.putc "nativeFunc
= #{operands[0].clValue(:nativeFunc)};"
1107 $asm.putc "functionReturnValue
= JSValue
::decode(nativeFunc(t0
.execState
));"
1108 $asm.putc "#if USE(JSVALUE32_64)"
1109 $asm.putc
" t1.i = functionReturnValue.tag();"
1110 $asm.putc
" t0.i = functionReturnValue.payload();"
1111 $asm.putc
"#else // USE_JSVALUE64)"
1112 $asm.putc
" t0.encodedJSValue = JSValue::encode(functionReturnValue);"
1113 $asm.putc
"#endif // USE_JSVALUE64)"
1115 # We can't do generic function calls with an arbitrary set of args, but
1116 # fortunately we don't have to here. All slow path function calls always
1117 # have a fixed prototype too. See cloopEmitCallSlowPath() for details.
1118 when "cloopCallSlowPath"
1119 cloopEmitCallSlowPath(operands
)
1121 # For debugging only. This is used to insert instrumentation into the
1122 # generated LLIntAssembly.h during llint development only. Do not use
1123 # for production code.
1125 $asm.putc
"#{annotation}"