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