Remove poisoning of typed array vector
[WebKit-https.git] / Source / JavaScriptCore / offlineasm / x86.rb
1 # Copyright (C) 2012-2018 Apple Inc. All rights reserved.
2 # Copyright (C) 2013 Digia Plc. and/or its subsidiary(-ies)
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 # 1. Redistributions of source code must retain the above copyright
8 #    notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 #    notice, this list of conditions and the following disclaimer in the
11 #    documentation and/or other materials provided with the distribution.
12 #
13 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 # THE POSSIBILITY OF SUCH DAMAGE.
24
25 require "config"
26
27 # GPR conventions, to match the baseline JIT:
28 #
29 #
30 # On x86-32 bits (windows and non-windows)
31 # a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not
32 # actually considered as such by the ABI and we need to push/pop our arguments
33 # on the stack. a0 and a1 are ecx and edx to follow fastcall.
34 #
35 # eax => t0, a2, r0
36 # edx => t1, a1, r1
37 # ecx => t2, a0
38 # ebx => t3, a3     (callee-save)
39 # esi => t4         (callee-save)
40 # edi => t5         (callee-save)
41 # ebp => cfr
42 # esp => sp
43 #
44 # On x86-64 non-windows
45 #
46 # rax => t0,     r0
47 # rdi =>     a0
48 # rsi => t1, a1
49 # rdx => t2, a2, r1
50 # rcx => t3, a3
51 #  r8 => t4
52 # r10 => t5
53 # rbx =>             csr0 (callee-save, PB, unused in baseline)
54 # r12 =>             csr1 (callee-save)
55 # r13 =>             csr2 (callee-save)
56 # r14 =>             csr3 (callee-save, tagTypeNumber)
57 # r15 =>             csr4 (callee-save, tagMask)
58 # rsp => sp
59 # rbp => cfr
60 # r11 =>                  (scratch)
61 #
62 # On x86-64 windows
63 # Arguments need to be push/pop'd on the stack in addition to being stored in
64 # the registers. Also, >8 return types are returned in a weird way.
65 #
66 # rax => t0,     r0
67 # rcx =>     a0
68 # rdx => t1, a1, r1
69 #  r8 => t2, a2
70 #  r9 => t3, a3
71 # r10 => t4
72 # rbx =>             csr0 (callee-save, PB, unused in baseline)
73 # rsi =>             csr1 (callee-save)
74 # rdi =>             csr2 (callee-save)
75 # r12 =>             csr3 (callee-save)
76 # r13 =>             csr4 (callee-save)
77 # r14 =>             csr5 (callee-save, tagTypeNumber)
78 # r15 =>             csr6 (callee-save, tagMask)
79 # rsp => sp
80 # rbp => cfr
81 # r11 =>                  (scratch)
82
83 def isX64
84     case $activeBackend
85     when "X86"
86         false
87     when "X86_WIN"
88         false
89     when "X86_64"
90         true
91     when "X86_64_WIN"
92         true
93     else
94         raise "bad value for $activeBackend: #{$activeBackend}"
95     end
96 end
97
98 def isWin
99     case $activeBackend
100     when "X86"
101         false
102     when "X86_WIN"
103         true
104     when "X86_64"
105         false
106     when "X86_64_WIN"
107         true
108     else
109         raise "bad value for $activeBackend: #{$activeBackend}"
110     end
111 end
112
113 def useX87
114     case $activeBackend
115     when "X86"
116         true
117     when "X86_WIN"
118         true
119     when "X86_64"
120         false
121     when "X86_64_WIN"
122         false
123     else
124         raise "bad value for $activeBackend: #{$activeBackend}"
125     end
126 end
127
128 def isMSVC
129     $options.has_key?(:assembler) && $options[:assembler] == "MASM"
130 end
131
132 def isIntelSyntax
133     $options.has_key?(:assembler) && $options[:assembler] == "MASM"
134 end
135
136 def register(name)
137     isIntelSyntax ? name : "%" + name
138 end
139
140 def offsetRegister(off, register)
141     isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})"
142 end
143
144 def callPrefix
145     isIntelSyntax ? "" : "*"
146 end
147
148 def orderOperands(opA, opB)
149     isIntelSyntax ? "#{opB}, #{opA}" : "#{opA}, #{opB}"
150 end
151
152 def const(c)
153     isIntelSyntax ? "#{c}" : "$#{c}"
154 end
155
156 def getSizeString(kind)
157     if !isIntelSyntax
158         return ""
159     end
160
161     size = ""
162     case kind
163     when :byte
164         size = "byte"
165     when :half
166         size = "word"
167     when :int
168         size = "dword"
169     when :ptr
170         size =  isX64 ? "qword" : "dword"
171     when :double
172         size = "qword"
173     when :quad
174         size = "qword"
175     else
176         raise "Invalid kind #{kind}"
177     end
178
179     return size + " " + "ptr" + " ";
180 end
181
182 class SpecialRegister < NoChildren
183     def x86Operand(kind)
184         raise unless @name =~ /^r/
185         raise unless isX64
186         case kind
187         when :half
188             register(@name + "w")
189         when :int
190             register(@name + "d")
191         when :ptr
192             register(@name)
193         when :quad
194             register(@name)
195         else
196             raise
197         end
198     end
199     def x86CallOperand(kind)
200         # Call operands are not allowed to be partial registers.
201         "#{callPrefix}#{x86Operand(:quad)}"
202     end
203 end
204
205 X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
206
207 def x86GPRName(name, kind)
208     case name
209     when "eax", "ebx", "ecx", "edx"
210         name8 = name[1] + 'l'
211         name16 = name[1..2]
212     when "esi", "edi", "ebp", "esp"
213         name16 = name[1..2]
214         name8 = name16 + 'l'
215     when "rax", "rbx", "rcx", "rdx"
216         raise "bad GPR name #{name} in 32-bit X86" unless isX64
217         name8 = name[1] + 'l'
218         name16 = name[1..2]
219     when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
220         raise "bad GPR name #{name} in 32-bit X86" unless isX64
221         case kind
222         when :half
223             return register(name + "w")
224         when :int
225             return register(name + "d")
226         when :ptr
227             return register(name)
228         when :quad
229             return register(name)
230         end
231     else
232         raise "bad GPR name #{name}"
233     end
234     case kind
235     when :byte
236         register(name8)
237     when :half
238         register(name16)
239     when :int
240         register("e" + name16)
241     when :ptr
242         register((isX64 ? "r" : "e") + name16)
243     when :quad
244         isX64 ? register("r" + name16) : raise
245     else
246         raise "invalid kind #{kind} for GPR #{name} in X86"
247     end
248 end
249
250 class Node
251     def x86LoadOperand(type, dst)
252         x86Operand(type)
253     end
254 end
255
256 class RegisterID
257     def supports8BitOnX86
258         case x86GPR
259         when "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"
260             true
261         when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
262             false
263         else
264             raise
265         end
266     end
267
268     def x86GPR
269         if isX64
270             case name
271             when "t0", "r0"
272                 "eax"
273             when "r1"
274                 "edx" # t1 = a1 when isWin, t2 = a2 otherwise
275             when "a0"
276                 isWin ? "ecx" : "edi"
277             when "t1", "a1"
278                 isWin ? "edx" : "esi"
279             when "t2", "a2"
280                 isWin ? "r8" : "edx"
281             when "t3", "a3"
282                 isWin ? "r9" : "ecx"
283             when "t4"
284                 isWin ? "r10" : "r8"
285             when "t5"
286                 raise "cannot use register #{name} on X86-64 Windows" unless not isWin
287                 "r10"
288             when "csr0"
289                 "ebx"
290             when "csr1"
291                 isWin ? "esi" : "r12"
292             when "csr2"
293                 isWin ? "edi" : "r13"
294             when "csr3"
295                 isWin ? "r12" : "r14"
296             when "csr4"
297                 isWin ? "r13" : "r15"
298             when "csr5"
299                 raise "cannot use register #{name} on X86-64" unless isWin
300                 "r14"
301             when "csr6"
302                 raise "cannot use register #{name} on X86-64" unless isWin
303                 "r15"
304             when "cfr"
305                 "ebp"
306             when "sp"
307                 "esp"
308             else
309                 raise "cannot use register #{name} on X86"
310             end
311         else
312             case name
313             when "t0", "r0", "a2"
314                 "eax"
315             when "t1", "r1", "a1"
316                 "edx"
317             when "t2", "a0"
318                 "ecx"
319             when "t3", "a3"
320                 "ebx"
321             when "t4"
322                 "esi"
323             when "t5"
324                 "edi"
325             when "cfr"
326                 "ebp"
327             when "sp"
328                 "esp"
329             end
330         end
331     end
332
333     def x86Operand(kind)
334         x86GPRName(x86GPR, kind)
335     end
336
337     def x86CallOperand(kind)
338         "#{callPrefix}#{x86Operand(:ptr)}"
339     end
340 end
341
342 class FPRegisterID
343     def x86Operand(kind)
344         raise unless kind == :double
345         raise if useX87
346         case name
347         when "ft0", "fa0", "fr"
348             register("xmm0")
349         when "ft1", "fa1"
350             register("xmm1")
351         when "ft2", "fa2"
352             register("xmm2")
353         when "ft3", "fa3"
354             register("xmm3")
355         when "ft4"
356             register("xmm4")
357         when "ft5"
358             register("xmm5")
359         else
360             raise "Bad register #{name} for X86 at #{codeOriginString}"
361         end
362     end
363     def x87DefaultStackPosition
364         case name
365         when "ft0", "fr"
366             0
367         when "ft1"
368             1
369         when "ft2", "ft3", "ft4", "ft5"
370             raise "Unimplemented register #{name} for X86 at #{codeOriginString}"
371         else
372             raise "Bad register #{name} for X86 at #{codeOriginString}"
373         end
374     end
375     def x87Operand(offset)
376         raise unless useX87
377         raise unless offset == 0 or offset == 1
378         "#{register("st")}(#{x87DefaultStackPosition + offset})"
379     end
380     def x86CallOperand(kind)
381         "#{callPrefix}#{x86Operand(kind)}"
382     end
383 end
384
385 class Immediate
386     def validX86Immediate?
387         if isX64
388             value >= -0x80000000 and value <= 0x7fffffff
389         else
390             true
391         end
392     end
393     def x86Operand(kind)
394         "#{const(value)}"
395     end
396     def x86CallOperand(kind)
397         "#{value}"
398     end
399 end
400
401 class Address
402     def supports8BitOnX86
403         true
404     end
405     
406     def x86AddressOperand(addressKind)
407         "#{offsetRegister(offset.value, base.x86Operand(addressKind))}"
408     end
409     def x86Operand(kind)
410         "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}"
411     end
412     def x86CallOperand(kind)
413         "#{callPrefix}#{x86Operand(kind)}"
414     end
415 end
416
417 class BaseIndex
418     def supports8BitOnX86
419         true
420     end
421     
422     def x86AddressOperand(addressKind)
423         if !isIntelSyntax
424             "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scale})"
425         else
426             "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scale}]"
427         end
428     end
429     
430     def x86Operand(kind)
431         if !isIntelSyntax
432             x86AddressOperand(:ptr)
433         else
434             "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scale}]"
435         end
436     end
437
438     def x86CallOperand(kind)
439         "#{callPrefix}#{x86Operand(kind)}"
440     end
441 end
442
443 class AbsoluteAddress
444     def supports8BitOnX86
445         true
446     end
447     
448     def x86AddressOperand(addressKind)
449         "#{address.value}"
450     end
451     
452     def x86Operand(kind)
453         "#{address.value}"
454     end
455
456     def x86CallOperand(kind)
457         "#{callPrefix}#{address.value}"
458     end
459 end
460
461 class LabelReference
462     def x86CallOperand(kind)
463         asmLabel
464     end
465     def x86LoadOperand(kind, dst)
466         # FIXME: Implement this on platforms that aren't Mach-O.
467         # https://bugs.webkit.org/show_bug.cgi?id=175104
468         $asm.puts "movq #{asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
469         "#{offset}(#{dst.x86Operand(kind)})"
470     end
471 end
472
473 class LocalLabelReference
474     def x86Operand(kind)
475         asmLabel
476     end
477     def x86CallOperand(kind)
478         asmLabel
479     end
480 end
481
482 class Sequence
483     def getModifiedListX86_64
484         newList = []
485         
486         @list.each {
487             | node |
488             newNode = node
489             if node.is_a? Instruction
490                 unless node.opcode == "move"
491                     usedScratch = false
492                     newOperands = node.operands.map {
493                         | operand |
494                         if operand.immediate? and not operand.validX86Immediate?
495                             if usedScratch
496                                 raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
497                             end
498                             newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
499                             usedScratch = true
500                             X64_SCRATCH_REGISTER
501                         else
502                             operand
503                         end
504                     }
505                     newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
506                 end
507             else
508                 unless node.is_a? Label or
509                         node.is_a? LocalLabel or
510                         node.is_a? Skip
511                     raise "Unexpected #{node.inspect} at #{node.codeOrigin}" 
512                 end
513             end
514             if newNode
515                 newList << newNode
516             end
517         }
518         
519         return newList
520     end
521     def getModifiedListX86_64_WIN
522         getModifiedListX86_64
523     end
524 end
525
526 class Instruction
527     
528     def x86Operands(*kinds)
529         raise unless kinds.size == operands.size
530         result = []
531         kinds.size.times {
532             | idx |
533             i = isIntelSyntax ? (kinds.size - idx - 1) : idx
534             result << operands[i].x86Operand(kinds[i])
535         }
536         result.join(", ")
537     end
538     
539     def x86LoadOperands(srcKind, dstKind)
540         orderOperands(operands[0].x86LoadOperand(srcKind, operands[1]), operands[1].x86Operand(dstKind))
541     end
542
543     def x86Suffix(kind)
544         if isIntelSyntax
545             return ""
546         end
547
548         case kind
549         when :byte
550             "b"
551         when :half
552             "w"
553         when :int
554             "l"
555         when :ptr
556             isX64 ? "q" : "l"
557         when :quad
558             isX64 ? "q" : raise
559         when :double
560             not useX87 ? "sd" : raise
561         else
562             raise
563         end
564     end
565     
566     def x86Bytes(kind)
567         case kind
568         when :byte
569             1
570         when :half
571             2
572         when :int
573             4
574         when :ptr
575             isX64 ? 8 : 4
576         when :quad
577             isX64 ? 8 : raise
578         when :double
579             8
580         else
581             raise
582         end
583     end
584
585     def emitX86Lea(src, dst, kind)
586         if src.is_a? LabelReference
587             $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
588         else
589             $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}"
590         end
591     end
592
593     def getImplicitOperandString
594         isIntelSyntax ? "st(0), " : ""
595     end
596     
597     def handleX86OpWithNumOperands(opcode, kind, numOperands)
598         if numOperands == 3
599             if operands[0] == operands[2]
600                 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
601             elsif operands[1] == operands[2]
602                 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
603             else
604                 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
605                 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
606             end
607         else
608             $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
609         end
610     end
611     
612     def handleX86Op(opcode, kind)
613         handleX86OpWithNumOperands(opcode, kind, operands.size)
614     end
615     
616     def handleX86Shift(opcode, kind)
617         if operands[0].is_a? Immediate or operands[0].x86GPR == "ecx"
618             $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
619         else
620             $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
621             $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
622             $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
623         end
624     end
625     
626     def handleX86DoubleBranch(branchOpcode, mode)
627         if useX87
628             handleX87Compare(mode)
629         else
630             case mode
631             when :normal
632                 $asm.puts "ucomisd #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}"
633             when :reverse
634                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
635             else
636                 raise mode.inspect
637             end
638         end
639         $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
640     end
641     
642     def handleX86IntCompare(opcodeSuffix, kind)
643         if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
644             $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
645         elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
646             $asm.puts "test#{x86Suffix(kind)}  #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
647         else
648             $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
649         end
650     end
651     
652     def handleX86IntBranch(branchOpcode, kind)
653         handleX86IntCompare(branchOpcode[1..-1], kind)
654         $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
655     end
656     
657     def handleX86Set(setOpcode, operand)
658         if operand.supports8BitOnX86
659             $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
660             if !isIntelSyntax
661                 $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
662             else
663                 $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
664             end
665         else
666             ax = RegisterID.new(nil, "r0")
667             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
668             $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}"
669             if !isIntelSyntax
670                 $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}"
671             else
672                 $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}"
673             end
674             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
675         end
676     end
677     
678     def handleX86IntCompareSet(setOpcode, kind)
679         handleX86IntCompare(setOpcode[3..-1], kind)
680         handleX86Set(setOpcode, operands[2])
681     end
682     
683     def handleX86Test(kind)
684         value = operands[0]
685         case operands.size
686         when 2
687             mask = Immediate.new(codeOrigin, -1)
688         when 3
689             mask = operands[1]
690         else
691             raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
692         end
693         
694         if mask.is_a? Immediate and mask.value == -1
695             if value.is_a? RegisterID
696                 $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
697             else
698                 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
699             end
700         else
701             $asm.puts "test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
702         end
703     end
704     
705     def handleX86BranchTest(branchOpcode, kind)
706         handleX86Test(kind)
707         $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
708     end
709     
710     def handleX86SetTest(setOpcode, kind)
711         handleX86Test(kind)
712         handleX86Set(setOpcode, operands.last)
713     end
714     
715     def handleX86OpBranch(opcode, branchOpcode, kind)
716         handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
717         case operands.size
718         when 4
719             jumpTarget = operands[3]
720         when 3
721             jumpTarget = operands[2]
722         else
723             raise self.inspect
724         end
725         $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
726     end
727     
728     def handleX86SubBranch(branchOpcode, kind)
729         if operands.size == 4 and operands[1] == operands[2]
730             $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
731             $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
732         else
733             handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
734         end
735         case operands.size
736         when 4
737             jumpTarget = operands[3]
738         when 3
739             jumpTarget = operands[2]
740         else
741             raise self.inspect
742         end
743         $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
744     end
745
746     def handleX86Add(kind)
747         if operands.size == 3 and operands[1] == operands[2]
748             unless Immediate.new(nil, 0) == operands[0]
749                 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
750             end
751         elsif operands.size == 3 and operands[0].is_a? Immediate
752             raise unless operands[1].is_a? RegisterID
753             raise unless operands[2].is_a? RegisterID
754             if operands[0].value == 0
755                 unless operands[1] == operands[2]
756                     $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
757                 end
758             else
759                 $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
760             end
761         elsif operands.size == 3 and operands[0].is_a? RegisterID
762             raise unless operands[1].is_a? RegisterID
763             raise unless operands[2].is_a? RegisterID
764             if operands[0] == operands[2]
765                 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
766             else
767                 if !isIntelSyntax
768                     $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
769                 else
770                     $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
771                 end
772             end
773         else
774             unless Immediate.new(nil, 0) == operands[0]
775                 $asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
776             end
777         end
778     end
779     
780     def handleX86Sub(kind)
781         if operands.size == 3 and operands[1] == operands[2]
782             $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
783             $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
784         else
785             handleX86Op("sub#{x86Suffix(kind)}", kind)
786         end
787     end
788     
789     def handleX86Mul(kind)
790         if operands.size == 3 and operands[0].is_a? Immediate
791             $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
792         else
793             # FIXME: could do some peephole in case the left operand is immediate and it's
794             # a power of two.
795             handleX86Op("imul#{x86Suffix(kind)}", kind)
796         end
797     end
798     
799     def handleX86Peek()
800         sp = RegisterID.new(nil, "sp")
801         opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
802         opB = operands[1].x86Operand(:ptr)
803         $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
804     end
805
806     def handleX86Poke()
807         sp = RegisterID.new(nil, "sp")
808         opA = operands[0].x86Operand(:ptr)
809         opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
810         $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
811     end
812
813     def handleMove
814         if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
815             if isX64
816                 $asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
817             else
818                 $asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
819             end
820         elsif operands[0] != operands[1]
821             if isX64
822                 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
823             else
824                 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
825             end
826         end
827     end
828
829     def handleX87Compare(mode)
830         floatingPointCompareImplicitOperand = getImplicitOperandString
831         case mode
832         when :normal
833             if (operands[0].x87DefaultStackPosition == 0)
834                 $asm.puts "fucomi #{floatingPointCompareImplicitOperand}#{operands[1].x87Operand(0)}"
835             else
836                 $asm.puts "fld #{operands[0].x87Operand(0)}"
837                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[1].x87Operand(1)}"
838             end
839         when :reverse
840             if (operands[1].x87DefaultStackPosition == 0)
841                 $asm.puts "fucomi #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(0)}"
842             else
843                 $asm.puts "fld #{operands[1].x87Operand(0)}"
844                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
845             end
846         else
847             raise mode.inspect
848         end
849     end
850
851     def handleX87BinOp(opcode, opcodereverse)
852         if (operands[1].x87DefaultStackPosition == 0)
853             $asm.puts "#{opcode} #{orderOperands(operands[0].x87Operand(0), register("st"))}"
854         elsif (operands[0].x87DefaultStackPosition == 0)
855             if !isIntelSyntax
856                 $asm.puts "#{opcodereverse} #{register("st")}, #{operands[1].x87Operand(0)}"
857             else
858                 $asm.puts "#{opcode} #{operands[1].x87Operand(0)}, #{register("st")}"
859             end
860         else
861             $asm.puts "fld #{operands[0].x87Operand(0)}"
862             $asm.puts "#{opcodereverse}p #{orderOperands(register("st"), operands[1].x87Operand(1))}"
863         end
864     end
865
866     def lowerX86
867         raise unless $activeBackend == "X86"
868         lowerX86Common
869     end
870
871     def lowerX86_WIN
872         raise unless $activeBackend == "X86_WIN" 
873         lowerX86Common
874     end
875     
876     def lowerX86_64
877         raise unless $activeBackend == "X86_64"
878         lowerX86Common
879     end
880
881     def lowerX86_64_WIN
882         raise unless $activeBackend == "X86_64_WIN"
883         lowerX86Common
884     end
885
886     def lowerX86Common
887         case opcode
888         when "addi"
889             handleX86Add(:int)
890         when "addp"
891             handleX86Add(:ptr)
892         when "addq"
893             handleX86Add(:quad)
894         when "andi"
895             handleX86Op("and#{x86Suffix(:int)}", :int)
896         when "andp"
897             handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
898         when "andq"
899             handleX86Op("and#{x86Suffix(:quad)}", :quad)
900         when "lshifti"
901             handleX86Shift("sal#{x86Suffix(:int)}", :int)
902         when "lshiftp"
903             handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
904         when "lshiftq"
905             handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
906         when "muli"
907             handleX86Mul(:int)
908         when "mulp"
909             handleX86Mul(:ptr)
910         when "mulq"
911             handleX86Mul(:quad)
912         when "negi"
913             $asm.puts "neg#{x86Suffix(:int)} #{x86Operands(:int)}"
914         when "negp"
915             $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
916         when "negq"
917             $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
918         when "noti"
919             $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
920         when "ori"
921             handleX86Op("or#{x86Suffix(:int)}", :int)
922         when "orp"
923             handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
924         when "orq"
925             handleX86Op("or#{x86Suffix(:quad)}", :quad)
926         when "rshifti"
927             handleX86Shift("sar#{x86Suffix(:int)}", :int)
928         when "rshiftp"
929             handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
930         when "rshiftq"
931             handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
932         when "urshifti"
933             handleX86Shift("shr#{x86Suffix(:int)}", :int)
934         when "urshiftp"
935             handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
936         when "urshiftq"
937             handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
938         when "subi"
939             handleX86Sub(:int)
940         when "subp"
941             handleX86Sub(:ptr)
942         when "subq"
943             handleX86Sub(:quad)
944         when "xori"
945             handleX86Op("xor#{x86Suffix(:int)}", :int)
946         when "xorp"
947             handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
948         when "xorq"
949             handleX86Op("xor#{x86Suffix(:quad)}", :quad)
950         when "loadi"
951             $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
952         when "storei"
953             $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
954         when "loadis"
955             if isX64
956                 if !isIntelSyntax
957                     $asm.puts "movslq #{x86LoadOperands(:int, :quad)}"
958                 else
959                     $asm.puts "movsxd #{x86LoadOperands(:int, :quad)}"
960                 end
961             else
962                 $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
963             end
964         when "loadp"
965             $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}"
966         when "storep"
967             $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
968         when "loadq"
969             $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}"
970         when "storeq"
971             $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
972         when "loadb"
973             if !isIntelSyntax
974                 $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}"
975             else
976                 $asm.puts "movzx #{x86LoadOperands(:byte, :int)}"
977             end
978         when "loadbs"
979             if !isIntelSyntax
980                 $asm.puts "movsbl #{x86LoadOperands(:byte, :int)}"
981             else
982                 $asm.puts "movsx #{x86LoadOperands(:byte, :int)}"
983             end
984         when "loadh"
985             if !isIntelSyntax
986                 $asm.puts "movzwl #{x86LoadOperands(:half, :int)}"
987             else
988                 $asm.puts "movzx #{x86LoadOperands(:half, :int)}"
989             end
990         when "loadhs"
991             if !isIntelSyntax
992                 $asm.puts "movswl #{x86LoadOperands(:half, :int)}"
993             else
994                 $asm.puts "movsx #{x86LoadOperands(:half, :int)}"
995             end
996         when "storeb"
997             $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
998         when "loadd"
999             if useX87
1000                 if !isIntelSyntax
1001                     $asm.puts "fldl #{operands[0].x86Operand(:double)}"
1002                 else
1003                     $asm.puts "fld #{operands[0].x86Operand(:double)}"
1004                 end
1005                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1006             else
1007                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1008             end
1009         when "moved"
1010             if useX87
1011                 if (operands[0].x87DefaultStackPosition == 0)
1012                     $asm.puts "fst #{operands[1].x87Operand(0)}"
1013                 else
1014                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1015                     $asm.puts "fstp #{operands[1].x87Operand(1)}"
1016                 end
1017             else
1018                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1019             end
1020         when "stored"
1021             if useX87
1022                 if (operands[0].x87DefaultStackPosition == 0)
1023                     $asm.puts "fst#{x86Suffix(:int)} #{operands[1].x86Operand(:double)}"
1024                 else
1025                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1026                     if !isIntelSyntax
1027                         $asm.puts "fstpl #{operands[1].x86Operand(:double)}"
1028                     else
1029                         $asm.puts "fstp #{operands[1].x86Operand(:double)}"
1030                     end
1031                 end
1032             else
1033                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1034             end
1035         when "addd"
1036             if useX87
1037                 handleX87BinOp("fadd", "fadd")
1038             else
1039                 $asm.puts "addsd #{x86Operands(:double, :double)}"
1040             end
1041         when "muld"
1042             if useX87
1043                 handleX87BinOp("fmul", "fmul")
1044             else
1045                 $asm.puts "mulsd #{x86Operands(:double, :double)}"
1046             end
1047         when "subd"
1048             if useX87
1049                 handleX87BinOp("fsub", "fsubr")
1050             else
1051                 $asm.puts "subsd #{x86Operands(:double, :double)}"
1052             end
1053         when "divd"
1054             if useX87
1055                 handleX87BinOp("fdiv", "fdivr")
1056             else
1057                 $asm.puts "divsd #{x86Operands(:double, :double)}"
1058             end
1059         when "sqrtd"
1060             if useX87
1061                 $asm.puts "fld #{operands[0].x87Operand(0)}"
1062                 $asm.puts "fsqrtl"
1063                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1064             else
1065                 $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1066             end
1067         when "ci2d"
1068             if useX87
1069                 sp = RegisterID.new(nil, "sp")
1070                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1071                 $asm.puts "fild#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1072                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1073             else
1074                 $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}"
1075             end
1076         when "bdeq"
1077             if useX87
1078                 handleX87Compare(:normal)
1079             else
1080                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1081             end
1082             if operands[0] == operands[1]
1083                 # This is just a jump ordered, which is a jnp.
1084                 $asm.puts "jnp #{operands[2].asmLabel}"
1085             else
1086                 isUnordered = LocalLabel.unique("bdeq")
1087                 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1088                 $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
1089                 isUnordered.lower("X86")
1090             end
1091         when "bdneq"
1092             handleX86DoubleBranch("jne", :normal)
1093         when "bdgt"
1094             handleX86DoubleBranch("ja", :normal)
1095         when "bdgteq"
1096             handleX86DoubleBranch("jae", :normal)
1097         when "bdlt"
1098             handleX86DoubleBranch("ja", :reverse)
1099         when "bdlteq"
1100             handleX86DoubleBranch("jae", :reverse)
1101         when "bdequn"
1102             handleX86DoubleBranch("je", :normal)
1103         when "bdnequn"
1104             if useX87
1105                 handleX87Compare(:normal)
1106             else
1107                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1108             end
1109             if operands[0] == operands[1]
1110                 # This is just a jump unordered, which is a jp.
1111                 $asm.puts "jp #{operands[2].asmLabel}"
1112             else
1113                 isUnordered = LocalLabel.unique("bdnequn")
1114                 isEqual = LocalLabel.unique("bdnequn")
1115                 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1116                 $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
1117                 isUnordered.lower("X86")
1118                 $asm.puts "jmp #{operands[2].asmLabel}"
1119                 isEqual.lower("X86")
1120             end
1121         when "bdgtun"
1122             handleX86DoubleBranch("jb", :reverse)
1123         when "bdgtequn"
1124             handleX86DoubleBranch("jbe", :reverse)
1125         when "bdltun"
1126             handleX86DoubleBranch("jb", :normal)
1127         when "bdltequn"
1128             handleX86DoubleBranch("jbe", :normal)
1129         when "btd2i"
1130             # FIXME: unused and unimplemented for x87
1131             raise if useX87
1132             $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1133             $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
1134             $asm.puts "je #{operands[2].asmLabel}"
1135         when "td2i"
1136             # FIXME: unused and unimplemented for x87
1137             raise if useX87
1138             $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1139         when "bcd2i"
1140             if useX87
1141                 floatingPointCompareImplicitOperand = getImplicitOperandString
1142                 sp = RegisterID.new(nil, "sp")
1143                 if (operands[0].x87DefaultStackPosition == 0)
1144                     $asm.puts "fistl -4(#{sp.x86Operand(:ptr)})"
1145                 else
1146                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1147                     $asm.puts "fistp#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1148                 end
1149                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1150                 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1151                 $asm.puts "je #{operands[2].asmLabel}"
1152                 $asm.puts "fild#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1153                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
1154                 $asm.puts "jp #{operands[2].asmLabel}"
1155                 $asm.puts "jne #{operands[2].asmLabel}"
1156             else
1157                 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1158                 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1159                 $asm.puts "je #{operands[2].asmLabel}"
1160                 $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
1161                 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
1162                 $asm.puts "jp #{operands[2].asmLabel}"
1163                 $asm.puts "jne #{operands[2].asmLabel}"
1164             end
1165         when "movdz"
1166             if useX87
1167                 $asm.puts "fldzl"
1168                 $asm.puts "fstp #{operands[0].x87Operand(1)}"
1169             else
1170                 $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
1171             end
1172         when "pop"
1173             operands.each {
1174                 | op |
1175                 $asm.puts "pop #{op.x86Operand(:ptr)}"
1176             }
1177         when "push"
1178             operands.each {
1179                 | op |
1180                 $asm.puts "push #{op.x86Operand(:ptr)}"
1181             }
1182         when "move"
1183             handleMove
1184         when "sxi2q"
1185             if !isIntelSyntax
1186                 $asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
1187             else
1188                 $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:quad))}"
1189             end
1190         when "zxi2q"
1191             $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:int))}"
1192         when "nop"
1193             $asm.puts "nop"
1194         when "bieq"
1195             handleX86IntBranch("je", :int)
1196         when "bpeq"
1197             handleX86IntBranch("je", :ptr)
1198         when "bqeq"
1199             handleX86IntBranch("je", :quad)
1200         when "bineq"
1201             handleX86IntBranch("jne", :int)
1202         when "bpneq"
1203             handleX86IntBranch("jne", :ptr)
1204         when "bqneq"
1205             handleX86IntBranch("jne", :quad)
1206         when "bia"
1207             handleX86IntBranch("ja", :int)
1208         when "bpa"
1209             handleX86IntBranch("ja", :ptr)
1210         when "bqa"
1211             handleX86IntBranch("ja", :quad)
1212         when "biaeq"
1213             handleX86IntBranch("jae", :int)
1214         when "bpaeq"
1215             handleX86IntBranch("jae", :ptr)
1216         when "bqaeq"
1217             handleX86IntBranch("jae", :quad)
1218         when "bib"
1219             handleX86IntBranch("jb", :int)
1220         when "bpb"
1221             handleX86IntBranch("jb", :ptr)
1222         when "bqb"
1223             handleX86IntBranch("jb", :quad)
1224         when "bibeq"
1225             handleX86IntBranch("jbe", :int)
1226         when "bpbeq"
1227             handleX86IntBranch("jbe", :ptr)
1228         when "bqbeq"
1229             handleX86IntBranch("jbe", :quad)
1230         when "bigt"
1231             handleX86IntBranch("jg", :int)
1232         when "bpgt"
1233             handleX86IntBranch("jg", :ptr)
1234         when "bqgt"
1235             handleX86IntBranch("jg", :quad)
1236         when "bigteq"
1237             handleX86IntBranch("jge", :int)
1238         when "bpgteq"
1239             handleX86IntBranch("jge", :ptr)
1240         when "bqgteq"
1241             handleX86IntBranch("jge", :quad)
1242         when "bilt"
1243             handleX86IntBranch("jl", :int)
1244         when "bplt"
1245             handleX86IntBranch("jl", :ptr)
1246         when "bqlt"
1247             handleX86IntBranch("jl", :quad)
1248         when "bilteq"
1249             handleX86IntBranch("jle", :int)
1250         when "bplteq"
1251             handleX86IntBranch("jle", :ptr)
1252         when "bqlteq"
1253             handleX86IntBranch("jle", :quad)
1254         when "bbeq"
1255             handleX86IntBranch("je", :byte)
1256         when "bbneq"
1257             handleX86IntBranch("jne", :byte)
1258         when "bba"
1259             handleX86IntBranch("ja", :byte)
1260         when "bbaeq"
1261             handleX86IntBranch("jae", :byte)
1262         when "bbb"
1263             handleX86IntBranch("jb", :byte)
1264         when "bbbeq"
1265             handleX86IntBranch("jbe", :byte)
1266         when "bbgt"
1267             handleX86IntBranch("jg", :byte)
1268         when "bbgteq"
1269             handleX86IntBranch("jge", :byte)
1270         when "bblt"
1271             handleX86IntBranch("jl", :byte)
1272         when "bblteq"
1273             handleX86IntBranch("jlteq", :byte)
1274         when "btis"
1275             handleX86BranchTest("js", :int)
1276         when "btps"
1277             handleX86BranchTest("js", :ptr)
1278         when "btqs"
1279             handleX86BranchTest("js", :quad)
1280         when "btiz"
1281             handleX86BranchTest("jz", :int)
1282         when "btpz"
1283             handleX86BranchTest("jz", :ptr)
1284         when "btqz"
1285             handleX86BranchTest("jz", :quad)
1286         when "btinz"
1287             handleX86BranchTest("jnz", :int)
1288         when "btpnz"
1289             handleX86BranchTest("jnz", :ptr)
1290         when "btqnz"
1291             handleX86BranchTest("jnz", :quad)
1292         when "btbs"
1293             handleX86BranchTest("js", :byte)
1294         when "btbz"
1295             handleX86BranchTest("jz", :byte)
1296         when "btbnz"
1297             handleX86BranchTest("jnz", :byte)
1298         when "jmp"
1299             $asm.puts "jmp #{operands[0].x86CallOperand(:ptr)}"
1300         when "baddio"
1301             handleX86OpBranch("add#{x86Suffix(:int)}", "jo", :int)
1302         when "baddpo"
1303             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
1304         when "baddqo"
1305             handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
1306         when "baddis"
1307             handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int)
1308         when "baddps"
1309             handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
1310         when "baddqs"
1311             handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
1312         when "baddiz"
1313             handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int)
1314         when "baddpz"
1315             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
1316         when "baddqz"
1317             handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
1318         when "baddinz"
1319             handleX86OpBranch("add#{x86Suffix(:int)}", "jnz", :int)
1320         when "baddpnz"
1321             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
1322         when "baddqnz"
1323             handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
1324         when "bsubio"
1325             handleX86SubBranch("jo", :int)
1326         when "bsubis"
1327             handleX86SubBranch("js", :int)
1328         when "bsubiz"
1329             handleX86SubBranch("jz", :int)
1330         when "bsubinz"
1331             handleX86SubBranch("jnz", :int)
1332         when "bmulio"
1333             handleX86OpBranch("imul#{x86Suffix(:int)}", "jo", :int)
1334         when "bmulis"
1335             handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int)
1336         when "bmuliz"
1337             handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int)
1338         when "bmulinz"
1339             handleX86OpBranch("imul#{x86Suffix(:int)}", "jnz", :int)
1340         when "borio"
1341             handleX86OpBranch("orl", "jo", :int)
1342         when "boris"
1343             handleX86OpBranch("orl", "js", :int)
1344         when "boriz"
1345             handleX86OpBranch("orl", "jz", :int)
1346         when "borinz"
1347             handleX86OpBranch("orl", "jnz", :int)
1348         when "break"
1349             $asm.puts "int #{const(3)}"
1350         when "call"
1351             if useX87
1352                 2.times {
1353                     | offset |
1354                     $asm.puts "ffree #{register("st")}(#{offset})"
1355                 }
1356             end
1357             op = operands[0].x86CallOperand(:ptr)
1358             if operands[0].is_a? LabelReference
1359                 operands[0].used
1360             end
1361             $asm.puts "call #{op}"
1362         when "ret"
1363             $asm.puts "ret"
1364         when "cieq"
1365             handleX86IntCompareSet("sete", :int)
1366         when "cbeq"
1367             handleX86IntCompareSet("sete", :byte)
1368         when "cpeq"
1369             handleX86IntCompareSet("sete", :ptr)
1370         when "cqeq"
1371             handleX86IntCompareSet("sete", :quad)
1372         when "cineq"
1373             handleX86IntCompareSet("setne", :int)
1374         when "cbneq"
1375             handleX86IntCompareSet("setne", :byte)
1376         when "cpneq"
1377             handleX86IntCompareSet("setne", :ptr)
1378         when "cqneq"
1379             handleX86IntCompareSet("setne", :quad)
1380         when "cia"
1381             handleX86IntCompareSet("seta", :int)
1382         when "cba"
1383             handleX86IntCompareSet("seta", :byte)
1384         when "cpa"
1385             handleX86IntCompareSet("seta", :ptr)
1386         when "cqa"
1387             handleX86IntCompareSet("seta", :quad)
1388         when "ciaeq"
1389             handleX86IntCompareSet("setae", :int)
1390         when "cbaeq"
1391             handleX86IntCompareSet("setae", :byte)
1392         when "cpaeq"
1393             handleX86IntCompareSet("setae", :ptr)
1394         when "cqaeq"
1395             handleX86IntCompareSet("setae", :quad)
1396         when "cib"
1397             handleX86IntCompareSet("setb", :int)
1398         when "cbb"
1399             handleX86IntCompareSet("setb", :byte)
1400         when "cpb"
1401             handleX86IntCompareSet("setb", :ptr)
1402         when "cqb"
1403             handleX86IntCompareSet("setb", :quad)
1404         when "cibeq"
1405             handleX86IntCompareSet("setbe", :int)
1406         when "cbbeq"
1407             handleX86IntCompareSet("setbe", :byte)
1408         when "cpbeq"
1409             handleX86IntCompareSet("setbe", :ptr)
1410         when "cqbeq"
1411             handleX86IntCompareSet("setbe", :quad)
1412         when "cigt"
1413             handleX86IntCompareSet("setg", :int)
1414         when "cbgt"
1415             handleX86IntCompareSet("setg", :byte)
1416         when "cpgt"
1417             handleX86IntCompareSet("setg", :ptr)
1418         when "cqgt"
1419             handleX86IntCompareSet("setg", :quad)
1420         when "cigteq"
1421             handleX86IntCompareSet("setge", :int)
1422         when "cbgteq"
1423             handleX86IntCompareSet("setge", :byte)
1424         when "cpgteq"
1425             handleX86IntCompareSet("setge", :ptr)
1426         when "cqgteq"
1427             handleX86IntCompareSet("setge", :quad)
1428         when "cilt"
1429             handleX86IntCompareSet("setl", :int)
1430         when "cblt"
1431             handleX86IntCompareSet("setl", :byte)
1432         when "cplt"
1433             handleX86IntCompareSet("setl", :ptr)
1434         when "cqlt"
1435             handleX86IntCompareSet("setl", :quad)
1436         when "cilteq"
1437             handleX86IntCompareSet("setle", :int)
1438         when "cblteq"
1439             handleX86IntCompareSet("setle", :byte)
1440         when "cplteq"
1441             handleX86IntCompareSet("setle", :ptr)
1442         when "cqlteq"
1443             handleX86IntCompareSet("setle", :quad)
1444         when "tis"
1445             handleX86SetTest("sets", :int)
1446         when "tiz"
1447             handleX86SetTest("setz", :int)
1448         when "tinz"
1449             handleX86SetTest("setnz", :int)
1450         when "tps"
1451             handleX86SetTest("sets", :ptr)
1452         when "tpz"
1453             handleX86SetTest("setz", :ptr)
1454         when "tpnz"
1455             handleX86SetTest("setnz", :ptr)
1456         when "tqs"
1457             handleX86SetTest("sets", :quad)
1458         when "tqz"
1459             handleX86SetTest("setz", :quad)
1460         when "tqnz"
1461             handleX86SetTest("setnz", :quad)
1462         when "tbs"
1463             handleX86SetTest("sets", :byte)
1464         when "tbz"
1465             handleX86SetTest("setz", :byte)
1466         when "tbnz"
1467             handleX86SetTest("setnz", :byte)
1468         when "peek"
1469             handleX86Peek()
1470         when "poke"
1471             handleX86Poke()
1472         when "cdqi"
1473             $asm.puts "cdq"
1474         when "idivi"
1475             $asm.puts "idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1476         when "fii2d"
1477             if useX87
1478                 sp = RegisterID.new(nil, "sp")
1479                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-8, sp.x86Operand(:ptr)))}"
1480                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1481                 $asm.puts "fld#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1482                 $asm.puts "fstp #{operands[2].x87Operand(1)}"
1483             else
1484                 $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
1485                 $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
1486                 $asm.puts "psllq $32, %xmm7"
1487                 $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
1488             end
1489         when "fd2ii"
1490             if useX87
1491                 sp = RegisterID.new(nil, "sp")
1492                 if (operands[0].x87DefaultStackPosition == 0)
1493                     $asm.puts "fst#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1494                 else
1495                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1496                     $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1497                 end
1498                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-8, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1499                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[2].x86Operand(:int))}"
1500             else
1501                 $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1502                 $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
1503                 $asm.puts "psrlq $32, %xmm7"
1504                 $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
1505             end
1506         when "fq2d"
1507             if useX87
1508                 sp = RegisterID.new(nil, "sp")
1509                 $asm.puts "movq #{operands[0].x86Operand(:quad)}, -8(#{sp.x86Operand(:ptr)})"
1510                 $asm.puts "fldl -8(#{sp.x86Operand(:ptr)})"
1511                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1512             else
1513                 if !isIntelSyntax
1514                     $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
1515                 else
1516                     # MASM does not accept register operands with movq.
1517                     # Debugging shows that movd actually moves a qword when using MASM.
1518                     $asm.puts "movd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:quad)}"
1519                 end
1520             end
1521         when "fd2q"
1522             if useX87
1523                 sp = RegisterID.new(nil, "sp")
1524                 if (operands[0].x87DefaultStackPosition == 0)
1525                     $asm.puts "fst#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1526                 else
1527                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1528                     $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1529                 end
1530                 $asm.puts "movq -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}"
1531             else
1532                 if !isIntelSyntax
1533                     $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1534                 else
1535                     # MASM does not accept register operands with movq.
1536                     # Debugging shows that movd actually moves a qword when using MASM.
1537                     $asm.puts "movd #{operands[1].x86Operand(:quad)}, #{operands[0].x86Operand(:double)}"
1538                 end
1539             end
1540         when "bo"
1541             $asm.puts "jo #{operands[0].asmLabel}"
1542         when "bs"
1543             $asm.puts "js #{operands[0].asmLabel}"
1544         when "bz"
1545             $asm.puts "jz #{operands[0].asmLabel}"
1546         when "bnz"
1547             $asm.puts "jnz #{operands[0].asmLabel}"
1548         when "leai"
1549             $asm.puts "lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}"
1550         when "leap"
1551             $asm.puts "lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}"
1552         when "memfence"
1553             sp = RegisterID.new(nil, "sp")
1554             if isIntelSyntax
1555                 $asm.puts "mfence"
1556             else
1557                 $asm.puts "lock; orl $0, (#{sp.x86Operand(:ptr)})"
1558             end
1559         else
1560             lowerDefault
1561         end
1562     end
1563 end
1564