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 |
|
---|
25 | require "config"
|
---|
26 |
|
---|
27 | # GPR conventions, to match the baseline JIT:
|
---|
28 | #
|
---|
29 | #
|
---|
30 | # On x86-32 bits (windows and non-windows)
|
---|
31 | # a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not
|
---|
32 | # actually considered as such by the ABI and we need to push/pop our arguments
|
---|
33 | # on the stack. a0 and a1 are ecx and edx to follow fastcall.
|
---|
34 | #
|
---|
35 | # eax => t0, a2, r0
|
---|
36 | # edx => t1, a1, r1
|
---|
37 | # ecx => t2, a0
|
---|
38 | # ebx => t3, a3 (callee-save)
|
---|
39 | # esi => t4 (callee-save)
|
---|
40 | # edi => t5 (callee-save)
|
---|
41 | # ebp => cfr
|
---|
42 | # esp => sp
|
---|
43 | #
|
---|
44 | # On x86-64 non-windows
|
---|
45 | #
|
---|
46 | # rax => t0, r0
|
---|
47 | # rdi => a0
|
---|
48 | # rsi => t1, a1
|
---|
49 | # rdx => t2, a2, r1
|
---|
50 | # rcx => t3, a3
|
---|
51 | # r8 => t4
|
---|
52 | # 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 |
|
---|
84 | def 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
|
---|
97 | end
|
---|
98 |
|
---|
99 | def 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
|
---|
112 | end
|
---|
113 |
|
---|
114 | def isMSVC
|
---|
115 | $options.has_key?(:assembler) && $options[:assembler] == "MASM"
|
---|
116 | end
|
---|
117 |
|
---|
118 | def isIntelSyntax
|
---|
119 | $options.has_key?(:assembler) && $options[:assembler] == "MASM"
|
---|
120 | end
|
---|
121 |
|
---|
122 | def register(name)
|
---|
123 | isIntelSyntax ? name : "%" + name
|
---|
124 | end
|
---|
125 |
|
---|
126 | def offsetRegister(off, register)
|
---|
127 | isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})"
|
---|
128 | end
|
---|
129 |
|
---|
130 | def callPrefix
|
---|
131 | isIntelSyntax ? "" : "*"
|
---|
132 | end
|
---|
133 |
|
---|
134 | def orderOperands(*operands)
|
---|
135 | (isIntelSyntax ? operands.reverse : operands).join(", ")
|
---|
136 | end
|
---|
137 |
|
---|
138 | def const(c)
|
---|
139 | isIntelSyntax ? "#{c}" : "$#{c}"
|
---|
140 | end
|
---|
141 |
|
---|
142 | def 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" + " ";
|
---|
168 | end
|
---|
169 |
|
---|
170 | class 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
|
---|
191 | end
|
---|
192 |
|
---|
193 | X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
|
---|
194 |
|
---|
195 | def 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
|
---|
236 | end
|
---|
237 |
|
---|
238 | class Node
|
---|
239 | def x86LoadOperand(type, dst)
|
---|
240 | x86Operand(type)
|
---|
241 | end
|
---|
242 | end
|
---|
243 |
|
---|
244 | class 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
|
---|
330 | end
|
---|
331 |
|
---|
332 | class 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
|
---|
359 | end
|
---|
360 |
|
---|
361 | class 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
|
---|
375 | end
|
---|
376 |
|
---|
377 | class 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
|
---|
391 | end
|
---|
392 |
|
---|
393 | class 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
|
---|
417 | end
|
---|
418 |
|
---|
419 | class 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
|
---|
435 | end
|
---|
436 |
|
---|
437 | class 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
|
---|
452 | end
|
---|
453 |
|
---|
454 | class LocalLabelReference
|
---|
455 | def x86Operand(kind)
|
---|
456 | asmLabel
|
---|
457 | end
|
---|
458 | def x86CallOperand(kind)
|
---|
459 | asmLabel
|
---|
460 | end
|
---|
461 | end
|
---|
462 |
|
---|
463 | class 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
|
---|
505 | end
|
---|
506 |
|
---|
507 | class 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
|
---|
1932 | end
|
---|
1933 |
|
---|