Stop placing std::isfinite and std::signbit inside the global scope
[WebKit.git] / Source / JavaScriptCore / offlineasm / cloop.rb
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
24 require "config"
25 require "ast"
26 require "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
34 def 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
54 end
55
56
57 class SpecialRegister < NoChildren
58     def clDump
59         @name
60     end
61     def clValue(type=:int)
62         @name + cloopMapType(type)
63     end
64 end
65
66 C_LOOP_SCRATCH_FPR = SpecialRegister.new("d8")
67
68 class 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
100 end
101
102 class 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
124 end
125
126 class 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
156 end
157
158 class 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, globalData)), &sp->globalData)"
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
229 end
230
231 class 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, globalData)), &sp->globalData)"
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
294 end
295
296 class AbsoluteAddress
297     def clDump
298         "#{codeOriginString}"
299     end
300     def clValue
301         clDump
302     end
303 end
304
305
306 #
307 # Lea support.
308 #
309
310 class 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
318 end
319
320 class 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
325 end
326
327 #
328 # Actual lowering code follows.
329 #
330
331 class 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
348 end
349
350 def clOperands(operands)
351     operands.map{|v| v.clDump}.join(", ")
352 end
353
354
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.
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
371 end
372
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.
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
388 end
389
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.
397     end
398 end
399
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};"
404 end
405
406
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)});"
411 end
412
413
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};"
417 end
418
419
420 # conditionTest should contain a string that provides a comparator and a RHS
421 # value e.g. "< 0".
422 def 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}"
436 end
437
438 # conditionTest should contain a string that provides a comparator and a RHS
439 # value e.g. "< 0".
440 def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
441     conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
442     $asm.putc "if (#{conditionExpr})"
443     $asm.putc "    goto #{branchTarget};"
444 end
445
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});"
452 end
453
454 def 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 "    if (temp #{conditionTest})"
469     $asm.putc "        goto  #{operands[2].cLabel};"
470     $asm.putc "    #{op2} = temp;"
471     $asm.putc "}"
472 end
473
474 def 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)))"
491 end
492
493 def 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)))"
510 end
511
512 def 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)"
522 end
523
524 def 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 "    if #{overflowTest} {"
537     $asm.putc "        goto #{operands[2].cLabel};"
538     $asm.putc "    }"
539     $asm.putc "    #{operands[1].clValue(type)} = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
540     $asm.putc "}"
541 end
542
543 # operands: callTarget, currentFrame, currentPC
544 def 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 "}"
551 end
552
553 class 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}, #{operands[2].clValue});"
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
1131 end