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