source: webkit/trunk/Source/JavaScriptCore/offlineasm/x86.rb

Last change on this file was 286356, checked in by [email protected], 3 years ago

[JSC] Remove debug print left over from previous patch
https://bugs.webkit.org/show_bug.cgi?id=233692

Unreviewed follow-up patch.

Patch by Xan Lopez <Xan Lopez> on 2021-12-01

  • offlineasm/x86.rb: remove debug print.
File size: 71.6 KB
Line 
1# Copyright (C) 2012-2020 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
27# GPR conventions, to match the baseline JIT:
28#
29#
30# On x86-32 bits (windows and non-windows)
31# a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not
32# actually considered as such by the ABI and we need to push/pop our arguments
33# on the stack. a0 and a1 are ecx and edx to follow fastcall.
34#
35# eax => t0, a2, r0
36# edx => t1, a1, r1
37# ecx => t2, a0
38# ebx => t3, a3 (callee-save)
39# esi => t4 (callee-save)
40# edi => t5 (callee-save)
41# ebp => cfr
42# esp => sp
43#
44# On x86-64 non-windows
45#
46# rax => t0, r0
47# rdi => a0
48# rsi => t1, a1
49# rdx => t2, a2, r1
50# rcx => t3, a3
51# r8 => t4
52# r9 => t5
53# r10 => t6
54# rbx => csr0 (callee-save, wasmInstance)
55# r12 => csr1 (callee-save, metadataTable)
56# r13 => csr2 (callee-save, PB)
57# r14 => csr3 (callee-save, tagTypeNumber)
58# r15 => csr4 (callee-save, tagMask)
59# rsp => sp
60# rbp => cfr
61# r11 => (scratch)
62#
63# On x86-64 windows
64# Arguments need to be push/pop'd on the stack in addition to being stored in
65# the registers. Also, >8 return types are returned in a weird way.
66#
67# rax => t0, r0
68# rcx => t5, a0
69# rdx => t1, a1, r1
70# r8 => t2, a2
71# r9 => t3, a3
72# r10 => t4
73# rbx => csr0 (callee-save, PB, unused in baseline)
74# rsi => csr1 (callee-save)
75# rdi => csr2 (callee-save)
76# r12 => csr3 (callee-save)
77# r13 => csr4 (callee-save)
78# r14 => csr5 (callee-save, numberTag)
79# r15 => csr6 (callee-save, notCellMask)
80# rsp => sp
81# rbp => cfr
82# r11 => (scratch)
83
84def isX64
85 case $activeBackend
86 when "X86"
87 false
88 when "X86_WIN"
89 false
90 when "X86_64"
91 true
92 when "X86_64_WIN"
93 true
94 else
95 raise "bad value for $activeBackend: #{$activeBackend}"
96 end
97end
98
99def isWin
100 case $activeBackend
101 when "X86"
102 false
103 when "X86_WIN"
104 true
105 when "X86_64"
106 false
107 when "X86_64_WIN"
108 true
109 else
110 raise "bad value for $activeBackend: #{$activeBackend}"
111 end
112end
113
114def isMSVC
115 $options.has_key?(:assembler) && $options[:assembler] == "MASM"
116end
117
118def isIntelSyntax
119 $options.has_key?(:assembler) && $options[:assembler] == "MASM"
120end
121
122def register(name)
123 isIntelSyntax ? name : "%" + name
124end
125
126def offsetRegister(off, register)
127 isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})"
128end
129
130def callPrefix
131 isIntelSyntax ? "" : "*"
132end
133
134def orderOperands(*operands)
135 (isIntelSyntax ? operands.reverse : operands).join(", ")
136end
137
138def const(c)
139 isIntelSyntax ? "#{c}" : "$#{c}"
140end
141
142def getSizeString(kind)
143 if !isIntelSyntax
144 return ""
145 end
146
147 size = ""
148 case kind
149 when :byte
150 size = "byte"
151 when :half
152 size = "word"
153 when :int
154 size = "dword"
155 when :ptr
156 size = isX64 ? "qword" : "dword"
157 when :float
158 size = "dword"
159 when :double
160 size = "qword"
161 when :quad
162 size = "qword"
163 else
164 raise "Invalid kind #{kind}"
165 end
166
167 return size + " " + "ptr" + " ";
168end
169
170class SpecialRegister < NoChildren
171 def x86Operand(kind)
172 raise unless @name =~ /^r/
173 raise unless isX64
174 case kind
175 when :half
176 register(@name + "w")
177 when :int
178 register(@name + "d")
179 when :ptr
180 register(@name)
181 when :quad
182 register(@name)
183 else
184 raise codeOriginString
185 end
186 end
187 def x86CallOperand(kind)
188 # Call operands are not allowed to be partial registers.
189 "#{callPrefix}#{x86Operand(:quad)}"
190 end
191end
192
193X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
194
195def x86GPRName(name, kind)
196 case name
197 when "eax", "ebx", "ecx", "edx"
198 name8 = name[1] + 'l'
199 name16 = name[1..2]
200 when "esi", "edi", "ebp", "esp"
201 name16 = name[1..2]
202 name8 = name16 + 'l'
203 when "rax", "rbx", "rcx", "rdx"
204 raise "bad GPR name #{name} in 32-bit X86" unless isX64
205 name8 = name[1] + 'l'
206 name16 = name[1..2]
207 when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
208 raise "bad GPR name #{name} in 32-bit X86" unless isX64
209 case kind
210 when :half
211 return register(name + "w")
212 when :int
213 return register(name + "d")
214 when :ptr
215 return register(name)
216 when :quad
217 return register(name)
218 end
219 else
220 raise "bad GPR name #{name}"
221 end
222 case kind
223 when :byte
224 register(name8)
225 when :half
226 register(name16)
227 when :int
228 register("e" + name16)
229 when :ptr
230 register((isX64 ? "r" : "e") + name16)
231 when :quad
232 isX64 ? register("r" + name16) : raise
233 else
234 raise "invalid kind #{kind} for GPR #{name} in X86"
235 end
236end
237
238class Node
239 def x86LoadOperand(type, dst)
240 x86Operand(type)
241 end
242end
243
244class RegisterID
245 def supports8BitOnX86
246 case x86GPR
247 when "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"
248 true
249 when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
250 false
251 else
252 raise
253 end
254 end
255
256 def x86GPR
257 if isX64
258 case name
259 when "t0", "r0", "ws0"
260 "eax"
261 when "r1"
262 "edx" # t1 = a1 when isWin, t2 = a2 otherwise
263 when "a0", "wa0"
264 isWin ? "ecx" : "edi"
265 when "t1", "a1", "wa1"
266 isWin ? "edx" : "esi"
267 when "t2", "a2", "wa2"
268 isWin ? "r8" : "edx"
269 when "t3", "a3", "wa3"
270 isWin ? "r9" : "ecx"
271 when "t4", "wa4"
272 isWin ? "r10" : "r8"
273 when "t5", "wa5"
274 isWin ? "ecx" : "r9"
275 when "t6", "ws1"
276 raise "cannot use register #{name} on X86-64 Windows" if isWin
277 "r10"
278 when "csr0"
279 "ebx"
280 when "csr1"
281 isWin ? "esi" : "r12"
282 when "csr2"
283 isWin ? "edi" : "r13"
284 when "csr3"
285 isWin ? "r12" : "r14"
286 when "csr4"
287 isWin ? "r13" : "r15"
288 when "csr5"
289 raise "cannot use register #{name} on X86-64" unless isWin
290 "r14"
291 when "csr6"
292 raise "cannot use register #{name} on X86-64" unless isWin
293 "r15"
294 when "cfr"
295 "ebp"
296 when "sp"
297 "esp"
298 else
299 raise "cannot use register #{name} on X86"
300 end
301 else
302 case name
303 when "t0", "r0", "a2"
304 "eax"
305 when "t1", "r1", "a1"
306 "edx"
307 when "t2", "a0"
308 "ecx"
309 when "t3", "a3"
310 "ebx"
311 when "t4"
312 "esi"
313 when "t5"
314 "edi"
315 when "cfr"
316 "ebp"
317 when "sp"
318 "esp"
319 end
320 end
321 end
322
323 def x86Operand(kind)
324 x86GPRName(x86GPR, kind)
325 end
326
327 def x86CallOperand(kind)
328 "#{callPrefix}#{x86Operand(:ptr)}"
329 end
330end
331
332class FPRegisterID
333 def x86Operand(kind)
334 raise unless [:float, :double].include? kind
335 case name
336 when "ft0", "fa0", "fr", "wfa0"
337 register("xmm0")
338 when "ft1", "fa1", "wfa1"
339 register("xmm1")
340 when "ft2", "fa2", "wfa2"
341 register("xmm2")
342 when "ft3", "fa3", "wfa3"
343 register("xmm3")
344 when "ft4", "wfa4"
345 register("xmm4")
346 when "ft5", "wfa5"
347 register("xmm5")
348 when "wfa6"
349 register("xmm6")
350 when "wfa7"
351 register("xmm7")
352 else
353 raise "Bad register #{name} for X86 at #{codeOriginString}"
354 end
355 end
356 def x86CallOperand(kind)
357 "#{callPrefix}#{x86Operand(kind)}"
358 end
359end
360
361class Immediate
362 def validX86Immediate?
363 if isX64
364 value >= -0x80000000 and value <= 0x7fffffff
365 else
366 true
367 end
368 end
369 def x86Operand(kind)
370 "#{const(value)}"
371 end
372 def x86CallOperand(kind)
373 "#{value}"
374 end
375end
376
377class Address
378 def supports8BitOnX86
379 true
380 end
381
382 def x86AddressOperand(addressKind)
383 "#{offsetRegister(offset.value, base.x86Operand(addressKind))}"
384 end
385 def x86Operand(kind)
386 "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}"
387 end
388 def x86CallOperand(kind)
389 "#{callPrefix}#{x86Operand(kind)}"
390 end
391end
392
393class BaseIndex
394 def supports8BitOnX86
395 true
396 end
397
398 def x86AddressOperand(addressKind)
399 if !isIntelSyntax
400 "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scaleValue})"
401 else
402 "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scaleValue}]"
403 end
404 end
405
406 def x86Operand(kind)
407 if !isIntelSyntax
408 x86AddressOperand(:ptr)
409 else
410 "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scaleValue}]"
411 end
412 end
413
414 def x86CallOperand(kind)
415 "#{callPrefix}#{x86Operand(kind)}"
416 end
417end
418
419class AbsoluteAddress
420 def supports8BitOnX86
421 true
422 end
423
424 def x86AddressOperand(addressKind)
425 "#{address.value}"
426 end
427
428 def x86Operand(kind)
429 "#{address.value}"
430 end
431
432 def x86CallOperand(kind)
433 "#{callPrefix}#{address.value}"
434 end
435end
436
437class LabelReference
438 def x86CallOperand(kind)
439 asmLabel
440 end
441 def x86LoadOperand(kind, dst)
442 # FIXME: Implement this on platforms that aren't Mach-O.
443 # https://bugs.webkit.org/show_bug.cgi?id=175104
444 used
445 if !isIntelSyntax
446 $asm.puts "movq #{asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
447 else
448 $asm.puts "lea #{dst.x86Operand(:ptr)}, #{asmLabel}"
449 end
450 offsetRegister(offset, dst.x86Operand(:ptr))
451 end
452end
453
454class LocalLabelReference
455 def x86Operand(kind)
456 asmLabel
457 end
458 def x86CallOperand(kind)
459 asmLabel
460 end
461end
462
463class Sequence
464 def getModifiedListX86_64
465 newList = []
466
467 @list.each {
468 | node |
469 newNode = node
470 if node.is_a? Instruction
471 unless node.opcode == "move"
472 usedScratch = false
473 newOperands = node.operands.map {
474 | operand |
475 if operand.immediate? and not operand.validX86Immediate?
476 if usedScratch
477 raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
478 end
479 newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
480 usedScratch = true
481 X64_SCRATCH_REGISTER
482 else
483 operand
484 end
485 }
486 newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
487 end
488 else
489 unless node.is_a? Label or
490 node.is_a? LocalLabel or
491 node.is_a? Skip
492 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
493 end
494 end
495 if newNode
496 newList << newNode
497 end
498 }
499
500 return newList
501 end
502 def getModifiedListX86_64_WIN
503 getModifiedListX86_64
504 end
505end
506
507class Instruction
508
509 def x86Operands(*kinds)
510 raise "Expected size of kinds to be #{operands.size}, but it was #{kinds.size}" unless kinds.size == operands.size
511 result = []
512 kinds.size.times {
513 | idx |
514 i = isIntelSyntax ? (kinds.size - idx - 1) : idx
515 result << operands[i].x86Operand(kinds[i])
516 }
517 result.join(", ")
518 end
519
520 def x86LoadOperands(srcKind, dstKind)
521 orderOperands(operands[0].x86LoadOperand(srcKind, operands[1]), operands[1].x86Operand(dstKind))
522 end
523
524 def x86Suffix(kind)
525 if isIntelSyntax and not [:float, :double].include? kind
526 return ""
527 end
528
529 case kind
530 when :byte
531 "b"
532 when :half
533 "w"
534 when :int
535 "l"
536 when :ptr
537 isX64 ? "q" : "l"
538 when :quad
539 isX64 ? "q" : raise
540 when :float
541 "ss"
542 when :double
543 "sd"
544 else
545 raise
546 end
547 end
548
549 def x86Bytes(kind)
550 case kind
551 when :byte
552 1
553 when :half
554 2
555 when :int
556 4
557 when :ptr
558 isX64 ? 8 : 4
559 when :quad
560 isX64 ? 8 : raise
561 when :float
562 4
563 when :double
564 8
565 else
566 raise
567 end
568 end
569
570 def emitX86Lea(src, dst, kind)
571 if src.is_a? LabelReference
572 src.used
573 if !isIntelSyntax
574 $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
575 else
576 $asm.puts "lea #{dst.x86Operand(:ptr)}, #{src.asmLabel}"
577 end
578 if src.offset != 0
579 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(const(src.offset), dst.x86Operand(kind))}"
580 end
581 else
582 $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}"
583 end
584 end
585
586 def getImplicitOperandString
587 isIntelSyntax ? "st(0), " : ""
588 end
589
590 def handleX86OpWithNumOperands(opcode, kind, numOperands)
591 if numOperands == 3
592 if operands[0] == operands[2]
593 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
594 elsif operands[1] == operands[2]
595 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
596 else
597 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
598 $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
599 end
600 else
601 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
602 end
603 end
604
605 def handleX86Op(opcode, kind)
606 handleX86OpWithNumOperands(opcode, kind, operands.size)
607 end
608
609 def handleX86Shift(opcode, kind)
610 if operands[0].is_a? Immediate or operands[0].x86GPR == "ecx"
611 $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
612 else
613 $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
614 $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
615 $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
616 end
617 end
618
619 def handleX86FPBranch(kind, branchOpcode, mode)
620 case mode
621 when :normal
622 $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}"
623 when :reverse
624 $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
625 else
626 raise mode.inspect
627 end
628 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
629 end
630
631 def handleX86IntCompare(opcodeSuffix, kind)
632 if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
633 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
634 elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
635 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
636 else
637 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
638 end
639 end
640
641 def handleX86IntCompare(opcodeSuffix, kind)
642 if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
643 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
644 elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
645 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
646 else
647 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
648 end
649 end
650
651 def handleX86IntBranch(branchOpcode, kind)
652 handleX86IntCompare(branchOpcode[1..-1], kind)
653 $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
654 end
655
656 def handleX86Set(setOpcode, operand)
657 if operand.supports8BitOnX86
658 $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
659 if !isIntelSyntax
660 $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
661 else
662 $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
663 end
664 else
665 ax = RegisterID.new(nil, "r0")
666 $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
667 $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}"
668 if !isIntelSyntax
669 $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}"
670 else
671 $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}"
672 end
673 $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
674 end
675 end
676
677 def handleX86IntCompareSet(setOpcode, kind)
678 handleX86IntCompare(setOpcode[3..-1], kind)
679 handleX86Set(setOpcode, operands[2])
680 end
681
682 def handleX86FPCompareSet(kind, setOpcode, order = :normal)
683 is_special = setOpcode.is_a? Symbol
684 left = operands[0]
685 right = operands[1]
686 target = operands[2]
687
688 compare = lambda do |lhs, rhs|
689 $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(lhs.x86Operand(:double), rhs.x86Operand(:double))}"
690 end
691
692 if is_special
693 case setOpcode
694 when :eq
695 if left == right
696 compare.call(right, left)
697 handleX86Set("setnp", operands[2])
698 return
699 end
700
701 isUnordered = LocalLabel.unique("isUnordered")
702 $asm.puts "movq $0, #{target.x86Operand(:quad)}"
703 compare.call(right, left)
704 $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
705 handleX86Set("sete", target)
706 isUnordered.lower($activeBackend)
707 return
708 when :nequn
709 if left == right
710 compare.call(right, left)
711 handleX86Set("setp", target)
712 return
713 end
714
715 isUnordered = LocalLabel.unique("isUnordered")
716 $asm.puts "movq $1, #{target.x86Operand(:quad)}"
717 compare.call(right, left);
718 $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
719 handleX86Set("setne", target)
720 isUnordered.lower($activeBackend)
721 return
722 else
723 raise "Uhandled special opcode: #{setOpcode}"
724 end
725 end
726
727 if order == :normal
728 compare.call(right, left)
729 else
730 compare.call(left, right)
731 end
732 handleX86Set(setOpcode, target)
733 end
734
735 def handleX86Test(kind)
736 value = operands[0]
737 case operands.size
738 when 2
739 mask = Immediate.new(codeOrigin, -1)
740 when 3
741 mask = operands[1]
742 else
743 raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
744 end
745
746 if mask.is_a? Immediate and mask.value == -1
747 if value.is_a? RegisterID
748 $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
749 else
750 $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
751 end
752 else
753 $asm.puts "test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
754 end
755 end
756
757 def handleX86BranchTest(branchOpcode, kind)
758 handleX86Test(kind)
759 $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
760 end
761
762 def handleX86SetTest(setOpcode, kind)
763 handleX86Test(kind)
764 handleX86Set(setOpcode, operands.last)
765 end
766
767 def handleX86OpBranch(opcode, branchOpcode, kind)
768 handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
769 case operands.size
770 when 4
771 jumpTarget = operands[3]
772 when 3
773 jumpTarget = operands[2]
774 else
775 raise self.inspect
776 end
777 $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
778 end
779
780 def handleX86SubBranch(branchOpcode, kind)
781 if operands.size == 4 and operands[1] == operands[2]
782 $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
783 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
784 else
785 handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
786 end
787 case operands.size
788 when 4
789 jumpTarget = operands[3]
790 when 3
791 jumpTarget = operands[2]
792 else
793 raise self.inspect
794 end
795 $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
796 end
797
798 def handleX86Add(kind)
799 if operands.size == 3 and operands[1] == operands[2]
800 unless Immediate.new(nil, 0) == operands[0]
801 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
802 end
803 elsif operands.size == 3 and operands[0].is_a? Immediate
804 raise unless operands[1].is_a? RegisterID
805 raise unless operands[2].is_a? RegisterID
806 if operands[0].value == 0
807 if operands[1] != operands[2]
808 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
809 end
810 else
811 $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
812 end
813 elsif operands.size == 3 and operands[0].is_a? RegisterID
814 raise unless operands[1].is_a? RegisterID
815 raise unless operands[2].is_a? RegisterID
816 if operands[0] == operands[2]
817 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
818 else
819 if !isIntelSyntax
820 $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
821 else
822 $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
823 end
824 end
825 else
826 unless Immediate.new(nil, 0) == operands[0]
827 $asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
828 end
829 end
830 end
831
832 def handleX86Sub(kind)
833 if operands.size == 3
834 if Immediate.new(nil, 0) == operands[1]
835 raise unless operands[0].is_a? RegisterID
836 raise unless operands[2].is_a? RegisterID
837 if operands[0] != operands[2]
838 $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
839 end
840 return
841 end
842 if operands[1] == operands[2]
843 $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
844 if Immediate.new(nil, 0) != operands[0]
845 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
846 end
847 return
848 end
849 end
850
851 if operands.size == 2
852 if Immediate.new(nil, 0) == operands[0]
853 return
854 end
855 end
856
857 handleX86Op("sub#{x86Suffix(kind)}", kind)
858 end
859
860 def handleX86Mul(kind)
861 if operands.size == 3 and operands[0].is_a? Immediate
862 $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
863 return
864 end
865
866 if operands.size == 2 and operands[0].is_a? Immediate
867 imm = operands[0].value
868 if imm > 0 and isPowerOfTwo(imm)
869 $asm.puts "sal#{x86Suffix(kind)} #{orderOperands(Immediate.new(nil, Math.log2(imm).to_i).x86Operand(kind), operands[1].x86Operand(kind))}"
870 return
871 end
872 end
873
874 handleX86Op("imul#{x86Suffix(kind)}", kind)
875 end
876
877 def handleX86AddFP(kind)
878 if operands.size == 2
879 $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
880 elsif operands.size == 3
881 $asm.puts "vadd#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
882 else
883 raise "Unexpected number of operands for floating point addition: #{operands.size}"
884 end
885 end
886
887 def handleX86SubFP(kind)
888 if operands.size == 2
889 $asm.puts "sub#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
890 elsif operands.size == 3
891 $asm.puts "vsub#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
892 else
893 raise "Unexpected number of operands for floating point addition: #{operands.size}"
894 end
895 end
896
897 def handleX86MulFP(kind)
898 if operands.size == 2
899 $asm.puts "mul#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
900 elsif operands.size == 3
901 $asm.puts "vmul#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
902 else
903 raise "Unexpected number of operands for floating point addition: #{operands.size}"
904 end
905 end
906
907 def handleX86DivFP(kind)
908 if operands.size == 2
909 $asm.puts "div#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
910 elsif operands.size == 3
911 $asm.puts "vdiv#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
912 else
913 raise "Unexpected number of operands for floating point addition: #{operands.size}"
914 end
915 end
916
917 def handleX86Peek()
918 sp = RegisterID.new(nil, "sp")
919 opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
920 opB = operands[1].x86Operand(:ptr)
921 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
922 end
923
924 def handleX86Poke()
925 sp = RegisterID.new(nil, "sp")
926 opA = operands[0].x86Operand(:ptr)
927 opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
928 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
929 end
930
931 def handleMove
932 if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
933 if isX64
934 $asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
935 else
936 $asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
937 end
938 elsif operands[0] != operands[1]
939 if isX64
940 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
941 else
942 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
943 end
944 end
945 end
946
947 def countLeadingZeros(kind)
948 target = operands[1]
949 srcIsNonZero = LocalLabel.unique("srcIsNonZero")
950 skipNonZeroCase = LocalLabel.unique("skipNonZeroCase")
951 zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8)
952 xorValue = Immediate.new(codeOrigin, kind == :quad ? 0x3f : 0x1f)
953 xor = kind == :quad ? "xorq" : "xori"
954
955 $asm.puts "bsr#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
956
957 Sequence.new(codeOrigin, [
958 Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]),
959 Instruction.new(codeOrigin, "move", [zeroValue, target]),
960 Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, skipNonZeroCase)]),
961
962 srcIsNonZero,
963 Instruction.new(codeOrigin, xor, [xorValue, target]),
964
965 skipNonZeroCase,
966 ]).lower($activeBackend)
967 end
968
969 def countTrailingZeros(kind)
970 target = operands[1]
971 srcIsNonZero = LocalLabel.unique("srcIsNonZero")
972 zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8)
973
974 $asm.puts "bsf#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
975
976 Sequence.new(codeOrigin, [
977 Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]),
978 Instruction.new(codeOrigin, "move", [zeroValue, target]),
979 srcIsNonZero,
980 ]).lower($activeBackend)
981 end
982
983 def truncateFloatingPointToQuad(kind)
984 src = operands[0]
985 dst = operands[1]
986 slow = LocalLabel.unique("slow")
987 done = LocalLabel.unique("done")
988 gprScratch = X64_SCRATCH_REGISTER
989 fprScratch = FPRegisterID.forName(codeOrigin, "wfa7")
990 int64SignBit = Immediate.new(codeOrigin, 0x8000000000000000)
991 case kind
992 when :float
993 int64Min = Immediate.new(codeOrigin, 0xdf000000)
994 negInt64Min = Immediate.new(codeOrigin, 0x5f000000)
995 integerSuffix = "i"
996 floatingSuffix = "f"
997 when :double
998 int64Min = Immediate.new(codeOrigin, 0xc3e0000000000000)
999 negInt64Min = Immediate.new(codeOrigin, 0x43e0000000000000)
1000 integerSuffix = "q"
1001 floatingSuffix = "d"
1002 else
1003 raise
1004 end
1005
1006 Sequence.new(codeOrigin, [
1007 Instruction.new(codeOrigin, "move", [negInt64Min, gprScratch]),
1008 Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]),
1009 Instruction.new(codeOrigin, "b#{floatingSuffix}gteq", [src, fprScratch, LocalLabelReference.new(codeOrigin, slow)]),
1010 Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [src, dst]),
1011 Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]),
1012
1013 slow,
1014 Instruction.new(codeOrigin, "move", [int64Min, gprScratch]),
1015 Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]),
1016 Instruction.new(codeOrigin, "add#{floatingSuffix}", [src, fprScratch]),
1017 Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [fprScratch, dst]),
1018 Instruction.new(codeOrigin, "move", [int64SignBit, gprScratch]),
1019 Instruction.new(codeOrigin, "orq", [gprScratch, dst]),
1020
1021 done,
1022 ]).lower($activeBackend)
1023 end
1024
1025 def convertQuadToFloatingPoint(kind)
1026 src = operands[0]
1027 scratch1 = operands[1]
1028 dst = operands[2]
1029 slow = LocalLabel.unique("slow")
1030 done = LocalLabel.unique("done")
1031 scratch2 = X64_SCRATCH_REGISTER
1032 one = Immediate.new(codeOrigin, 0x1)
1033
1034 case kind
1035 when :float
1036 floatingSuffix = "f"
1037 when :double
1038 floatingSuffix = "d"
1039 else
1040 raise
1041 end
1042
1043 Sequence.new(codeOrigin, [
1044 Instruction.new(codeOrigin, "btqs", [src, LocalLabelReference.new(codeOrigin, slow)]),
1045 Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [src, dst]),
1046 Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]),
1047
1048 slow,
1049 Instruction.new(codeOrigin, "move", [src, scratch1]),
1050 Instruction.new(codeOrigin, "move", [src, scratch2]),
1051 Instruction.new(codeOrigin, "urshiftq", [one, scratch1]),
1052 Instruction.new(codeOrigin, "andq", [one, scratch2]),
1053 Instruction.new(codeOrigin, "orq", [scratch1, scratch2]),
1054 Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [scratch2, dst]),
1055 Instruction.new(codeOrigin, "add#{floatingSuffix}", [dst, dst]),
1056
1057 done,
1058 ]).lower($activeBackend)
1059 end
1060
1061 def lowerX86
1062 raise unless $activeBackend == "X86"
1063 lowerX86Common
1064 end
1065
1066 def lowerX86_WIN
1067 raise unless $activeBackend == "X86_WIN"
1068 lowerX86Common
1069 end
1070
1071 def lowerX86_64
1072 raise unless $activeBackend == "X86_64"
1073 lowerX86Common
1074 end
1075
1076 def lowerX86_64_WIN
1077 raise unless $activeBackend == "X86_64_WIN"
1078 lowerX86Common
1079 end
1080
1081 def lowerX86Common
1082 case opcode
1083 when "addi"
1084 handleX86Add(:int)
1085 when "addp"
1086 handleX86Add(:ptr)
1087 when "addq"
1088 handleX86Add(:quad)
1089 when "andi"
1090 handleX86Op("and#{x86Suffix(:int)}", :int)
1091 when "andp"
1092 handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
1093 when "andq"
1094 handleX86Op("and#{x86Suffix(:quad)}", :quad)
1095 when "andf"
1096 handleX86Op("andps", :float)
1097 when "andd"
1098 handleX86Op("andpd", :double)
1099 when "lshifti"
1100 handleX86Shift("sal#{x86Suffix(:int)}", :int)
1101 when "lshiftp"
1102 handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
1103 when "lshiftq"
1104 handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
1105 when "muli"
1106 handleX86Mul(:int)
1107 when "mulp"
1108 handleX86Mul(:ptr)
1109 when "mulq"
1110 handleX86Mul(:quad)
1111 when "negi"
1112 $asm.puts "neg#{x86Suffix(:int)} #{x86Operands(:int)}"
1113 when "negp"
1114 $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
1115 when "negq"
1116 $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
1117 when "noti"
1118 $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
1119 when "notq"
1120 $asm.puts "not#{x86Suffix(:quad)} #{x86Operands(:quad)}"
1121 when "ori"
1122 handleX86Op("or#{x86Suffix(:int)}", :int)
1123 when "orp"
1124 handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
1125 when "orq"
1126 handleX86Op("or#{x86Suffix(:quad)}", :quad)
1127 when "orf"
1128 handleX86Op("orps", :float)
1129 when "ord"
1130 handleX86Op("orpd", :double)
1131 when "orh"
1132 handleX86Op("or#{x86Suffix(:half)}", :half)
1133 when "rshifti"
1134 handleX86Shift("sar#{x86Suffix(:int)}", :int)
1135 when "rshiftp"
1136 handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
1137 when "rshiftq"
1138 handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
1139 when "urshifti"
1140 handleX86Shift("shr#{x86Suffix(:int)}", :int)
1141 when "urshiftp"
1142 handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
1143 when "urshiftq"
1144 handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
1145 when "rrotatei"
1146 handleX86Shift("ror#{x86Suffix(:int)}", :int)
1147 when "rrotateq"
1148 handleX86Shift("ror#{x86Suffix(:quad)}", :quad)
1149 when "lrotatei"
1150 handleX86Shift("rol#{x86Suffix(:int)}", :int)
1151 when "lrotateq"
1152 handleX86Shift("rol#{x86Suffix(:quad)}", :quad)
1153 when "subi"
1154 handleX86Sub(:int)
1155 when "subp"
1156 handleX86Sub(:ptr)
1157 when "subq"
1158 handleX86Sub(:quad)
1159 when "xori"
1160 handleX86Op("xor#{x86Suffix(:int)}", :int)
1161 when "xorp"
1162 handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
1163 when "xorq"
1164 handleX86Op("xor#{x86Suffix(:quad)}", :quad)
1165 when "leap"
1166 emitX86Lea(operands[0], operands[1], :ptr)
1167 when "loadi", "atomicloadi"
1168 $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
1169 when "storei"
1170 $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
1171 when "loadis"
1172 if isX64
1173 if !isIntelSyntax
1174 $asm.puts "movslq #{x86LoadOperands(:int, :quad)}"
1175 else
1176 $asm.puts "movsxd #{x86LoadOperands(:int, :quad)}"
1177 end
1178 else
1179 $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
1180 end
1181 when "loadp"
1182 $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}"
1183 when "storep"
1184 $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
1185 when "loadq", "atomicloadq"
1186 $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}"
1187 when "storeq"
1188 $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
1189 when "loadb", "atomicloadb"
1190 if !isIntelSyntax
1191 $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}"
1192 else
1193 $asm.puts "movzx #{x86LoadOperands(:byte, :int)}"
1194 end
1195 when "loadbsi"
1196 if !isIntelSyntax
1197 $asm.puts "movsbl #{x86LoadOperands(:byte, :int)}"
1198 else
1199 $asm.puts "movsx #{x86LoadOperands(:byte, :int)}"
1200 end
1201 when "loadbsq"
1202 if !isIntelSyntax
1203 $asm.puts "movsbq #{x86LoadOperands(:byte, :quad)}"
1204 else
1205 $asm.puts "movsx #{x86LoadOperands(:byte, :quad)}"
1206 end
1207 when "loadh", "atomicloadh"
1208 if !isIntelSyntax
1209 $asm.puts "movzwl #{x86LoadOperands(:half, :int)}"
1210 else
1211 $asm.puts "movzx #{x86LoadOperands(:half, :int)}"
1212 end
1213 when "loadhsi"
1214 if !isIntelSyntax
1215 $asm.puts "movswl #{x86LoadOperands(:half, :int)}"
1216 else
1217 $asm.puts "movsx #{x86LoadOperands(:half, :int)}"
1218 end
1219 when "loadhsq"
1220 if !isIntelSyntax
1221 $asm.puts "movswq #{x86LoadOperands(:half, :quad)}"
1222 else
1223 $asm.puts "movsx #{x86LoadOperands(:half, :quad)}"
1224 end
1225 when "storeb"
1226 $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
1227 when "storeh"
1228 $asm.puts "mov#{x86Suffix(:half)} #{x86Operands(:half, :half)}"
1229 when "loadf"
1230 $asm.puts "movss #{x86Operands(:float, :float)}"
1231 when "loadd"
1232 $asm.puts "movsd #{x86Operands(:double, :double)}"
1233 when "moved"
1234 $asm.puts "movsd #{x86Operands(:double, :double)}"
1235 when "storef"
1236 $asm.puts "movss #{x86Operands(:float, :float)}"
1237 when "stored"
1238 $asm.puts "movsd #{x86Operands(:double, :double)}"
1239 when "addf"
1240 handleX86AddFP(:float)
1241 when "addd"
1242 handleX86AddFP(:double)
1243 when "mulf"
1244 handleX86MulFP(:float)
1245 when "muld"
1246 handleX86MulFP(:double)
1247 when "subf"
1248 handleX86SubFP(:float)
1249 when "subd"
1250 handleX86SubFP(:double)
1251 when "divf"
1252 handleX86DivFP(:float)
1253 when "divd"
1254 handleX86DivFP(:double)
1255 when "sqrtf"
1256 $asm.puts "sqrtss #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:float)}"
1257 when "sqrtd"
1258 $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1259 when "roundf"
1260 $asm.puts "roundss $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1261 when "roundd"
1262 $asm.puts "roundsd $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1263 when "floorf"
1264 $asm.puts "roundss $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1265 when "floord"
1266 $asm.puts "roundsd $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1267 when "ceilf"
1268 $asm.puts "roundss $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1269 when "ceild"
1270 $asm.puts "roundsd $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1271 when "truncatef"
1272 $asm.puts "roundss $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1273 when "truncated"
1274 $asm.puts "roundsd $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
1275 when "truncatef2i"
1276 $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}"
1277 when "truncated2i"
1278 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1279 when "truncatef2q"
1280 truncateFloatingPointToQuad(:float)
1281 when "truncated2q"
1282 truncateFloatingPointToQuad(:double)
1283 when "truncatef2is"
1284 $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:int)}"
1285 when "truncatef2qs"
1286 $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}"
1287 when "truncated2is"
1288 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1289 when "truncated2qs"
1290 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1291 when "ci2d"
1292 $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}"
1293 when "ci2ds"
1294 $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}"
1295 when "ci2fs"
1296 $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:float))}"
1297 when "ci2f"
1298 $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}"
1299 when "cq2f"
1300 convertQuadToFloatingPoint(:float)
1301 when "cq2d"
1302 convertQuadToFloatingPoint(:double)
1303 when "cq2fs"
1304 $asm.puts "cvtsi2ssq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}"
1305 when "cq2ds"
1306 $asm.puts "cvtsi2sdq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}"
1307 when "cd2f"
1308 $asm.puts "cvtsd2ss #{x86Operands(:double, :float)}"
1309 when "cf2d"
1310 $asm.puts "cvtss2sd #{x86Operands(:float, :double)}"
1311 when "bdeq"
1312 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1313 if operands[0] == operands[1]
1314 # This is just a jump ordered, which is a jnp.
1315 $asm.puts "jnp #{operands[2].asmLabel}"
1316 else
1317 isUnordered = LocalLabel.unique("bdeq")
1318 $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
1319 $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}"
1320 isUnordered.lower($activeBackend)
1321 end
1322 when "bdneq"
1323 handleX86FPBranch(:double, "jne", :normal)
1324 when "bdgt"
1325 handleX86FPBranch(:double, "ja", :normal)
1326 when "bdgteq"
1327 handleX86FPBranch(:double, "jae", :normal)
1328 when "bdlt"
1329 handleX86FPBranch(:double, "ja", :reverse)
1330 when "bdlteq"
1331 handleX86FPBranch(:double, "jae", :reverse)
1332 when "bdequn"
1333 handleX86FPBranch(:double, "je", :normal)
1334 when "bdnequn"
1335 $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1336 if operands[0] == operands[1]
1337 # This is just a jump unordered, which is a jp.
1338 $asm.puts "jp #{operands[2].asmLabel}"
1339 else
1340 isUnordered = LocalLabel.unique("bdnequn")
1341 isEqual = LocalLabel.unique("bdnequn")
1342 $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
1343 $asm.puts "je #{LocalLabelReference.new(codeOrigin, isEqual).asmLabel}"
1344 isUnordered.lower($activeBackend)
1345 $asm.puts "jmp #{operands[2].asmLabel}"
1346 isEqual.lower($activeBackend)
1347 end
1348 when "bdgtun"
1349 handleX86FPBranch(:double, "jb", :reverse)
1350 when "bdgtequn"
1351 handleX86FPBranch(:double, "jbe", :reverse)
1352 when "bdltun"
1353 handleX86FPBranch(:double, "jb", :normal)
1354 when "bdltequn"
1355 handleX86FPBranch(:double, "jbe", :normal)
1356 when "bfeq"
1357 $asm.puts "ucomiss #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}"
1358 if operands[0] == operands[1]
1359 # This is just a jump ordered, which is a jnp.
1360 $asm.puts "jnp #{operands[2].asmLabel}"
1361 else
1362 isUnordered = LocalLabel.unique("bfeq")
1363 $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
1364 $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}"
1365 isUnordered.lower($activeBackend)
1366 end
1367 when "bfgt"
1368 handleX86FPBranch(:float, "ja", :normal)
1369 when "bfgteq"
1370 handleX86FPBranch(:float, "jae", :normal)
1371 when "bflt"
1372 handleX86FPBranch(:float, "ja", :reverse)
1373 when "bfgtun"
1374 handleX86FPBranch(:float, "jb", :reverse)
1375 when "bfgtequn"
1376 handleX86FPBranch(:float, "jbe", :reverse)
1377 when "bfltun"
1378 handleX86FPBranch(:float, "jb", :normal)
1379 when "bfltequn"
1380 handleX86FPBranch(:float, "jbe", :normal)
1381 when "btd2i"
1382 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1383 $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
1384 $asm.puts "je #{operands[2].asmLabel}"
1385 when "td2i"
1386 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1387 when "bcd2i"
1388 $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1389 $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
1390 $asm.puts "je #{operands[2].asmLabel}"
1391 $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
1392 $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
1393 $asm.puts "jp #{operands[2].asmLabel}"
1394 $asm.puts "jne #{operands[2].asmLabel}"
1395 when "movdz"
1396 $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
1397 when "pop"
1398 operands.each {
1399 | op |
1400 $asm.puts "pop #{op.x86Operand(:ptr)}"
1401 }
1402 when "push"
1403 operands.each {
1404 | op |
1405 $asm.puts "push #{op.x86Operand(:ptr)}"
1406 }
1407 when "move"
1408 handleMove
1409 when "sxi2q"
1410 if !isIntelSyntax
1411 $asm.puts "movslq #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:quad)}"
1412 else
1413 $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:quad))}"
1414 end
1415 when "zxi2q"
1416 $asm.puts "mov#{x86Suffix(:int)} #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:int))}"
1417 when "sxb2i"
1418 if !isIntelSyntax
1419 $asm.puts "movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
1420 else
1421 $asm.puts "movsx #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:int))}"
1422 end
1423 when "sxh2i"
1424 if !isIntelSyntax
1425 $asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
1426 else
1427 $asm.puts "movsx #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:int))}"
1428 end
1429 when "sxb2q"
1430 if !isIntelSyntax
1431 $asm.puts "movsbq #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:quad)}"
1432 else
1433 $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(:quad))}"
1434 end
1435 when "sxh2q"
1436 if !isIntelSyntax
1437 $asm.puts "movswq #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:quad)}"
1438 else
1439 $asm.puts "movsxd #{orderOperands(operands[0].x86Operand(:half), operands[1].x86Operand(:quad))}"
1440 end
1441 when "nop"
1442 $asm.puts "nop"
1443 when "bieq"
1444 handleX86IntBranch("je", :int)
1445 when "bpeq"
1446 handleX86IntBranch("je", :ptr)
1447 when "bqeq"
1448 handleX86IntBranch("je", :quad)
1449 when "bineq"
1450 handleX86IntBranch("jne", :int)
1451 when "bpneq"
1452 handleX86IntBranch("jne", :ptr)
1453 when "bqneq"
1454 handleX86IntBranch("jne", :quad)
1455 when "bia"
1456 handleX86IntBranch("ja", :int)
1457 when "bpa"
1458 handleX86IntBranch("ja", :ptr)
1459 when "bqa"
1460 handleX86IntBranch("ja", :quad)
1461 when "biaeq"
1462 handleX86IntBranch("jae", :int)
1463 when "bpaeq"
1464 handleX86IntBranch("jae", :ptr)
1465 when "bqaeq"
1466 handleX86IntBranch("jae", :quad)
1467 when "bib"
1468 handleX86IntBranch("jb", :int)
1469 when "bpb"
1470 handleX86IntBranch("jb", :ptr)
1471 when "bqb"
1472 handleX86IntBranch("jb", :quad)
1473 when "bibeq"
1474 handleX86IntBranch("jbe", :int)
1475 when "bpbeq"
1476 handleX86IntBranch("jbe", :ptr)
1477 when "bqbeq"
1478 handleX86IntBranch("jbe", :quad)
1479 when "bigt"
1480 handleX86IntBranch("jg", :int)
1481 when "bpgt"
1482 handleX86IntBranch("jg", :ptr)
1483 when "bqgt"
1484 handleX86IntBranch("jg", :quad)
1485 when "bigteq"
1486 handleX86IntBranch("jge", :int)
1487 when "bpgteq"
1488 handleX86IntBranch("jge", :ptr)
1489 when "bqgteq"
1490 handleX86IntBranch("jge", :quad)
1491 when "bilt"
1492 handleX86IntBranch("jl", :int)
1493 when "bplt"
1494 handleX86IntBranch("jl", :ptr)
1495 when "bqlt"
1496 handleX86IntBranch("jl", :quad)
1497 when "bilteq"
1498 handleX86IntBranch("jle", :int)
1499 when "bplteq"
1500 handleX86IntBranch("jle", :ptr)
1501 when "bqlteq"
1502 handleX86IntBranch("jle", :quad)
1503 when "bbeq"
1504 handleX86IntBranch("je", :byte)
1505 when "bbneq"
1506 handleX86IntBranch("jne", :byte)
1507 when "bba"
1508 handleX86IntBranch("ja", :byte)
1509 when "bbaeq"
1510 handleX86IntBranch("jae", :byte)
1511 when "bbb"
1512 handleX86IntBranch("jb", :byte)
1513 when "bbbeq"
1514 handleX86IntBranch("jbe", :byte)
1515 when "bbgt"
1516 handleX86IntBranch("jg", :byte)
1517 when "bbgteq"
1518 handleX86IntBranch("jge", :byte)
1519 when "bblt"
1520 handleX86IntBranch("jl", :byte)
1521 when "bblteq"
1522 handleX86IntBranch("jlteq", :byte)
1523 when "btis"
1524 handleX86BranchTest("js", :int)
1525 when "btps"
1526 handleX86BranchTest("js", :ptr)
1527 when "btqs"
1528 handleX86BranchTest("js", :quad)
1529 when "btiz"
1530 handleX86BranchTest("jz", :int)
1531 when "btpz"
1532 handleX86BranchTest("jz", :ptr)
1533 when "btqz"
1534 handleX86BranchTest("jz", :quad)
1535 when "btinz"
1536 handleX86BranchTest("jnz", :int)
1537 when "btpnz"
1538 handleX86BranchTest("jnz", :ptr)
1539 when "btqnz"
1540 handleX86BranchTest("jnz", :quad)
1541 when "btbs"
1542 handleX86BranchTest("js", :byte)
1543 when "btbz"
1544 handleX86BranchTest("jz", :byte)
1545 when "btbnz"
1546 handleX86BranchTest("jnz", :byte)
1547 when "jmp"
1548 $asm.puts "jmp #{operands[0].x86CallOperand(:ptr)}"
1549 when "baddio"
1550 handleX86OpBranch("add#{x86Suffix(:int)}", "jo", :int)
1551 when "baddpo"
1552 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jo", :ptr)
1553 when "baddqo"
1554 handleX86OpBranch("add#{x86Suffix(:quad)}", "jo", :quad)
1555 when "baddis"
1556 handleX86OpBranch("add#{x86Suffix(:int)}", "js", :int)
1557 when "baddps"
1558 handleX86OpBranch("add#{x86Suffix(:ptr)}", "js", :ptr)
1559 when "baddqs"
1560 handleX86OpBranch("add#{x86Suffix(:quad)}", "js", :quad)
1561 when "baddiz"
1562 handleX86OpBranch("add#{x86Suffix(:int)}", "jz", :int)
1563 when "baddpz"
1564 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jz", :ptr)
1565 when "baddqz"
1566 handleX86OpBranch("add#{x86Suffix(:quad)}", "jz", :quad)
1567 when "baddinz"
1568 handleX86OpBranch("add#{x86Suffix(:int)}", "jnz", :int)
1569 when "baddpnz"
1570 handleX86OpBranch("add#{x86Suffix(:ptr)}", "jnz", :ptr)
1571 when "baddqnz"
1572 handleX86OpBranch("add#{x86Suffix(:quad)}", "jnz", :quad)
1573 when "bsubio"
1574 handleX86SubBranch("jo", :int)
1575 when "bsubis"
1576 handleX86SubBranch("js", :int)
1577 when "bsubiz"
1578 handleX86SubBranch("jz", :int)
1579 when "bsubinz"
1580 handleX86SubBranch("jnz", :int)
1581 when "bmulio"
1582 handleX86OpBranch("imul#{x86Suffix(:int)}", "jo", :int)
1583 when "bmulis"
1584 handleX86OpBranch("imul#{x86Suffix(:int)}", "js", :int)
1585 when "bmuliz"
1586 handleX86OpBranch("imul#{x86Suffix(:int)}", "jz", :int)
1587 when "bmulinz"
1588 handleX86OpBranch("imul#{x86Suffix(:int)}", "jnz", :int)
1589 when "borio"
1590 handleX86OpBranch("orl", "jo", :int)
1591 when "boris"
1592 handleX86OpBranch("orl", "js", :int)
1593 when "boriz"
1594 handleX86OpBranch("orl", "jz", :int)
1595 when "borinz"
1596 handleX86OpBranch("orl", "jnz", :int)
1597 when "break"
1598 $asm.puts "int #{const(3)}"
1599 when "call"
1600 op = operands[0].x86CallOperand(:ptr)
1601 if operands[0].is_a? LabelReference
1602 operands[0].used
1603 end
1604 $asm.puts "call #{op}"
1605 when "ret"
1606 $asm.puts "ret"
1607 when "cieq"
1608 handleX86IntCompareSet("sete", :int)
1609 when "cbeq"
1610 handleX86IntCompareSet("sete", :byte)
1611 when "cpeq"
1612 handleX86IntCompareSet("sete", :ptr)
1613 when "cqeq"
1614 handleX86IntCompareSet("sete", :quad)
1615 when "cineq"
1616 handleX86IntCompareSet("setne", :int)
1617 when "cbneq"
1618 handleX86IntCompareSet("setne", :byte)
1619 when "cpneq"
1620 handleX86IntCompareSet("setne", :ptr)
1621 when "cqneq"
1622 handleX86IntCompareSet("setne", :quad)
1623 when "cia"
1624 handleX86IntCompareSet("seta", :int)
1625 when "cba"
1626 handleX86IntCompareSet("seta", :byte)
1627 when "cpa"
1628 handleX86IntCompareSet("seta", :ptr)
1629 when "cqa"
1630 handleX86IntCompareSet("seta", :quad)
1631 when "ciaeq"
1632 handleX86IntCompareSet("setae", :int)
1633 when "cbaeq"
1634 handleX86IntCompareSet("setae", :byte)
1635 when "cpaeq"
1636 handleX86IntCompareSet("setae", :ptr)
1637 when "cqaeq"
1638 handleX86IntCompareSet("setae", :quad)
1639 when "cib"
1640 handleX86IntCompareSet("setb", :int)
1641 when "cbb"
1642 handleX86IntCompareSet("setb", :byte)
1643 when "cpb"
1644 handleX86IntCompareSet("setb", :ptr)
1645 when "cqb"
1646 handleX86IntCompareSet("setb", :quad)
1647 when "cibeq"
1648 handleX86IntCompareSet("setbe", :int)
1649 when "cbbeq"
1650 handleX86IntCompareSet("setbe", :byte)
1651 when "cpbeq"
1652 handleX86IntCompareSet("setbe", :ptr)
1653 when "cqbeq"
1654 handleX86IntCompareSet("setbe", :quad)
1655 when "cigt"
1656 handleX86IntCompareSet("setg", :int)
1657 when "cbgt"
1658 handleX86IntCompareSet("setg", :byte)
1659 when "cpgt"
1660 handleX86IntCompareSet("setg", :ptr)
1661 when "cqgt"
1662 handleX86IntCompareSet("setg", :quad)
1663 when "cigteq"
1664 handleX86IntCompareSet("setge", :int)
1665 when "cbgteq"
1666 handleX86IntCompareSet("setge", :byte)
1667 when "cpgteq"
1668 handleX86IntCompareSet("setge", :ptr)
1669 when "cqgteq"
1670 handleX86IntCompareSet("setge", :quad)
1671 when "cilt"
1672 handleX86IntCompareSet("setl", :int)
1673 when "cblt"
1674 handleX86IntCompareSet("setl", :byte)
1675 when "cplt"
1676 handleX86IntCompareSet("setl", :ptr)
1677 when "cqlt"
1678 handleX86IntCompareSet("setl", :quad)
1679 when "cilteq"
1680 handleX86IntCompareSet("setle", :int)
1681 when "cblteq"
1682 handleX86IntCompareSet("setle", :byte)
1683 when "cplteq"
1684 handleX86IntCompareSet("setle", :ptr)
1685 when "cqlteq"
1686 handleX86IntCompareSet("setle", :quad)
1687 when "cfeq"
1688 handleX86FPCompareSet(:float, :eq)
1689 when "cdeq"
1690 handleX86FPCompareSet(:double, :eq)
1691 when "cfneq"
1692 handleX86FPCompareSet(:float, "setne")
1693 when "cdneq"
1694 handleX86FPCompareSet(:double, "setne")
1695 when "cfnequn"
1696 handleX86FPCompareSet(:float, :nequn)
1697 when "cdnequn"
1698 handleX86FPCompareSet(:double, :nequn)
1699 when "cfgt"
1700 handleX86FPCompareSet(:float, "seta")
1701 when "cdgt"
1702 handleX86FPCompareSet(:double, "seta")
1703 when "cfgteq"
1704 handleX86FPCompareSet(:float, "setae")
1705 when "cdgteq"
1706 handleX86FPCompareSet(:double, "setae")
1707 when "cflt"
1708 handleX86FPCompareSet(:float, "seta", :reverse)
1709 when "cdlt"
1710 handleX86FPCompareSet(:double, "seta", :reverse)
1711 when "cflteq"
1712 handleX86FPCompareSet(:float, "setae", :reverse)
1713 when "cdlteq"
1714 handleX86FPCompareSet(:double, "setae", :reverse)
1715 when "tis"
1716 handleX86SetTest("sets", :int)
1717 when "tiz"
1718 handleX86SetTest("setz", :int)
1719 when "tinz"
1720 handleX86SetTest("setnz", :int)
1721 when "tps"
1722 handleX86SetTest("sets", :ptr)
1723 when "tpz"
1724 handleX86SetTest("setz", :ptr)
1725 when "tpnz"
1726 handleX86SetTest("setnz", :ptr)
1727 when "tqs"
1728 handleX86SetTest("sets", :quad)
1729 when "tqz"
1730 handleX86SetTest("setz", :quad)
1731 when "tqnz"
1732 handleX86SetTest("setnz", :quad)
1733 when "tbs"
1734 handleX86SetTest("sets", :byte)
1735 when "tbz"
1736 handleX86SetTest("setz", :byte)
1737 when "tbnz"
1738 handleX86SetTest("setnz", :byte)
1739 when "peek"
1740 handleX86Peek()
1741 when "poke"
1742 handleX86Poke()
1743 when "cdqi"
1744 $asm.puts "cdq"
1745 when "cqoq"
1746 $asm.puts "cqo"
1747 when "idivi"
1748 $asm.puts "idiv#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1749 when "udivi"
1750 $asm.puts "div#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1751 when "idivq"
1752 $asm.puts "idiv#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}"
1753 when "udivq"
1754 $asm.puts "div#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}"
1755 when "popcnti"
1756 $asm.puts "popcnt#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
1757 when "popcntq"
1758 $asm.puts "popcnt#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
1759 when "tzcnti"
1760 countTrailingZeros(:int)
1761 when "tzcntq"
1762 countTrailingZeros(:quad)
1763 when "lzcnti"
1764 countLeadingZeros(:int)
1765 when "lzcntq"
1766 countLeadingZeros(:quad)
1767 when "fii2d"
1768 $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
1769 $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
1770 $asm.puts "psllq $32, %xmm7"
1771 $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
1772 when "fd2ii"
1773 $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
1774 $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
1775 $asm.puts "psrlq $32, %xmm7"
1776 $asm.puts "movd %xmm7, #{operands[2].x86Operand(:int)}"
1777 when "fq2d"
1778 if !isIntelSyntax
1779 $asm.puts "movq #{operands[0].x86Operand(:quad)}, #{operands[1].x86Operand(:double)}"
1780 else
1781 # MASM does not accept register operands with movq.
1782 # Debugging shows that movd actually moves a qword when using MASM.
1783 $asm.puts "movd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:quad)}"
1784 end
1785 when "fd2q"
1786 if !isIntelSyntax
1787 $asm.puts "movq #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
1788 else
1789 # MASM does not accept register operands with movq.
1790 # Debugging shows that movd actually moves a qword when using MASM.
1791 $asm.puts "movd #{operands[1].x86Operand(:quad)}, #{operands[0].x86Operand(:double)}"
1792 end
1793 when "fi2f"
1794 $asm.puts "movd #{x86Operands(:int, :float)}"
1795 when "ff2i"
1796 $asm.puts "movd #{x86Operands(:float, :int)}"
1797 when "bo"
1798 $asm.puts "jo #{operands[0].asmLabel}"
1799 when "bs"
1800 $asm.puts "js #{operands[0].asmLabel}"
1801 when "bz"
1802 $asm.puts "jz #{operands[0].asmLabel}"
1803 when "bnz"
1804 $asm.puts "jnz #{operands[0].asmLabel}"
1805 when "leai"
1806 $asm.puts "lea#{x86Suffix(:int)} #{orderOperands(operands[0].x86AddressOperand(:int), operands[1].x86Operand(:int))}"
1807 when "leap"
1808 $asm.puts "lea#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86AddressOperand(:ptr), operands[1].x86Operand(:ptr))}"
1809 when "memfence", "fence"
1810 sp = RegisterID.new(nil, "sp")
1811 if isIntelSyntax
1812 $asm.puts "mfence"
1813 else
1814 $asm.puts "lock; orl $0, (#{sp.x86Operand(:ptr)})"
1815 end
1816 when "absf"
1817 $asm.puts "movl #{orderOperands("$0x80000000", X64_SCRATCH_REGISTER.x86Operand(:int))}"
1818 $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:int), operands[1].x86Operand(:float))}"
1819 $asm.puts "andnps #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}"
1820 when "absd"
1821 $asm.puts "movq #{orderOperands("$0x8000000000000000", X64_SCRATCH_REGISTER.x86Operand(:quad))}"
1822 $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:quad), operands[1].x86Operand(:double))}"
1823 $asm.puts "andnps #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1824 when "negf"
1825 $asm.puts "movl #{orderOperands("$0x80000000", X64_SCRATCH_REGISTER.x86Operand(:int))}"
1826 $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:int), operands[1].x86Operand(:float))}"
1827 $asm.puts "xorps #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}"
1828 when "negd"
1829 $asm.puts "movq #{orderOperands("$0x8000000000000000", X64_SCRATCH_REGISTER.x86Operand(:quad))}"
1830 $asm.puts "movd #{orderOperands(X64_SCRATCH_REGISTER.x86Operand(:quad), operands[1].x86Operand(:double))}"
1831 $asm.puts "xorpd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
1832 when "tls_loadp"
1833 raise "tls_loadp is only supported on x64" unless isX64
1834 if operands[0].immediate?
1835 mem = "%gs:#{operands[0].value * 8}"
1836 else
1837 mem = BaseIndex.new(codeOrigin, nil, operands[0], 8, "%gs:").x86AddressOperand(:quad)
1838 end
1839 $asm.puts "movq #{orderOperands(mem, operands[1].x86Operand(:quad))}"
1840 when "tls_loadp"
1841 raise "tls_loadp is only supported on x64" unless isX64
1842 if operands[0].immediate?
1843 mem = "%gs:#{operands[0].value * x86Bytes(:ptr)}"
1844 else
1845 mem = BaseIndex.new(codeOrigin, nil, operands[0], x86Bytes(:ptr), "%gs:").x86AddressOperand(:quad)
1846 end
1847 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(mem, operands[1].x86Operand(:quad))}"
1848 when "tls_storep"
1849 raise "tls_loadp is only supported on x64" unless isX64
1850 if operands[1].immediate?
1851 mem = "%gs:#{operands[1].value * x86Bytes(:ptr)}"
1852 else
1853 mem = BaseIndex.new(codeOrigin, nil, operands[1], x86Bytes(:ptr), "%gs:").x86AddressOperand(:ptr)
1854 end
1855 $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(operands[0].x86Operand(:ptr), mem)}"
1856 when "atomicxchgaddb"
1857 $asm.puts "lock"
1858 $asm.puts "xadd#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
1859 when "atomicxchgaddh"
1860 $asm.puts "lock"
1861 $asm.puts "xadd#{x86Suffix(:half)} #{x86Operands(:half, :half)}"
1862 when "atomicxchgaddi"
1863 $asm.puts "lock"
1864 $asm.puts "xadd#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
1865 when "atomicxchgaddq"
1866 $asm.puts "lock"
1867 $asm.puts "xadd#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
1868 when "atomicxchgsubb"
1869 $asm.puts "neg#{x86Suffix(:byte)} #{operands[0].x86Operand(:byte)}"
1870 $asm.puts "lock"
1871 $asm.puts "xadd#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
1872 when "atomicxchgsubh"
1873 $asm.puts "neg#{x86Suffix(:half)} #{operands[0].x86Operand(:half)}"
1874 $asm.puts "lock"
1875 $asm.puts "xadd#{x86Suffix(:half)} #{x86Operands(:half, :half)}"
1876 when "atomicxchgsubi"
1877 $asm.puts "neg#{x86Suffix(:int)} #{operands[0].x86Operand(:int)}"
1878 $asm.puts "lock"
1879 $asm.puts "xadd#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
1880 when "atomicxchgsubq"
1881 $asm.puts "neg#{x86Suffix(:quad)} #{operands[0].x86Operand(:quad)}"
1882 $asm.puts "lock"
1883 $asm.puts "xadd#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
1884 when "atomicxchgb"
1885 $asm.puts "xchg#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
1886 when "atomicxchgh"
1887 $asm.puts "xchg#{x86Suffix(:half)} #{x86Operands(:half, :half)}"
1888 when "atomicxchgi"
1889 $asm.puts "xchg#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
1890 when "atomicxchgq"
1891 $asm.puts "xchg#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
1892 when "batomicweakcasb"
1893 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1894 $asm.puts "lock"
1895 $asm.puts "cmpxchg#{x86Suffix(:byte)} #{orderOperands(operands[1].x86Operand(:byte), operands[2].x86Operand(:byte))}"
1896 $asm.puts "jne #{operands.last.asmLabel}"
1897 when "batomicweakcash"
1898 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1899 $asm.puts "lock"
1900 $asm.puts "cmpxchg#{x86Suffix(:half)} #{orderOperands(operands[1].x86Operand(:half), operands[2].x86Operand(:half))}"
1901 $asm.puts "jne #{operands.last.asmLabel}"
1902 when "batomicweakcasi"
1903 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1904 $asm.puts "lock"
1905 $asm.puts "cmpxchg#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), operands[2].x86Operand(:int))}"
1906 $asm.puts "jne #{operands.last.asmLabel}"
1907 when "batomicweakcasq"
1908 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1909 $asm.puts "lock"
1910 $asm.puts "cmpxchg#{x86Suffix(:quad)} #{orderOperands(operands[1].x86Operand(:quad), operands[2].x86Operand(:quad))}"
1911 $asm.puts "jne #{operands.last.asmLabel}"
1912 when "atomicweakcasb"
1913 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1914 $asm.puts "lock"
1915 $asm.puts "cmpxchg#{x86Suffix(:byte)} #{orderOperands(operands[1].x86Operand(:byte), operands[2].x86Operand(:byte))}"
1916 when "atomicweakcash"
1917 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1918 $asm.puts "lock"
1919 $asm.puts "cmpxchg#{x86Suffix(:half)} #{orderOperands(operands[1].x86Operand(:half), operands[2].x86Operand(:half))}"
1920 when "atomicweakcasi"
1921 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1922 $asm.puts "lock"
1923 $asm.puts "cmpxchg#{x86Suffix(:int)} #{orderOperands(operands[1].x86Operand(:int), operands[2].x86Operand(:int))}"
1924 when "atomicweakcasq"
1925 raise "first operand must be t0" unless operands[0].is_a? RegisterID and operands[0].name == 't0'
1926 $asm.puts "lock"
1927 $asm.puts "cmpxchg#{x86Suffix(:quad)} #{orderOperands(operands[1].x86Operand(:quad), operands[2].x86Operand(:quad))}"
1928 else
1929 lowerDefault
1930 end
1931 end
1932end
1933
Note: See TracBrowser for help on using the repository browser.