1# Copyright (C) 2012 Apple Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions
5# are met:
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.
11#
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.
23
24require "config"
25require "ast"
26require "opt"
27
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
32# ARMv7 backend's.
33
34def cloopMapType(type)
35    case type
36    when :int;            ".i"
37    when :uint;           ".u"
38    when :int32;          ".i32"
39    when :uint32;         ".u32"
40    when :int64;          ".i64"
41    when :uint64;         ".u64"
42    when :int8;           ".i8"
43    when :uint8;          ".u8"
44    when :int8Ptr;        ".i8p"
45    when :voidPtr;        ".vp"
46    when :nativeFunc;     ".nativeFunc"
47    when :double;         ".d"
48    when :castToDouble;   ".castToDouble"
49    when :castToInt64;    ".castToInt64"
50    when :opcode;         ".opcode"
51    else;
52        raise "Unsupported type"
53    end
54end
55
56
57class SpecialRegister < NoChildren
58    def clDump
59        @name
60    end
61    def clValue(type=:int)
62        @name + cloopMapType(type)
63    end
64end
65
66C_LOOP_SCRATCH_FPR = SpecialRegister.new("d6")
67
68class RegisterID
69    def clDump
70        case name
71        when "t0"
72            "t0"
73        when "t1"
74            "t1"
75        when "t2"
76            "t2"
77        when "t3"
78            "t3"
79        when "t4"
80            "rPC"
81        when "t6"
82            "rBasePC"
83        when "csr1"
84            "tagTypeNumber"
85        when "csr2"
86            "tagMask"
87        when "cfr"
88            "cfr"
89        when "lr"
90            "rRetVPC"
91        when "sp"
92            "sp"
93        else
94            raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
95        end
96    end
97    def clValue(type=:int)
98        clDump + cloopMapType(type)
99    end
100end
101
102class FPRegisterID
103    def clDump
104        case name
105        when "ft0", "fr"
106            "d0"
107        when "ft1"
108            "d1"
109        when "ft2"
110            "d2"
111        when "ft3"
112            "d3"
113        when "ft4"
114            "d4"
115        when "ft5"
116            "d5"
117        else
118            raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
119        end
120    end
121    def clValue(type=:int)
122        clDump + cloopMapType(type)
123    end
124end
125
126class Immediate
127    def clDump
128        "#{value}"
129    end
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.
136        #
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.
140
141        valueStr = (value < 0) ? "#{value}" : "0x#{value.to_s(16)}"
142
143        case type
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})"
152        else
153            raise "Not implemented immediate of type: #{type}" 
154        end
155    end
156end
157
158class Address
159    def clDump
160        "[#{base.clDump}, #{offset.value}]"
161    end
162    def clValue(type=:int)
163        case type
164        when :int8;         int8MemRef
165        when :int32;        int32MemRef
166        when :int64;        int64MemRef
167        when :int;          intMemRef
168        when :uint8;        uint8MemRef
169        when :uint32;       uint32MemRef
170        when :uint64;       uint64MemRef
171        when :uint;         uintMemRef
172        when :opcode;       opcodeMemRef
173        when :nativeFunc;   nativeFuncMemRef
174        else
175            raise "Unexpected Address type: #{type}"
176        end
177    end
178    def pointerExpr
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}"
186        else
187            "#{base.clValue(:int8Ptr)} - #{-offset.value}"
188        end
189    end
190    def int8MemRef
191        "*CAST<int8_t*>(#{pointerExpr})"
192    end
193    def int16MemRef
194        "*CAST<int16_t*>(#{pointerExpr})"
195    end
196    def int32MemRef
197        "*CAST<int32_t*>(#{pointerExpr})"
198    end
199    def int64MemRef
200        "*CAST<int64_t*>(#{pointerExpr})"
201    end
202    def intMemRef
203        "*CAST<intptr_t*>(#{pointerExpr})"
204    end
205    def uint8MemRef
206        "*CAST<uint8_t*>(#{pointerExpr})"
207    end
208    def uint16MemRef
209        "*CAST<uint16_t*>(#{pointerExpr})"
210    end
211    def uint32MemRef
212        "*CAST<uint32_t*>(#{pointerExpr})"
213    end
214    def uint64MemRef
215        "*CAST<uint64_t*>(#{pointerExpr})"
216    end
217    def uintMemRef
218        "*CAST<uintptr_t*>(#{pointerExpr})"
219    end
220    def nativeFuncMemRef
221        "*CAST<NativeFunction*>(#{pointerExpr})"
222    end
223    def opcodeMemRef
224        "*CAST<Opcode*>(#{pointerExpr})"
225    end
226    def dblMemRef
227        "*CAST<double*>(#{pointerExpr})"
228    end
229end
230
231class BaseIndex
232    def clDump
233        "[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
234    end
235    def clValue(type=:int)
236        case type
237        when :int8;       int8MemRef
238        when :int32;      int32MemRef
239        when :int64;      int64MemRef
240        when :int;        intMemRef
241        when :uint8;      uint8MemRef
242        when :uint32;     uint32MemRef
243        when :uint64;     uint64MemRef
244        when :uint;       uintMemRef
245        when :opcode;     opcodeMemRef
246        else
247            raise "Unexpected BaseIndex type: #{type}"
248        end
249    end
250    def pointerExpr
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)"
254        else
255            "#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift}) + #{offset.clValue}"
256        end
257    end
258    def int8MemRef
259        "*CAST<int8_t*>(#{pointerExpr})"
260    end
261    def int16MemRef
262        "*CAST<int16_t*>(#{pointerExpr})"
263    end
264    def int32MemRef
265        "*CAST<int32_t*>(#{pointerExpr})"
266    end
267    def int64MemRef
268        "*CAST<int64_t*>(#{pointerExpr})"
269    end
270    def intMemRef
271        "*CAST<intptr_t*>(#{pointerExpr})"
272    end
273    def uint8MemRef
274        "*CAST<uint8_t*>(#{pointerExpr})"
275    end
276    def uint16MemRef
277        "*CAST<uint16_t*>(#{pointerExpr})"
278    end
279    def uint32MemRef
280        "*CAST<uint32_t*>(#{pointerExpr})"
281    end
282    def uint64MemRef
283        "*CAST<uint64_t*>(#{pointerExpr})"
284    end
285    def uintMemRef
286        "*CAST<uintptr_t*>(#{pointerExpr})"
287    end
288    def opcodeMemRef
289        "*CAST<Opcode*>(#{pointerExpr})"
290    end
291    def dblMemRef
292        "*CAST<double*>(#{pointerExpr})"
293    end
294end
295
296class AbsoluteAddress
297    def clDump
298        "#{codeOriginString}"
299    end
300    def clValue
301        clDump
302    end
303end
304
305
306#
307# Lea support.
308#
309
310class Address
311    def cloopEmitLea(destination, type)
312        if destination == base
313            $asm.putc "#{destination.clValue(:int8Ptr)} += #{offset.clValue(type)};"
314        else
315            $asm.putc "#{destination.clValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + #{offset.clValue(type)};"
316        end
317    end
318end
319
320class BaseIndex
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});"
324    end
325end
326
327#
328# Actual lowering code follows.
329#
330
331class Sequence
332    def getModifiedListC_LOOP
333        myList = @list
334        
335        # Verify that we will only see instructions and labels.
336        myList.each {
337            | node |
338            unless node.is_a? Instruction or
339                    node.is_a? Label or
340                    node.is_a? LocalLabel or
341                    node.is_a? Skip
342                raise "Unexpected #{node.inspect} at #{node.codeOrigin}" 
343            end
344        }
345        
346        return myList
347    end
348end
349
350def clOperands(operands)
351    operands.map{|v| v.clDump}.join(", ")
352end
353
354
355def 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.
362        end
363    else
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.
369        end
370    end
371end
372
373def 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.
379        end
380    else
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.
386        end
387    end
388end
389
390def 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.
397    end
398end
399
400def 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};"
404end
405
406
407def 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)});"
411end
412
413
414def cloopEmitCompareAndBranch(operands, type, comparator)
415    $asm.putc "if (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)})"
416    $asm.putc "    goto #{operands[2].cLabel};"
417end
418
419
420# conditionTest should contain a string that provides a comparator and a RHS
421# value e.g. "< 0".
422def cloopGenerateConditionExpression(operands, type, conditionTest)
423    op1 = operands[0].clValue(type)
424
425    # The operands must consist of 2 or 3 values.
426    case operands.size
427    when 2 # Just test op1 against the conditionTest.
428        lhs = op1
429    when 3 # Mask op1 with op2 before testing against the conditionTest.
430        lhs = "(#{op1} & #{operands[1].clValue(type)})"
431    else
432        raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
433    end
434    
435    "#{lhs} #{conditionTest}"
436end
437
438# conditionTest should contain a string that provides a comparator and a RHS
439# value e.g. "< 0".
440def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
441    conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
442    $asm.putc "if (#{conditionExpr})"
443    $asm.putc "    goto #{branchTarget};"
444end
445
446def 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});"
452end
453
454def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
455    case type
456    when :int;   tempType = "intptr_t"
457    when :int32; tempType = "int32_t"
458    when :int64; tempType = "int64_t"
459    else
460        raise "Unimplemented type"
461    end
462
463    op1 = operands[0].clValue(type)
464    op2 = operands[1].clValue(type)
465
466    $asm.putc "{"
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};"
471    $asm.putc "}"
472end
473
474def cloopAddOverflowTest(operands, type)
475    case type
476    when :int32
477        tempType = "int32_t"
478        signBit = "SIGN_BIT32"
479    else
480        raise "Unimplemented type"
481    end
482
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)))"
491end
492
493def cloopSubOverflowTest(operands, type)
494    case type
495    when :int32
496        tempType = "int32_t"
497        signBit = "SIGN_BIT32"
498    else
499        raise "Unimplemented type"
500    end
501
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)))"
510end
511
512def cloopMulOverflowTest(operands, type)
513    case type
514    when :int32
515        tempType = "uint32_t"
516    else
517        raise "Unimplemented type"
518    end
519    $asm.putc "    #{tempType} a = #{operands[0].clValue(type)};"
520    $asm.putc "    #{tempType} b = #{operands[1].clValue(type)};"
521    "((b | a) >> 15)"
522end
523
524def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
525    $asm.putc "{"
526
527    # Emit the overflow test based on the operands and the type:
528    case operator
529    when "+"; overflowTest = cloopAddOverflowTest(operands, type)
530    when "-"; overflowTest = cloopSubOverflowTest(operands, type)
531    when "*"; overflowTest = cloopMulOverflowTest(operands, type)
532    else
533        raise "Unimplemented opeartor"
534    end
535
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};"
540    $asm.putc "}"
541end
542
543# operands: callTarget, currentFrame, currentPC
544def cloopEmitCallSlowPath(operands)
545    $asm.putc "{"
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);"
550    $asm.putc "}"
551end
552
553class Instruction
554    def lowerC_LOOP
555        $asm.codeOrigin codeOriginString if $enableCodeOriginComments
556        $asm.annotation annotation if $enableInstrAnnotations && (opcode != "cloopDo")
557
558        case opcode
559        when "addi"
560            cloopEmitOperation(operands, :int32, "+")
561        when "addq"
562            cloopEmitOperation(operands, :int64, "+")
563        when "addp"
564            cloopEmitOperation(operands, :int, "+")
565
566        when "andi"
567            cloopEmitOperation(operands, :int32, "&")
568        when "andq"
569            cloopEmitOperation(operands, :int64, "&")
570        when "andp"
571            cloopEmitOperation(operands, :int, "&")
572
573        when "ori"
574            cloopEmitOperation(operands, :int32, "|")
575        when "orq"
576            cloopEmitOperation(operands, :int64, "|")
577        when "orp"
578            cloopEmitOperation(operands, :int, "|")
579
580        when "xori"
581            cloopEmitOperation(operands, :int32, "^")
582        when "xorq"
583            cloopEmitOperation(operands, :int64, "^")
584        when "xorp"
585            cloopEmitOperation(operands, :int, "^")
586
587        when "lshifti"
588            cloopEmitShiftOperation(operands, :int32, "<<")
589        when "lshiftq"
590            cloopEmitShiftOperation(operands, :int64, "<<")
591        when "lshiftp"
592            cloopEmitShiftOperation(operands, :int, "<<")
593
594        when "rshifti"
595            cloopEmitShiftOperation(operands, :int32, ">>")
596        when "rshiftq"
597            cloopEmitShiftOperation(operands, :int64, ">>")
598        when "rshiftp"
599            cloopEmitShiftOperation(operands, :int, ">>")
600
601        when "urshifti"
602            cloopEmitShiftOperation(operands, :uint32, ">>")
603        when "urshiftq"
604            cloopEmitShiftOperation(operands, :uint64, ">>")
605        when "urshiftp"
606            cloopEmitShiftOperation(operands, :uint, ">>")
607
608        when "muli"
609            cloopEmitOperation(operands, :int32, "*")
610        when "mulq"
611            cloopEmitOperation(operands, :int64, "*")
612        when "mulp"
613            cloopEmitOperation(operands, :int, "*")
614
615        when "subi"
616            cloopEmitOperation(operands, :int32, "-")
617        when "subq"
618            cloopEmitOperation(operands, :int64, "-")
619        when "subp"
620            cloopEmitOperation(operands, :int, "-")
621
622        when "negi"
623            cloopEmitUnaryOperation(operands, :int32, "-")
624        when "negq"
625            cloopEmitUnaryOperation(operands, :int64, "-")
626        when "negp"
627            cloopEmitUnaryOperation(operands, :int, "-")
628
629        when "noti"
630            cloopEmitUnaryOperation(operands, :int32, "!")
631
632        when "loadi"
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.
636        when "loadis"
637            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int32MemRef};"
638        when "loadq"
639            $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].int64MemRef};"
640        when "loadp"
641            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].intMemRef};"
642        when "storei"
643            $asm.putc "#{operands[1].int32MemRef} = #{operands[0].clValue(:int32)};"
644        when "storeq"
645            $asm.putc "#{operands[1].int64MemRef} = #{operands[0].clValue(:int64)};"
646        when "storep"
647            $asm.putc "#{operands[1].intMemRef} = #{operands[0].clValue(:int)};"
648        when "loadb"
649            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].uint8MemRef};"
650        when "loadbs"
651            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int8MemRef};"
652        when "storeb"
653            $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};"
654        when "loadh"
655            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].uint16MemRef};"
656        when "loadhs"
657            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].int16MemRef};"
658        when "storeh"
659            $asm.putc "*#{operands[1].uint16MemRef} = #{operands[0].clValue(:int16)};"
660        when "loadd"
661            $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].dblMemRef};"
662        when "stored"
663            $asm.putc "#{operands[1].dblMemRef} = #{operands[0].clValue(:double)};"
664
665        when "addd"
666            cloopEmitOperation(operands, :double, "+")
667        when "divd"
668            cloopEmitOperation(operands, :double, "/")
669        when "subd"
670            cloopEmitOperation(operands, :double, "-")
671        when "muld"
672            cloopEmitOperation(operands, :double, "*")
673
674        # Convert an int value to its double equivalent, and store it in a double register.
675        when "ci2d"
676            $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].clValue(:int32)};"
677            
678        when "bdeq"
679            cloopEmitCompareAndBranch(operands, :double, "==")
680        when "bdneq"
681            cloopEmitCompareAndBranch(operands, :double, "!=")
682        when "bdgt"
683            cloopEmitCompareAndBranch(operands, :double, ">");
684        when "bdgteq"
685            cloopEmitCompareAndBranch(operands, :double, ">=");
686        when "bdlt"
687            cloopEmitCompareAndBranch(operands, :double, "<");
688        when "bdlteq"
689            cloopEmitCompareAndBranch(operands, :double, "<=");
690
691        when "bdequn"
692            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "==")
693        when "bdnequn"
694            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "!=")
695        when "bdgtun"
696            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">")
697        when "bdgtequn"
698            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">=")
699        when "bdltun"
700            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<")
701        when "bdltequn"
702            cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<=")
703
704        when "td2i"
705            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].clValue(:double)};"
706            $asm.putc "#{operands[1].clDump}.clearHighWord();"
707
708        when "bcd2i"  # operands: srcDbl dstInt slowPath
709            $asm.putc "{"
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();"
716            $asm.putc "}"
717
718        when "move"
719            $asm.putc "#{operands[1].clValue(:int)} = #{operands[0].clValue(:int)};"
720        when "sxi2q"
721            $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].clValue(:int32)};"
722        when "zxi2q"
723            $asm.putc "#{operands[1].clValue(:uint64)} = #{operands[0].clValue(:uint32)};"
724        when "nop"
725            $asm.putc "// nop"
726        when "bbeq"
727            cloopEmitCompareAndBranch(operands, :int8, "==")
728        when "bieq"
729            cloopEmitCompareAndBranch(operands, :int32, "==")
730        when "bqeq"
731            cloopEmitCompareAndBranch(operands, :int64, "==")
732        when "bpeq"
733            cloopEmitCompareAndBranch(operands, :int, "==")
734
735        when "bbneq"
736            cloopEmitCompareAndBranch(operands, :int8, "!=")
737        when "bineq"
738            cloopEmitCompareAndBranch(operands, :int32, "!=")
739        when "bqneq"
740            cloopEmitCompareAndBranch(operands, :int64, "!=")
741        when "bpneq"
742            cloopEmitCompareAndBranch(operands, :int, "!=")
743
744        when "bba"
745            cloopEmitCompareAndBranch(operands, :uint8, ">")
746        when "bia"
747            cloopEmitCompareAndBranch(operands, :uint32, ">")
748        when "bqa"
749            cloopEmitCompareAndBranch(operands, :uint64, ">")
750        when "bpa"
751            cloopEmitCompareAndBranch(operands, :uint, ">")
752
753        when "bbaeq"
754            cloopEmitCompareAndBranch(operands, :uint8, ">=")
755        when "biaeq"
756            cloopEmitCompareAndBranch(operands, :uint32, ">=")
757        when "bqaeq"
758            cloopEmitCompareAndBranch(operands, :uint64, ">=")
759        when "bpaeq"
760            cloopEmitCompareAndBranch(operands, :uint, ">=")
761
762        when "bbb"
763            cloopEmitCompareAndBranch(operands, :uint8, "<")
764        when "bib"
765            cloopEmitCompareAndBranch(operands, :uint32, "<")
766        when "bqb"
767            cloopEmitCompareAndBranch(operands, :uint64, "<")
768        when "bpb"
769            cloopEmitCompareAndBranch(operands, :uint, "<")
770
771        when "bbbeq"
772            cloopEmitCompareAndBranch(operands, :uint8, "<=")
773        when "bibeq"
774            cloopEmitCompareAndBranch(operands, :uint32, "<=")
775        when "bqbeq"
776            cloopEmitCompareAndBranch(operands, :uint64, "<=")
777        when "bpbeq"
778            cloopEmitCompareAndBranch(operands, :uint, "<=")
779
780        when "bbgt"
781            cloopEmitCompareAndBranch(operands, :int8, ">")
782        when "bigt"
783            cloopEmitCompareAndBranch(operands, :int32, ">")
784        when "bqgt"
785            cloopEmitCompareAndBranch(operands, :int64, ">")
786        when "bpgt"
787            cloopEmitCompareAndBranch(operands, :int, ">")
788
789        when "bbgteq"
790            cloopEmitCompareAndBranch(operands, :int8, ">=")
791        when "bigteq"
792            cloopEmitCompareAndBranch(operands, :int32, ">=")
793        when "bqgteq"
794            cloopEmitCompareAndBranch(operands, :int64, ">=")
795        when "bpgteq"
796            cloopEmitCompareAndBranch(operands, :int, ">=")
797
798        when "bblt"
799            cloopEmitCompareAndBranch(operands, :int8, "<")
800        when "bilt"
801            cloopEmitCompareAndBranch(operands, :int32, "<")
802        when "bqlt"
803            cloopEmitCompareAndBranch(operands, :int64, "<")
804        when "bplt"
805            cloopEmitCompareAndBranch(operands, :int, "<")
806
807        when "bblteq"
808            cloopEmitCompareAndBranch(operands, :int8, "<=")
809        when "bilteq"
810            cloopEmitCompareAndBranch(operands, :int32, "<=")
811        when "bqlteq"
812            cloopEmitCompareAndBranch(operands, :int64, "<=")
813        when "bplteq"
814            cloopEmitCompareAndBranch(operands, :int, "<=")
815
816        when "btbz"
817            cloopEmitTestAndBranchIf(operands, :int8, "== 0", operands[-1].cLabel)
818        when "btiz"
819            cloopEmitTestAndBranchIf(operands, :int32, "== 0", operands[-1].cLabel)
820        when "btqz"
821            cloopEmitTestAndBranchIf(operands, :int64, "== 0", operands[-1].cLabel)
822        when "btpz"
823            cloopEmitTestAndBranchIf(operands, :int, "== 0", operands[-1].cLabel)
824
825        when "btbnz"
826            cloopEmitTestAndBranchIf(operands, :int8, "!= 0", operands[-1].cLabel)
827        when "btinz"
828            cloopEmitTestAndBranchIf(operands, :int32, "!= 0", operands[-1].cLabel)
829        when "btqnz"
830            cloopEmitTestAndBranchIf(operands, :int64, "!= 0", operands[-1].cLabel)
831        when "btpnz"
832            cloopEmitTestAndBranchIf(operands, :int, "!= 0", operands[-1].cLabel)
833
834        when "btbs"
835            cloopEmitTestAndBranchIf(operands, :int8, "< 0", operands[-1].cLabel)
836        when "btis"
837            cloopEmitTestAndBranchIf(operands, :int32, "< 0", operands[-1].cLabel)
838        when "btqs"
839            cloopEmitTestAndBranchIf(operands, :int64, "< 0", operands[-1].cLabel)
840        when "btps"
841            cloopEmitTestAndBranchIf(operands, :int, "< 0", operands[-1].cLabel)
842
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).
846        #
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.
851        when "jmp"
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};"
855            else
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();"
860            end
861
862        when "call"
863            $asm.putc "CRASH(); // generic call instruction not supported by design!"
864        when "break"
865            $asm.putc "CRASH(); // break instruction not implemented."
866        when "ret"
867            $asm.putc "goto doReturnHelper;"
868
869        when "cbeq"
870            cloopEmitCompareAndSet(operands, :uint8, "==")
871        when "cieq"
872            cloopEmitCompareAndSet(operands, :uint32, "==")
873        when "cqeq"
874            cloopEmitCompareAndSet(operands, :uint64, "==")
875        when "cpeq"
876            cloopEmitCompareAndSet(operands, :uint, "==")
877
878        when "cbneq"
879            cloopEmitCompareAndSet(operands, :uint8, "!=")
880        when "cineq"
881            cloopEmitCompareAndSet(operands, :uint32, "!=")
882        when "cqneq"
883            cloopEmitCompareAndSet(operands, :uint64, "!=")
884        when "cpneq"
885            cloopEmitCompareAndSet(operands, :uint, "!=")
886
887        when "cba"
888            cloopEmitCompareAndSet(operands, :uint8, ">")
889        when "cia"
890            cloopEmitCompareAndSet(operands, :uint32, ">")
891        when "cqa"
892            cloopEmitCompareAndSet(operands, :uint64, ">")
893        when "cpa"
894            cloopEmitCompareAndSet(operands, :uint, ">")
895
896        when "cbaeq"
897            cloopEmitCompareAndSet(operands, :uint8, ">=")
898        when "ciaeq"
899            cloopEmitCompareAndSet(operands, :uint32, ">=")
900        when "cqaeq"
901            cloopEmitCompareAndSet(operands, :uint64, ">=")
902        when "cpaeq"
903            cloopEmitCompareAndSet(operands, :uint, ">=")
904
905        when "cbb"
906            cloopEmitCompareAndSet(operands, :uint8, "<")
907        when "cib"
908            cloopEmitCompareAndSet(operands, :uint32, "<")
909        when "cqb"
910            cloopEmitCompareAndSet(operands, :uint64, "<")
911        when "cpb"
912            cloopEmitCompareAndSet(operands, :uint, "<")
913
914        when "cbbeq"
915            cloopEmitCompareAndSet(operands, :uint8, "<=")
916        when "cibeq"
917            cloopEmitCompareAndSet(operands, :uint32, "<=")
918        when "cqbeq"
919            cloopEmitCompareAndSet(operands, :uint64, "<=")
920        when "cpbeq"
921            cloopEmitCompareAndSet(operands, :uint, "<=")
922
923        when "cbgt"
924            cloopEmitCompareAndSet(operands, :int8, ">")
925        when "cigt"
926            cloopEmitCompareAndSet(operands, :int32, ">")
927        when "cqgt"
928            cloopEmitCompareAndSet(operands, :int64, ">")
929        when "cpgt"
930            cloopEmitCompareAndSet(operands, :int, ">")
931
932        when "cbgteq"
933            cloopEmitCompareAndSet(operands, :int8, ">=")
934        when "cigteq"
935            cloopEmitCompareAndSet(operands, :int32, ">=")
936        when "cqgteq"
937            cloopEmitCompareAndSet(operands, :int64, ">=")
938        when "cpgteq"
939            cloopEmitCompareAndSet(operands, :int, ">=")
940
941        when "cblt"
942            cloopEmitCompareAndSet(operands, :int8, "<")
943        when "cilt"
944            cloopEmitCompareAndSet(operands, :int32, "<")
945        when "cqlt"
946            cloopEmitCompareAndSet(operands, :int64, "<")
947        when "cplt"
948            cloopEmitCompareAndSet(operands, :int, "<")
949
950        when "cblteq"
951            cloopEmitCompareAndSet(operands, :int8, "<=")
952        when "cilteq"
953            cloopEmitCompareAndSet(operands, :int32, "<=")
954        when "cqlteq"
955            cloopEmitCompareAndSet(operands, :int64, "<=")
956        when "cplteq"
957            cloopEmitCompareAndSet(operands, :int, "<=")
958
959        when "tbs"
960            cloopEmitTestSet(operands, :int8, "< 0")
961        when "tis"
962            cloopEmitTestSet(operands, :int32, "< 0")
963        when "tqs"
964            cloopEmitTestSet(operands, :int64, "< 0")
965        when "tps"
966            cloopEmitTestSet(operands, :int, "< 0")
967
968        when "tbz"
969            cloopEmitTestSet(operands, :int8, "== 0")
970        when "tiz"
971            cloopEmitTestSet(operands, :int32, "== 0")
972        when "tqz"
973            cloopEmitTestSet(operands, :int64, "== 0")
974        when "tpz"
975            cloopEmitTestSet(operands, :int, "== 0")
976
977        when "tbnz"
978            cloopEmitTestSet(operands, :int8, "!= 0")
979        when "tinz"
980            cloopEmitTestSet(operands, :int32, "!= 0")
981        when "tqnz"
982            cloopEmitTestSet(operands, :int64, "!= 0")
983        when "tpnz"
984            cloopEmitTestSet(operands, :int, "!= 0")
985
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.
989        when "cdqi"
990            $asm.putc "{"
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();"
996            $asm.putc "}"
997
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.
1003        #
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.
1008        when "idivi"
1009            # Divide t1,t0 (EDX,EAX) by the specified arg, and store the remainder in t1,
1010            # and quotient in t0:
1011            $asm.putc "{"
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();"
1018            $asm.putc "}"
1019
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.
1022        when "fii2d"
1023            $asm.putc "#{operands[2].clValue(:double)} = Ints2Double(#{operands[0].clValue(:uint32)}, #{operands[1].clValue(:uint32)});"
1024
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).
1027        when "fd2ii"
1028            $asm.putc "Double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clValue(:uint32)}, #{operands[2].clValue(:uint32)});"
1029
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.
1032        when "fq2d"
1033            $asm.putc "#{operands[1].clValue(:double)} = #{operands[0].clValue(:castToDouble)};"
1034
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.
1037        when "fd2q"
1038            $asm.putc "#{operands[1].clValue(:int64)} = #{operands[0].clValue(:castToInt64)};"
1039
1040        when "leai"
1041            operands[0].cloopEmitLea(operands[1], :int32)
1042        when "leap"
1043            operands[0].cloopEmitLea(operands[1], :int)
1044
1045        when "baddio"
1046            cloopEmitOpAndBranchIfOverflow(operands, "+", :int32)
1047        when "bsubio"
1048            cloopEmitOpAndBranchIfOverflow(operands, "-", :int32)
1049        when "bmulio"
1050            cloopEmitOpAndBranchIfOverflow(operands, "*", :int32)
1051
1052        when "baddis"
1053            cloopEmitOpAndBranch(operands, "+", :int32, "< 0")
1054        when "baddiz"
1055            cloopEmitOpAndBranch(operands, "+", :int32, "== 0")
1056        when "baddinz"
1057            cloopEmitOpAndBranch(operands, "+", :int32, "!= 0")
1058
1059        when "baddqs"
1060            cloopEmitOpAndBranch(operands, "+", :int64, "< 0")
1061        when "baddqz"
1062            cloopEmitOpAndBranch(operands, "+", :int64, "== 0")
1063        when "baddqnz"
1064            cloopEmitOpAndBranch(operands, "+", :int64, "!= 0")
1065
1066        when "baddps"
1067            cloopEmitOpAndBranch(operands, "+", :int, "< 0")
1068        when "baddpz"
1069            cloopEmitOpAndBranch(operands, "+", :int, "== 0")
1070        when "baddpnz"
1071            cloopEmitOpAndBranch(operands, "+", :int, "!= 0")
1072
1073        when "bsubis"
1074            cloopEmitOpAndBranch(operands, "-", :int32, "< 0")
1075        when "bsubiz"
1076            cloopEmitOpAndBranch(operands, "-", :int32, "== 0")
1077        when "bsubinz"
1078            cloopEmitOpAndBranch(operands, "-", :int32, "!= 0")
1079
1080        when "borris"
1081            cloopEmitOpAndBranch(operands, "|", :int32, "< 0")
1082        when "borriz"
1083            cloopEmitOpAndBranch(operands, "|", :int32, "== 0")
1084        when "borrinz"
1085            cloopEmitOpAndBranch(operands, "|", :int32, "!= 0")
1086
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.
1092        when "cloopCrash"
1093            $asm.putc "CRASH();"
1094
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();"
1101
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)"            
1114
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)
1120
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.
1124        when "cloopDo"
1125            $asm.putc "#{annotation}"
1126
1127        else
1128            lowerDefault
1129        end
1130    end
1131end
1132