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