b7d4f511ecef023339093afb68f47a073bbda52b
[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     def x86AddressOperand(addressKind)
472         # FIXME: Implement this on platforms that aren't Mach-O.
473         # https://bugs.webkit.org/show_bug.cgi?id=175104
474         "#{asmLabel}@GOTPCREL(%rip)"
475     end
476 end
477
478 class LocalLabelReference
479     def x86Operand(kind)
480         asmLabel
481     end
482     def x86CallOperand(kind)
483         asmLabel
484     end
485 end
486
487 class Sequence
488     def getModifiedListX86_64
489         newList = []
490         
491         @list.each {
492             | node |
493             newNode = node
494             if node.is_a? Instruction
495                 unless node.opcode == "move"
496                     usedScratch = false
497                     newOperands = node.operands.map {
498                         | operand |
499                         if operand.immediate? and not operand.validX86Immediate?
500                             if usedScratch
501                                 raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
502                             end
503                             newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
504                             usedScratch = true
505                             X64_SCRATCH_REGISTER
506                         else
507                             operand
508                         end
509                     }
510                     newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
511                 end
512             else
513                 unless node.is_a? Label or
514                         node.is_a? LocalLabel or
515                         node.is_a? Skip
516                     raise "Unexpected #{node.inspect} at #{node.codeOrigin}" 
517                 end
518             end
519             if newNode
520                 newList << newNode
521             end
522         }
523         
524         return newList
525     end
526     def getModifiedListX86_64_WIN
527         getModifiedListX86_64
528     end
529 end
530
531 class Instruction
532     
533     def x86Operands(*kinds)
534         raise unless kinds.size == operands.size
535         result = []
536         kinds.size.times {
537             | idx |
538             i = isIntelSyntax ? (kinds.size - idx - 1) : idx
539             result << operands[i].x86Operand(kinds[i])
540         }
541         result.join(", ")
542     end
543     
544     def x86LoadOperands(srcKind, dstKind)
545         orderOperands(operands[0].x86LoadOperand(srcKind, operands[1]), operands[1].x86Operand(dstKind))
546     end
547
548     def x86Suffix(kind)
549         if isIntelSyntax
550             return ""
551         end
552
553         case kind
554         when :byte
555             "b"
556         when :half
557             "w"
558         when :int
559             "l"
560         when :ptr
561             isX64 ? "q" : "l"
562         when :quad
563             isX64 ? "q" : raise
564         when :double
565             not useX87 ? "sd" : raise
566         else
567             raise
568         end
569     end
570     
571     def x86Bytes(kind)
572         case kind
573         when :byte
574             1
575         when :half
576             2
577         when :int
578             4
579         when :ptr
580             isX64 ? 8 : 4
581         when :quad
582             isX64 ? 8 : raise
583         when :double
584             8
585         else
586             raise
587         end
588     end
589
590     def emitX86Lea(src, dst, kind)
591         if src.is_a? LabelReference
592             $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
593         else
594             $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}"
595         end
596     end
597
598     def getImplicitOperandString
599         isIntelSyntax ? "st(0), " : ""
600     end
601     
602     def handleX86OpWithNumOperands(opcode, kind, numOperands)
603         if numOperands == 3
604             if operands[0] == operands[2]
605                 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
606             elsif operands[1] == operands[2]
607                 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
608             else
609                 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
610                 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
611             end
612         else
613             $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
614         end
615     end
616     
617     def handleX86Op(opcode, kind)
618         handleX86OpWithNumOperands(opcode, kind, operands.size)
619     end
620     
621     def handleX86Shift(opcode, kind)
622         if operands[0].is_a? Immediate or operands[0].x86GPR == "ecx"
623             $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
624         else
625             $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
626             $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
627             $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
628         end
629     end
630     
631     def handleX86DoubleBranch(branchOpcode, mode)
632         if useX87
633             handleX87Compare(mode)
634         else
635             case mode
636             when :normal
637                 $asm.puts "ucomisd #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}"
638             when :reverse
639                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
640             else
641                 raise mode.inspect
642             end
643         end
644         $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
645     end
646     
647     def handleX86IntCompare(opcodeSuffix, kind)
648         if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
649             $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
650         elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
651             $asm.puts "test#{x86Suffix(kind)}  #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
652         else
653             $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
654         end
655     end
656     
657     def handleX86IntBranch(branchOpcode, kind)
658         handleX86IntCompare(branchOpcode[1..-1], kind)
659         $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
660     end
661     
662     def handleX86Set(setOpcode, operand)
663         if operand.supports8BitOnX86
664             $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
665             if !isIntelSyntax
666                 $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
667             else
668                 $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
669             end
670         else
671             ax = RegisterID.new(nil, "r0")
672             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
673             $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}"
674             if !isIntelSyntax
675                 $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}"
676             else
677                 $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}"
678             end
679             $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
680         end
681     end
682     
683     def handleX86IntCompareSet(setOpcode, kind)
684         handleX86IntCompare(setOpcode[3..-1], kind)
685         handleX86Set(setOpcode, operands[2])
686     end
687     
688     def handleX86Test(kind)
689         value = operands[0]
690         case operands.size
691         when 2
692             mask = Immediate.new(codeOrigin, -1)
693         when 3
694             mask = operands[1]
695         else
696             raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
697         end
698         
699         if mask.is_a? Immediate and mask.value == -1
700             if value.is_a? RegisterID
701                 $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
702             else
703                 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
704             end
705         else
706             $asm.puts "test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
707         end
708     end
709     
710     def handleX86BranchTest(branchOpcode, kind)
711         handleX86Test(kind)
712         $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
713     end
714     
715     def handleX86SetTest(setOpcode, kind)
716         handleX86Test(kind)
717         handleX86Set(setOpcode, operands.last)
718     end
719     
720     def handleX86OpBranch(opcode, branchOpcode, kind)
721         handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
722         case operands.size
723         when 4
724             jumpTarget = operands[3]
725         when 3
726             jumpTarget = operands[2]
727         else
728             raise self.inspect
729         end
730         $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
731     end
732     
733     def handleX86SubBranch(branchOpcode, kind)
734         if operands.size == 4 and operands[1] == operands[2]
735             $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
736             $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
737         else
738             handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
739         end
740         case operands.size
741         when 4
742             jumpTarget = operands[3]
743         when 3
744             jumpTarget = operands[2]
745         else
746             raise self.inspect
747         end
748         $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
749     end
750
751     def handleX86Add(kind)
752         if operands.size == 3 and operands[1] == operands[2]
753             unless Immediate.new(nil, 0) == operands[0]
754                 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
755             end
756         elsif operands.size == 3 and operands[0].is_a? Immediate
757             raise unless operands[1].is_a? RegisterID
758             raise unless operands[2].is_a? RegisterID
759             if operands[0].value == 0
760                 unless operands[1] == operands[2]
761                     $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
762                 end
763             else
764                 $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
765             end
766         elsif operands.size == 3 and operands[0].is_a? RegisterID
767             raise unless operands[1].is_a? RegisterID
768             raise unless operands[2].is_a? RegisterID
769             if operands[0] == operands[2]
770                 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
771             else
772                 if !isIntelSyntax
773                     $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
774                 else
775                     $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
776                 end
777             end
778         else
779             unless Immediate.new(nil, 0) == operands[0]
780                 $asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
781             end
782         end
783     end
784     
785     def handleX86Sub(kind)
786         if operands.size == 3 and operands[1] == operands[2]
787             $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
788             $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
789         else
790             handleX86Op("sub#{x86Suffix(kind)}", kind)
791         end
792     end
793     
794     def handleX86Mul(kind)
795         if operands.size == 3 and operands[0].is_a? Immediate
796             $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
797         else
798             # FIXME: could do some peephole in case the left operand is immediate and it's
799             # a power of two.
800             handleX86Op("imul#{x86Suffix(kind)}", kind)
801         end
802     end
803     
804     def handleX86Peek()
805         sp = RegisterID.new(nil, "sp")
806         opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
807         opB = operands[1].x86Operand(:ptr)
808         $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
809     end
810
811     def handleX86Poke()
812         sp = RegisterID.new(nil, "sp")
813         opA = operands[0].x86Operand(:ptr)
814         opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
815         $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
816     end
817
818     def handleMove
819         if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
820             if isX64
821                 $asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
822             else
823                 $asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
824             end
825         elsif operands[0] != operands[1]
826             if isX64
827                 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
828             else
829                 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
830             end
831         end
832     end
833
834     def handleX87Compare(mode)
835         floatingPointCompareImplicitOperand = getImplicitOperandString
836         case mode
837         when :normal
838             if (operands[0].x87DefaultStackPosition == 0)
839                 $asm.puts "fucomi #{floatingPointCompareImplicitOperand}#{operands[1].x87Operand(0)}"
840             else
841                 $asm.puts "fld #{operands[0].x87Operand(0)}"
842                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[1].x87Operand(1)}"
843             end
844         when :reverse
845             if (operands[1].x87DefaultStackPosition == 0)
846                 $asm.puts "fucomi #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(0)}"
847             else
848                 $asm.puts "fld #{operands[1].x87Operand(0)}"
849                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
850             end
851         else
852             raise mode.inspect
853         end
854     end
855
856     def handleX87BinOp(opcode, opcodereverse)
857         if (operands[1].x87DefaultStackPosition == 0)
858             $asm.puts "#{opcode} #{orderOperands(operands[0].x87Operand(0), register("st"))}"
859         elsif (operands[0].x87DefaultStackPosition == 0)
860             if !isIntelSyntax
861                 $asm.puts "#{opcodereverse} #{register("st")}, #{operands[1].x87Operand(0)}"
862             else
863                 $asm.puts "#{opcode} #{operands[1].x87Operand(0)}, #{register("st")}"
864             end
865         else
866             $asm.puts "fld #{operands[0].x87Operand(0)}"
867             $asm.puts "#{opcodereverse}p #{orderOperands(register("st"), operands[1].x87Operand(1))}"
868         end
869     end
870
871     def lowerX86
872         raise unless $activeBackend == "X86"
873         lowerX86Common
874     end
875
876     def lowerX86_WIN
877         raise unless $activeBackend == "X86_WIN" 
878         lowerX86Common
879     end
880     
881     def lowerX86_64
882         raise unless $activeBackend == "X86_64"
883         lowerX86Common
884     end
885
886     def lowerX86_64_WIN
887         raise unless $activeBackend == "X86_64_WIN"
888         lowerX86Common
889     end
890
891     def lowerX86Common
892         case opcode
893         when "addi"
894             handleX86Add(:int)
895         when "addp"
896             handleX86Add(:ptr)
897         when "addq"
898             handleX86Add(:quad)
899         when "andi"
900             handleX86Op("and#{x86Suffix(:int)}", :int)
901         when "andp"
902             handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
903         when "andq"
904             handleX86Op("and#{x86Suffix(:quad)}", :quad)
905         when "lshifti"
906             handleX86Shift("sal#{x86Suffix(:int)}", :int)
907         when "lshiftp"
908             handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
909         when "lshiftq"
910             handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
911         when "muli"
912             handleX86Mul(:int)
913         when "mulp"
914             handleX86Mul(:ptr)
915         when "mulq"
916             handleX86Mul(:quad)
917         when "negi"
918             $asm.puts "neg#{x86Suffix(:int)} #{x86Operands(:int)}"
919         when "negp"
920             $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
921         when "negq"
922             $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
923         when "noti"
924             $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
925         when "ori"
926             handleX86Op("or#{x86Suffix(:int)}", :int)
927         when "orp"
928             handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
929         when "orq"
930             handleX86Op("or#{x86Suffix(:quad)}", :quad)
931         when "rshifti"
932             handleX86Shift("sar#{x86Suffix(:int)}", :int)
933         when "rshiftp"
934             handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
935         when "rshiftq"
936             handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
937         when "urshifti"
938             handleX86Shift("shr#{x86Suffix(:int)}", :int)
939         when "urshiftp"
940             handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
941         when "urshiftq"
942             handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
943         when "subi"
944             handleX86Sub(:int)
945         when "subp"
946             handleX86Sub(:ptr)
947         when "subq"
948             handleX86Sub(:quad)
949         when "xori"
950             handleX86Op("xor#{x86Suffix(:int)}", :int)
951         when "xorp"
952             handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
953         when "xorq"
954             handleX86Op("xor#{x86Suffix(:quad)}", :quad)
955         when "loadi"
956             $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
957         when "storei"
958             $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
959         when "loadis"
960             if isX64
961                 if !isIntelSyntax
962                     $asm.puts "movslq #{x86LoadOperands(:int, :quad)}"
963                 else
964                     $asm.puts "movsxd #{x86LoadOperands(:int, :quad)}"
965                 end
966             else
967                 $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
968             end
969         when "loadp"
970             $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}"
971         when "storep"
972             $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
973         when "loadq"
974             $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}"
975         when "storeq"
976             $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
977         when "loadb"
978             if !isIntelSyntax
979                 $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}"
980             else
981                 $asm.puts "movzx #{x86LoadOperands(:byte, :int)}"
982             end
983         when "loadbs"
984             if !isIntelSyntax
985                 $asm.puts "movsbl #{x86LoadOperands(:byte, :int)}"
986             else
987                 $asm.puts "movsx #{x86LoadOperands(:byte, :int)}"
988             end
989         when "loadh"
990             if !isIntelSyntax
991                 $asm.puts "movzwl #{x86LoadOperands(:half, :int)}"
992             else
993                 $asm.puts "movzx #{x86LoadOperands(:half, :int)}"
994             end
995         when "loadhs"
996             if !isIntelSyntax
997                 $asm.puts "movswl #{x86LoadOperands(:half, :int)}"
998             else
999                 $asm.puts "movsx #{x86LoadOperands(:half, :int)}"
1000             end
1001         when "storeb"
1002             $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
1003         when "loadd"
1004             if useX87
1005                 if !isIntelSyntax
1006                     $asm.puts "fldl #{operands[0].x86Operand(:double)}"
1007                 else
1008                     $asm.puts "fld #{operands[0].x86Operand(:double)}"
1009                 end
1010                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1011             else
1012                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1013             end
1014         when "moved"
1015             if useX87
1016                 if (operands[0].x87DefaultStackPosition == 0)
1017                     $asm.puts "fst #{operands[1].x87Operand(0)}"
1018                 else
1019                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1020                     $asm.puts "fstp #{operands[1].x87Operand(1)}"
1021                 end
1022             else
1023                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1024             end
1025         when "stored"
1026             if useX87
1027                 if (operands[0].x87DefaultStackPosition == 0)
1028                     $asm.puts "fst#{x86Suffix(:int)} #{operands[1].x86Operand(:double)}"
1029                 else
1030                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1031                     if !isIntelSyntax
1032                         $asm.puts "fstpl #{operands[1].x86Operand(:double)}"
1033                     else
1034                         $asm.puts "fstp #{operands[1].x86Operand(:double)}"
1035                     end
1036                 end
1037             else
1038                 $asm.puts "movsd #{x86Operands(:double, :double)}"
1039             end
1040         when "addd"
1041             if useX87
1042                 handleX87BinOp("fadd", "fadd")
1043             else
1044                 $asm.puts "addsd #{x86Operands(:double, :double)}"
1045             end
1046         when "muld"
1047             if useX87
1048                 handleX87BinOp("fmul", "fmul")
1049             else
1050                 $asm.puts "mulsd #{x86Operands(:double, :double)}"
1051             end
1052         when "subd"
1053             if useX87
1054                 handleX87BinOp("fsub", "fsubr")
1055             else
1056                 $asm.puts "subsd #{x86Operands(:double, :double)}"
1057             end
1058         when "divd"
1059             if useX87
1060                 handleX87BinOp("fdiv", "fdivr")
1061             else
1062                 $asm.puts "divsd #{x86Operands(:double, :double)}"
1063             end
1064         when "sqrtd"
1065             if useX87
1066                 $asm.puts "fld #{operands[0].x87Operand(0)}"
1067                 $asm.puts "fsqrtl"
1068                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1069             else
1070                 $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1071             end
1072         when "ci2d"
1073             if useX87
1074                 sp = RegisterID.new(nil, "sp")
1075                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1076                 $asm.puts "fild#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1077                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1078             else
1079                 $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}"
1080             end
1081         when "bdeq"
1082             if useX87
1083                 handleX87Compare(:normal)
1084             else
1085                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1086             end
1087             if operands[0] == operands[1]
1088                 # This is just a jump ordered, which is a jnp.
1089                 $asm.puts "jnp #{operands[2].asmLabel}"
1090             else
1091                 isUnordered = LocalLabel.unique("bdeq")
1092                 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1093                 $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
1094                 isUnordered.lower("X86")
1095             end
1096         when "bdneq"
1097             handleX86DoubleBranch("jne", :normal)
1098         when "bdgt"
1099             handleX86DoubleBranch("ja", :normal)
1100         when "bdgteq"
1101             handleX86DoubleBranch("jae", :normal)
1102         when "bdlt"
1103             handleX86DoubleBranch("ja", :reverse)
1104         when "bdlteq"
1105             handleX86DoubleBranch("jae", :reverse)
1106         when "bdequn"
1107             handleX86DoubleBranch("je", :normal)
1108         when "bdnequn"
1109             if useX87
1110                 handleX87Compare(:normal)
1111             else
1112                 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1113             end
1114             if operands[0] == operands[1]
1115                 # This is just a jump unordered, which is a jp.
1116                 $asm.puts "jp #{operands[2].asmLabel}"
1117             else
1118                 isUnordered = LocalLabel.unique("bdnequn")
1119                 isEqual = LocalLabel.unique("bdnequn")
1120                 $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
1121                 $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
1122                 isUnordered.lower("X86")
1123                 $asm.puts "jmp #{operands[2].asmLabel}"
1124                 isEqual.lower("X86")
1125             end
1126         when "bdgtun"
1127             handleX86DoubleBranch("jb", :reverse)
1128         when "bdgtequn"
1129             handleX86DoubleBranch("jbe", :reverse)
1130         when "bdltun"
1131             handleX86DoubleBranch("jb", :normal)
1132         when "bdltequn"
1133             handleX86DoubleBranch("jbe", :normal)
1134         when "btd2i"
1135             # FIXME: unused and unimplemented for x87
1136             raise if useX87
1137             $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1138             $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
1139             $asm.puts "je #{operands[2].asmLabel}"
1140         when "td2i"
1141             # FIXME: unused and unimplemented for x87
1142             raise if useX87
1143             $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1144         when "bcd2i"
1145             if useX87
1146                 floatingPointCompareImplicitOperand = getImplicitOperandString
1147                 sp = RegisterID.new(nil, "sp")
1148                 if (operands[0].x87DefaultStackPosition == 0)
1149                     $asm.puts "fistl -4(#{sp.x86Operand(:ptr)})"
1150                 else
1151                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1152                     $asm.puts "fistp#{x86Suffix(:ptr)} #{getSizeString(:ptr)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1153                 end
1154                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1155                 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1156                 $asm.puts "je #{operands[2].asmLabel}"
1157                 $asm.puts "fild#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-4, sp.x86Operand(:ptr))}"
1158                 $asm.puts "fucomip #{floatingPointCompareImplicitOperand}#{operands[0].x87Operand(1)}"
1159                 $asm.puts "jp #{operands[2].asmLabel}"
1160                 $asm.puts "jne #{operands[2].asmLabel}"
1161             else
1162                 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1163                 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1164                 $asm.puts "je #{operands[2].asmLabel}"
1165                 $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
1166                 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
1167                 $asm.puts "jp #{operands[2].asmLabel}"
1168                 $asm.puts "jne #{operands[2].asmLabel}"
1169             end
1170         when "movdz"
1171             if useX87
1172                 $asm.puts "fldzl"
1173                 $asm.puts "fstp #{operands[0].x87Operand(1)}"
1174             else
1175                 $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
1176             end
1177         when "pop"
1178             operands.each {
1179                 | op |
1180                 $asm.puts "pop #{op.x86Operand(:ptr)}"
1181             }
1182         when "push"
1183             operands.each {
1184                 | op |
1185                 $asm.puts "push #{op.x86Operand(:ptr)}"
1186             }
1187         when "move"
1188             handleMove
1189         when "sxi2q"
1190             if !isIntelSyntax
1191                 $asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
1192             else
1193                 $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:quad))}"
1194             end
1195         when "zxi2q"
1196             $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:int))}"
1197         when "nop"
1198             $asm.puts "nop"
1199         when "bieq"
1200             handleX86IntBranch("je", :int)
1201         when "bpeq"
1202             handleX86IntBranch("je", :ptr)
1203         when "bqeq"
1204             handleX86IntBranch("je", :quad)
1205         when "bineq"
1206             handleX86IntBranch("jne", :int)
1207         when "bpneq"
1208             handleX86IntBranch("jne", :ptr)
1209         when "bqneq"
1210             handleX86IntBranch("jne", :quad)
1211         when "bia"
1212             handleX86IntBranch("ja", :int)
1213         when "bpa"
1214             handleX86IntBranch("ja", :ptr)
1215         when "bqa"
1216             handleX86IntBranch("ja", :quad)
1217         when "biaeq"
1218             handleX86IntBranch("jae", :int)
1219         when "bpaeq"
1220             handleX86IntBranch("jae", :ptr)
1221         when "bqaeq"
1222             handleX86IntBranch("jae", :quad)
1223         when "bib"
1224             handleX86IntBranch("jb", :int)
1225         when "bpb"
1226             handleX86IntBranch("jb", :ptr)
1227         when "bqb"
1228             handleX86IntBranch("jb", :quad)
1229         when "bibeq"
1230             handleX86IntBranch("jbe", :int)
1231         when "bpbeq"
1232             handleX86IntBranch("jbe", :ptr)
1233         when "bqbeq"
1234             handleX86IntBranch("jbe", :quad)
1235         when "bigt"
1236             handleX86IntBranch("jg", :int)
1237         when "bpgt"
1238             handleX86IntBranch("jg", :ptr)
1239         when "bqgt"
1240             handleX86IntBranch("jg", :quad)
1241         when "bigteq"
1242             handleX86IntBranch("jge", :int)
1243         when "bpgteq"
1244             handleX86IntBranch("jge", :ptr)
1245         when "bqgteq"
1246             handleX86IntBranch("jge", :quad)
1247         when "bilt"
1248             handleX86IntBranch("jl", :int)
1249         when "bplt"
1250             handleX86IntBranch("jl", :ptr)
1251         when "bqlt"
1252             handleX86IntBranch("jl", :quad)
1253         when "bilteq"
1254             handleX86IntBranch("jle", :int)
1255         when "bplteq"
1256             handleX86IntBranch("jle", :ptr)
1257         when "bqlteq"
1258             handleX86IntBranch("jle", :quad)
1259         when "bbeq"
1260             handleX86IntBranch("je", :byte)
1261         when "bbneq"
1262             handleX86IntBranch("jne", :byte)
1263         when "bba"
1264             handleX86IntBranch("ja", :byte)
1265         when "bbaeq"
1266             handleX86IntBranch("jae", :byte)
1267         when "bbb"
1268             handleX86IntBranch("jb", :byte)
1269         when "bbbeq"
1270             handleX86IntBranch("jbe", :byte)
1271         when "bbgt"
1272             handleX86IntBranch("jg", :byte)
1273         when "bbgteq"
1274             handleX86IntBranch("jge", :byte)
1275         when "bblt"
1276             handleX86IntBranch("jl", :byte)
1277         when "bblteq"
1278             handleX86IntBranch("jlteq", :byte)
1279         when "btis"
1280             handleX86BranchTest("js", :int)
1281         when "btps"
1282             handleX86BranchTest("js", :ptr)
1283         when "btqs"
1284             handleX86BranchTest("js", :quad)
1285         when "btiz"
1286             handleX86BranchTest("jz", :int)
1287         when "btpz"
1288             handleX86BranchTest("jz", :ptr)
1289         when "btqz"
1290             handleX86BranchTest("jz", :quad)
1291         when "btinz"
1292             handleX86BranchTest("jnz", :int)
1293         when "btpnz"
1294             handleX86BranchTest("jnz", :ptr)
1295         when "btqnz"
1296             handleX86BranchTest("jnz", :quad)
1297         when "btbs"
1298             handleX86BranchTest("js", :byte)
1299         when "btbz"
1300             handleX86BranchTest("jz", :byte)
1301         when "btbnz"
1302             handleX86BranchTest("jnz", :byte)
1303         when "jmp"
1304             $asm.puts "jmp #{operands[0].x86CallOperand(:ptr)}"
1305         when "baddio"
1306             handleX86OpBranch("add#{x86Suffix(:int)}", "jo", :int)
1307         when "baddpo"
1308             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
1309         when "baddqo"
1310             handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
1311         when "baddis"
1312             handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int)
1313         when "baddps"
1314             handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
1315         when "baddqs"
1316             handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
1317         when "baddiz"
1318             handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int)
1319         when "baddpz"
1320             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
1321         when "baddqz"
1322             handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
1323         when "baddinz"
1324             handleX86OpBranch("add#{x86Suffix(:int)}", "jnz", :int)
1325         when "baddpnz"
1326             handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
1327         when "baddqnz"
1328             handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
1329         when "bsubio"
1330             handleX86SubBranch("jo", :int)
1331         when "bsubis"
1332             handleX86SubBranch("js", :int)
1333         when "bsubiz"
1334             handleX86SubBranch("jz", :int)
1335         when "bsubinz"
1336             handleX86SubBranch("jnz", :int)
1337         when "bmulio"
1338             handleX86OpBranch("imul#{x86Suffix(:int)}", "jo", :int)
1339         when "bmulis"
1340             handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int)
1341         when "bmuliz"
1342             handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int)
1343         when "bmulinz"
1344             handleX86OpBranch("imul#{x86Suffix(:int)}", "jnz", :int)
1345         when "borio"
1346             handleX86OpBranch("orl", "jo", :int)
1347         when "boris"
1348             handleX86OpBranch("orl", "js", :int)
1349         when "boriz"
1350             handleX86OpBranch("orl", "jz", :int)
1351         when "borinz"
1352             handleX86OpBranch("orl", "jnz", :int)
1353         when "break"
1354             $asm.puts "int #{const(3)}"
1355         when "call"
1356             if useX87
1357                 2.times {
1358                     | offset |
1359                     $asm.puts "ffree #{register("st")}(#{offset})"
1360                 }
1361             end
1362             op = operands[0].x86CallOperand(:ptr)
1363             if operands[0].is_a? LabelReference
1364                 operands[0].used
1365             end
1366             $asm.puts "call #{op}"
1367         when "ret"
1368             $asm.puts "ret"
1369         when "cieq"
1370             handleX86IntCompareSet("sete", :int)
1371         when "cbeq"
1372             handleX86IntCompareSet("sete", :byte)
1373         when "cpeq"
1374             handleX86IntCompareSet("sete", :ptr)
1375         when "cqeq"
1376             handleX86IntCompareSet("sete", :quad)
1377         when "cineq"
1378             handleX86IntCompareSet("setne", :int)
1379         when "cbneq"
1380             handleX86IntCompareSet("setne", :byte)
1381         when "cpneq"
1382             handleX86IntCompareSet("setne", :ptr)
1383         when "cqneq"
1384             handleX86IntCompareSet("setne", :quad)
1385         when "cia"
1386             handleX86IntCompareSet("seta", :int)
1387         when "cba"
1388             handleX86IntCompareSet("seta", :byte)
1389         when "cpa"
1390             handleX86IntCompareSet("seta", :ptr)
1391         when "cqa"
1392             handleX86IntCompareSet("seta", :quad)
1393         when "ciaeq"
1394             handleX86IntCompareSet("setae", :int)
1395         when "cbaeq"
1396             handleX86IntCompareSet("setae", :byte)
1397         when "cpaeq"
1398             handleX86IntCompareSet("setae", :ptr)
1399         when "cqaeq"
1400             handleX86IntCompareSet("setae", :quad)
1401         when "cib"
1402             handleX86IntCompareSet("setb", :int)
1403         when "cbb"
1404             handleX86IntCompareSet("setb", :byte)
1405         when "cpb"
1406             handleX86IntCompareSet("setb", :ptr)
1407         when "cqb"
1408             handleX86IntCompareSet("setb", :quad)
1409         when "cibeq"
1410             handleX86IntCompareSet("setbe", :int)
1411         when "cbbeq"
1412             handleX86IntCompareSet("setbe", :byte)
1413         when "cpbeq"
1414             handleX86IntCompareSet("setbe", :ptr)
1415         when "cqbeq"
1416             handleX86IntCompareSet("setbe", :quad)
1417         when "cigt"
1418             handleX86IntCompareSet("setg", :int)
1419         when "cbgt"
1420             handleX86IntCompareSet("setg", :byte)
1421         when "cpgt"
1422             handleX86IntCompareSet("setg", :ptr)
1423         when "cqgt"
1424             handleX86IntCompareSet("setg", :quad)
1425         when "cigteq"
1426             handleX86IntCompareSet("setge", :int)
1427         when "cbgteq"
1428             handleX86IntCompareSet("setge", :byte)
1429         when "cpgteq"
1430             handleX86IntCompareSet("setge", :ptr)
1431         when "cqgteq"
1432             handleX86IntCompareSet("setge", :quad)
1433         when "cilt"
1434             handleX86IntCompareSet("setl", :int)
1435         when "cblt"
1436             handleX86IntCompareSet("setl", :byte)
1437         when "cplt"
1438             handleX86IntCompareSet("setl", :ptr)
1439         when "cqlt"
1440             handleX86IntCompareSet("setl", :quad)
1441         when "cilteq"
1442             handleX86IntCompareSet("setle", :int)
1443         when "cblteq"
1444             handleX86IntCompareSet("setle", :byte)
1445         when "cplteq"
1446             handleX86IntCompareSet("setle", :ptr)
1447         when "cqlteq"
1448             handleX86IntCompareSet("setle", :quad)
1449         when "tis"
1450             handleX86SetTest("sets", :int)
1451         when "tiz"
1452             handleX86SetTest("setz", :int)
1453         when "tinz"
1454             handleX86SetTest("setnz", :int)
1455         when "tps"
1456             handleX86SetTest("sets", :ptr)
1457         when "tpz"
1458             handleX86SetTest("setz", :ptr)
1459         when "tpnz"
1460             handleX86SetTest("setnz", :ptr)
1461         when "tqs"
1462             handleX86SetTest("sets", :quad)
1463         when "tqz"
1464             handleX86SetTest("setz", :quad)
1465         when "tqnz"
1466             handleX86SetTest("setnz", :quad)
1467         when "tbs"
1468             handleX86SetTest("sets", :byte)
1469         when "tbz"
1470             handleX86SetTest("setz", :byte)
1471         when "tbnz"
1472             handleX86SetTest("setnz", :byte)
1473         when "peek"
1474             handleX86Peek()
1475         when "poke"
1476             handleX86Poke()
1477         when "cdqi"
1478             $asm.puts "cdq"
1479         when "idivi"
1480             $asm.puts "idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1481         when "fii2d"
1482             if useX87
1483                 sp = RegisterID.new(nil, "sp")
1484                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), offsetRegister(-8, sp.x86Operand(:ptr)))}"
1485                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), offsetRegister(-4, sp.x86Operand(:ptr)))}"
1486                 $asm.puts "fld#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1487                 $asm.puts "fstp #{operands[2].x87Operand(1)}"
1488             else
1489                 $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
1490                 $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
1491                 $asm.puts "psllq $32, %xmm7"
1492                 $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
1493             end
1494         when "fd2ii"
1495             if useX87
1496                 sp = RegisterID.new(nil, "sp")
1497                 if (operands[0].x87DefaultStackPosition == 0)
1498                     $asm.puts "fst#{x86Suffix(:ptr)} #{getSizeString(:double)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1499                 else
1500                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1501                     $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1502                 end
1503                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-8, sp.x86Operand(:ptr)), operands[1].x86Operand(:int))}"
1504                 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(offsetRegister(-4, sp.x86Operand(:ptr)), operands[2].x86Operand(:int))}"
1505             else
1506                 $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1507                 $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
1508                 $asm.puts "psrlq $32, %xmm7"
1509                 $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
1510             end
1511         when "fq2d"
1512             if useX87
1513                 sp = RegisterID.new(nil, "sp")
1514                 $asm.puts "movq #{operands[0].x86Operand(:quad)}, -8(#{sp.x86Operand(:ptr)})"
1515                 $asm.puts "fldl -8(#{sp.x86Operand(:ptr)})"
1516                 $asm.puts "fstp #{operands[1].x87Operand(1)}"
1517             else
1518                 if !isIntelSyntax
1519                     $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
1520                 else
1521                     # MASM does not accept register operands with movq.
1522                     # Debugging shows that movd actually moves a qword when using MASM.
1523                     $asm.puts "movd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:quad)}"
1524                 end
1525             end
1526         when "fd2q"
1527             if useX87
1528                 sp = RegisterID.new(nil, "sp")
1529                 if (operands[0].x87DefaultStackPosition == 0)
1530                     $asm.puts "fst#{x86Suffix(:int)} #{getSizeString(:int)}#{offsetRegister(-8, sp.x86Operand(:ptr))}"
1531                 else
1532                     $asm.puts "fld #{operands[0].x87Operand(0)}"
1533                     $asm.puts "fstpl -8(#{sp.x86Operand(:ptr)})"
1534                 end
1535                 $asm.puts "movq -8(#{sp.x86Operand(:ptr)}), #{operands[1].x86Operand(:quad)}"
1536             else
1537                 if !isIntelSyntax
1538                     $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1539                 else
1540                     # MASM does not accept register operands with movq.
1541                     # Debugging shows that movd actually moves a qword when using MASM.
1542                     $asm.puts "movd #{operands[1].x86Operand(:quad)}, #{operands[0].x86Operand(:double)}"
1543                 end
1544             end
1545         when "bo"
1546             $asm.puts "jo #{operands[0].asmLabel}"
1547         when "bs"
1548             $asm.puts "js #{operands[0].asmLabel}"
1549         when "bz"
1550             $asm.puts "jz #{operands[0].asmLabel}"
1551         when "bnz"
1552             $asm.puts "jnz #{operands[0].asmLabel}"
1553         when "leai"
1554             emitX86Lea(operands[0], operands[1], :int)
1555         when "leap"
1556             emitX86Lea(operands[0], operands[1], :ptr)
1557         when "memfence"
1558             sp = RegisterID.new(nil, "sp")
1559             if isIntelSyntax
1560                 $asm.puts "mfence"
1561             else
1562                 $asm.puts "lock; orl $0, (#{sp.x86Operand(:ptr)})"
1563             end
1564         else
1565             lowerDefault
1566         end
1567     end
1568 end
1569