PageRenderTime 67ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/JavaScriptCore/offlineasm/x86.rb

http://github.com/WebKit/webkit
Ruby | 1832 lines | 1638 code | 105 blank | 89 comment | 139 complexity | af9b28b816fcf1430c8d6e558e84ea70 MD5 | raw file
Possible License(s): MPL-2.0, 0BSD, MPL-2.0-no-copyleft-exception, BSD-3-Clause, AGPL-1.0, MIT, GPL-2.0, GPL-3.0, Unlicense, BSD-2-Clause, LGPL-2.1, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. # Copyright (C) 2012-2018 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. require "config"
  25. # GPR conventions, to match the baseline JIT:
  26. #
  27. #
  28. # On x86-32 bits (windows and non-windows)
  29. # a0, a1, a2, a3 are only there for ease-of-use of offlineasm; they are not
  30. # actually considered as such by the ABI and we need to push/pop our arguments
  31. # on the stack. a0 and a1 are ecx and edx to follow fastcall.
  32. #
  33. # eax => t0, a2, r0
  34. # edx => t1, a1, r1
  35. # ecx => t2, a0
  36. # ebx => t3, a3 (callee-save)
  37. # esi => t4 (callee-save)
  38. # edi => t5 (callee-save)
  39. # ebp => cfr
  40. # esp => sp
  41. #
  42. # On x86-64 non-windows
  43. #
  44. # rax => t0, r0
  45. # rdi => a0
  46. # rsi => t1, a1
  47. # rdx => t2, a2, r1
  48. # rcx => t3, a3
  49. # r8 => t4
  50. # r9 => t5
  51. # r10 => t6
  52. # rbx => csr0 (callee-save, wasmInstance)
  53. # r12 => csr1 (callee-save, metadataTable)
  54. # r13 => csr2 (callee-save, PB)
  55. # r14 => csr3 (callee-save, tagTypeNumber)
  56. # r15 => csr4 (callee-save, tagMask)
  57. # rsp => sp
  58. # rbp => cfr
  59. # r11 => (scratch)
  60. #
  61. # On x86-64 windows
  62. # Arguments need to be push/pop'd on the stack in addition to being stored in
  63. # the registers. Also, >8 return types are returned in a weird way.
  64. #
  65. # rax => t0, r0
  66. # rcx => t5, a0
  67. # rdx => t1, a1, r1
  68. # r8 => t2, a2
  69. # r9 => t3, a3
  70. # r10 => t4
  71. # rbx => csr0 (callee-save, PB, unused in baseline)
  72. # rsi => csr1 (callee-save)
  73. # rdi => csr2 (callee-save)
  74. # r12 => csr3 (callee-save)
  75. # r13 => csr4 (callee-save)
  76. # r14 => csr5 (callee-save, numberTag)
  77. # r15 => csr6 (callee-save, notCellMask)
  78. # rsp => sp
  79. # rbp => cfr
  80. # r11 => (scratch)
  81. def isX64
  82. case $activeBackend
  83. when "X86"
  84. false
  85. when "X86_WIN"
  86. false
  87. when "X86_64"
  88. true
  89. when "X86_64_WIN"
  90. true
  91. else
  92. raise "bad value for $activeBackend: #{$activeBackend}"
  93. end
  94. end
  95. def isWin
  96. case $activeBackend
  97. when "X86"
  98. false
  99. when "X86_WIN"
  100. true
  101. when "X86_64"
  102. false
  103. when "X86_64_WIN"
  104. true
  105. else
  106. raise "bad value for $activeBackend: #{$activeBackend}"
  107. end
  108. end
  109. def isMSVC
  110. $options.has_key?(:assembler) && $options[:assembler] == "MASM"
  111. end
  112. def isIntelSyntax
  113. $options.has_key?(:assembler) && $options[:assembler] == "MASM"
  114. end
  115. def register(name)
  116. isIntelSyntax ? name : "%" + name
  117. end
  118. def offsetRegister(off, register)
  119. isIntelSyntax ? "[#{off} + #{register}]" : "#{off}(#{register})"
  120. end
  121. def callPrefix
  122. isIntelSyntax ? "" : "*"
  123. end
  124. def orderOperands(*operands)
  125. (isIntelSyntax ? operands.reverse : operands).join(", ")
  126. end
  127. def const(c)
  128. isIntelSyntax ? "#{c}" : "$#{c}"
  129. end
  130. def getSizeString(kind)
  131. if !isIntelSyntax
  132. return ""
  133. end
  134. size = ""
  135. case kind
  136. when :byte
  137. size = "byte"
  138. when :half
  139. size = "word"
  140. when :int
  141. size = "dword"
  142. when :ptr
  143. size = isX64 ? "qword" : "dword"
  144. when :float
  145. size = "dword"
  146. when :double
  147. size = "qword"
  148. when :quad
  149. size = "qword"
  150. else
  151. raise "Invalid kind #{kind}"
  152. end
  153. return size + " " + "ptr" + " ";
  154. end
  155. class SpecialRegister < NoChildren
  156. def x86Operand(kind)
  157. raise unless @name =~ /^r/
  158. raise unless isX64
  159. case kind
  160. when :half
  161. register(@name + "w")
  162. when :int
  163. register(@name + "d")
  164. when :ptr
  165. register(@name)
  166. when :quad
  167. register(@name)
  168. else
  169. raise codeOriginString
  170. end
  171. end
  172. def x86CallOperand(kind)
  173. # Call operands are not allowed to be partial registers.
  174. "#{callPrefix}#{x86Operand(:quad)}"
  175. end
  176. end
  177. X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
  178. def x86GPRName(name, kind)
  179. case name
  180. when "eax", "ebx", "ecx", "edx"
  181. name8 = name[1] + 'l'
  182. name16 = name[1..2]
  183. when "esi", "edi", "ebp", "esp"
  184. name16 = name[1..2]
  185. name8 = name16 + 'l'
  186. when "rax", "rbx", "rcx", "rdx"
  187. raise "bad GPR name #{name} in 32-bit X86" unless isX64
  188. name8 = name[1] + 'l'
  189. name16 = name[1..2]
  190. when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
  191. raise "bad GPR name #{name} in 32-bit X86" unless isX64
  192. case kind
  193. when :half
  194. return register(name + "w")
  195. when :int
  196. return register(name + "d")
  197. when :ptr
  198. return register(name)
  199. when :quad
  200. return register(name)
  201. end
  202. else
  203. raise "bad GPR name #{name}"
  204. end
  205. case kind
  206. when :byte
  207. register(name8)
  208. when :half
  209. register(name16)
  210. when :int
  211. register("e" + name16)
  212. when :ptr
  213. register((isX64 ? "r" : "e") + name16)
  214. when :quad
  215. isX64 ? register("r" + name16) : raise
  216. else
  217. raise "invalid kind #{kind} for GPR #{name} in X86"
  218. end
  219. end
  220. class Node
  221. def x86LoadOperand(type, dst)
  222. x86Operand(type)
  223. end
  224. end
  225. class RegisterID
  226. def supports8BitOnX86
  227. case x86GPR
  228. when "eax", "ebx", "ecx", "edx", "edi", "esi", "ebp", "esp"
  229. true
  230. when "r8", "r9", "r10", "r12", "r13", "r14", "r15"
  231. false
  232. else
  233. raise
  234. end
  235. end
  236. def x86GPR
  237. if isX64
  238. case name
  239. when "t0", "r0", "ws0"
  240. "eax"
  241. when "r1"
  242. "edx" # t1 = a1 when isWin, t2 = a2 otherwise
  243. when "a0", "wa0"
  244. isWin ? "ecx" : "edi"
  245. when "t1", "a1", "wa1"
  246. isWin ? "edx" : "esi"
  247. when "t2", "a2", "wa2"
  248. isWin ? "r8" : "edx"
  249. when "t3", "a3", "wa3"
  250. isWin ? "r9" : "ecx"
  251. when "t4", "wa4"
  252. isWin ? "r10" : "r8"
  253. when "t5", "wa5"
  254. isWin ? "ecx" : "r9"
  255. when "t6", "ws1"
  256. raise "cannot use register #{name} on X86-64 Windows" if isWin
  257. "r10"
  258. when "csr0"
  259. "ebx"
  260. when "csr1"
  261. isWin ? "esi" : "r12"
  262. when "csr2"
  263. isWin ? "edi" : "r13"
  264. when "csr3"
  265. isWin ? "r12" : "r14"
  266. when "csr4"
  267. isWin ? "r13" : "r15"
  268. when "csr5"
  269. raise "cannot use register #{name} on X86-64" unless isWin
  270. "r14"
  271. when "csr6"
  272. raise "cannot use register #{name} on X86-64" unless isWin
  273. "r15"
  274. when "cfr"
  275. "ebp"
  276. when "sp"
  277. "esp"
  278. else
  279. raise "cannot use register #{name} on X86"
  280. end
  281. else
  282. case name
  283. when "t0", "r0", "a2"
  284. "eax"
  285. when "t1", "r1", "a1"
  286. "edx"
  287. when "t2", "a0"
  288. "ecx"
  289. when "t3", "a3"
  290. "ebx"
  291. when "t4"
  292. "esi"
  293. when "t5"
  294. "edi"
  295. when "cfr"
  296. "ebp"
  297. when "sp"
  298. "esp"
  299. end
  300. end
  301. end
  302. def x86Operand(kind)
  303. x86GPRName(x86GPR, kind)
  304. end
  305. def x86CallOperand(kind)
  306. "#{callPrefix}#{x86Operand(:ptr)}"
  307. end
  308. end
  309. class FPRegisterID
  310. def x86Operand(kind)
  311. raise unless [:float, :double].include? kind
  312. case name
  313. when "ft0", "fa0", "fr", "wfa0"
  314. register("xmm0")
  315. when "ft1", "fa1", "wfa1"
  316. register("xmm1")
  317. when "ft2", "fa2", "wfa2"
  318. register("xmm2")
  319. when "ft3", "fa3", "wfa3"
  320. register("xmm3")
  321. when "ft4", "wfa4"
  322. register("xmm4")
  323. when "ft5", "wfa5"
  324. register("xmm5")
  325. when "wfa6"
  326. register("xmm6")
  327. when "wfa7"
  328. register("xmm7")
  329. else
  330. raise "Bad register #{name} for X86 at #{codeOriginString}"
  331. end
  332. end
  333. def x86CallOperand(kind)
  334. "#{callPrefix}#{x86Operand(kind)}"
  335. end
  336. end
  337. class Immediate
  338. def validX86Immediate?
  339. if isX64
  340. value >= -0x80000000 and value <= 0x7fffffff
  341. else
  342. true
  343. end
  344. end
  345. def x86Operand(kind)
  346. "#{const(value)}"
  347. end
  348. def x86CallOperand(kind)
  349. "#{value}"
  350. end
  351. end
  352. class Address
  353. def supports8BitOnX86
  354. true
  355. end
  356. def x86AddressOperand(addressKind)
  357. "#{offsetRegister(offset.value, base.x86Operand(addressKind))}"
  358. end
  359. def x86Operand(kind)
  360. "#{getSizeString(kind)}#{x86AddressOperand(:ptr)}"
  361. end
  362. def x86CallOperand(kind)
  363. "#{callPrefix}#{x86Operand(kind)}"
  364. end
  365. end
  366. class BaseIndex
  367. def supports8BitOnX86
  368. true
  369. end
  370. def x86AddressOperand(addressKind)
  371. if !isIntelSyntax
  372. "#{offset.value}(#{base.x86Operand(addressKind)}, #{index.x86Operand(addressKind)}, #{scaleValue})"
  373. else
  374. "#{getSizeString(addressKind)}[#{offset.value} + #{base.x86Operand(addressKind)} + #{index.x86Operand(addressKind)} * #{scaleValue}]"
  375. end
  376. end
  377. def x86Operand(kind)
  378. if !isIntelSyntax
  379. x86AddressOperand(:ptr)
  380. else
  381. "#{getSizeString(kind)}[#{offset.value} + #{base.x86Operand(:ptr)} + #{index.x86Operand(:ptr)} * #{scaleValue}]"
  382. end
  383. end
  384. def x86CallOperand(kind)
  385. "#{callPrefix}#{x86Operand(kind)}"
  386. end
  387. end
  388. class AbsoluteAddress
  389. def supports8BitOnX86
  390. true
  391. end
  392. def x86AddressOperand(addressKind)
  393. "#{address.value}"
  394. end
  395. def x86Operand(kind)
  396. "#{address.value}"
  397. end
  398. def x86CallOperand(kind)
  399. "#{callPrefix}#{address.value}"
  400. end
  401. end
  402. class LabelReference
  403. def x86CallOperand(kind)
  404. asmLabel
  405. end
  406. def x86LoadOperand(kind, dst)
  407. # FIXME: Implement this on platforms that aren't Mach-O.
  408. # https://bugs.webkit.org/show_bug.cgi?id=175104
  409. used
  410. if !isIntelSyntax
  411. $asm.puts "movq #{asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
  412. else
  413. $asm.puts "lea #{dst.x86Operand(:ptr)}, #{asmLabel}"
  414. end
  415. "#{offset}(#{dst.x86Operand(kind)})"
  416. end
  417. end
  418. class LocalLabelReference
  419. def x86Operand(kind)
  420. asmLabel
  421. end
  422. def x86CallOperand(kind)
  423. asmLabel
  424. end
  425. end
  426. class Sequence
  427. def getModifiedListX86_64
  428. newList = []
  429. @list.each {
  430. | node |
  431. newNode = node
  432. if node.is_a? Instruction
  433. unless node.opcode == "move"
  434. usedScratch = false
  435. newOperands = node.operands.map {
  436. | operand |
  437. if operand.immediate? and not operand.validX86Immediate?
  438. if usedScratch
  439. raise "Attempt to use scratch register twice at #{operand.codeOriginString}"
  440. end
  441. newList << Instruction.new(operand.codeOrigin, "move", [operand, X64_SCRATCH_REGISTER])
  442. usedScratch = true
  443. X64_SCRATCH_REGISTER
  444. else
  445. operand
  446. end
  447. }
  448. newNode = Instruction.new(node.codeOrigin, node.opcode, newOperands, node.annotation)
  449. end
  450. else
  451. unless node.is_a? Label or
  452. node.is_a? LocalLabel or
  453. node.is_a? Skip
  454. raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
  455. end
  456. end
  457. if newNode
  458. newList << newNode
  459. end
  460. }
  461. return newList
  462. end
  463. def getModifiedListX86_64_WIN
  464. getModifiedListX86_64
  465. end
  466. end
  467. class Instruction
  468. def x86Operands(*kinds)
  469. raise "Expected size of kinds to be #{operands.size}, but it was #{kinds.size}" unless kinds.size == operands.size
  470. result = []
  471. kinds.size.times {
  472. | idx |
  473. i = isIntelSyntax ? (kinds.size - idx - 1) : idx
  474. result << operands[i].x86Operand(kinds[i])
  475. }
  476. result.join(", ")
  477. end
  478. def x86LoadOperands(srcKind, dstKind)
  479. orderOperands(operands[0].x86LoadOperand(srcKind, operands[1]), operands[1].x86Operand(dstKind))
  480. end
  481. def x86Suffix(kind)
  482. if isIntelSyntax and not [:float, :double].include? kind
  483. return ""
  484. end
  485. case kind
  486. when :byte
  487. "b"
  488. when :half
  489. "w"
  490. when :int
  491. "l"
  492. when :ptr
  493. isX64 ? "q" : "l"
  494. when :quad
  495. isX64 ? "q" : raise
  496. when :float
  497. "ss"
  498. when :double
  499. "sd"
  500. else
  501. raise
  502. end
  503. end
  504. def x86Bytes(kind)
  505. case kind
  506. when :byte
  507. 1
  508. when :half
  509. 2
  510. when :int
  511. 4
  512. when :ptr
  513. isX64 ? 8 : 4
  514. when :quad
  515. isX64 ? 8 : raise
  516. when :float
  517. 4
  518. when :double
  519. 8
  520. else
  521. raise
  522. end
  523. end
  524. def emitX86Lea(src, dst, kind)
  525. if src.is_a? LabelReference
  526. src.used
  527. if !isIntelSyntax
  528. $asm.puts "movq #{src.asmLabel}@GOTPCREL(%rip), #{dst.x86Operand(:ptr)}"
  529. else
  530. $asm.puts "lea #{dst.x86Operand(:ptr)}, #{src.asmLabel}"
  531. end
  532. else
  533. $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(src.x86AddressOperand(kind), dst.x86Operand(kind))}"
  534. end
  535. end
  536. def getImplicitOperandString
  537. isIntelSyntax ? "st(0), " : ""
  538. end
  539. def handleX86OpWithNumOperands(opcode, kind, numOperands)
  540. if numOperands == 3
  541. if operands[0] == operands[2]
  542. $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
  543. elsif operands[1] == operands[2]
  544. $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  545. else
  546. $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  547. $asm.puts "#{opcode} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
  548. end
  549. else
  550. $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
  551. end
  552. end
  553. def handleX86Op(opcode, kind)
  554. handleX86OpWithNumOperands(opcode, kind, operands.size)
  555. end
  556. def handleX86Shift(opcode, kind)
  557. if operands[0].is_a? Immediate or operands[0].x86GPR == "ecx"
  558. $asm.puts "#{opcode} #{orderOperands(operands[0].x86Operand(:byte), operands[1].x86Operand(kind))}"
  559. else
  560. $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
  561. $asm.puts "#{opcode} #{orderOperands(register("cl"), operands[1].x86Operand(kind))}"
  562. $asm.puts "xchg#{x86Suffix(:ptr)} #{operands[0].x86Operand(:ptr)}, #{x86GPRName("ecx", :ptr)}"
  563. end
  564. end
  565. def handleX86FPBranch(kind, branchOpcode, mode)
  566. case mode
  567. when :normal
  568. $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(:double), operands[0].x86Operand(:double))}"
  569. when :reverse
  570. $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
  571. else
  572. raise mode.inspect
  573. end
  574. $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
  575. end
  576. def handleX86IntCompare(opcodeSuffix, kind)
  577. if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
  578. $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
  579. elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
  580. $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
  581. else
  582. $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
  583. end
  584. end
  585. def handleX86IntCompare(opcodeSuffix, kind)
  586. if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
  587. $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[1].x86Operand(kind))}"
  588. elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
  589. $asm.puts "test#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[0].x86Operand(kind))}"
  590. else
  591. $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind))}"
  592. end
  593. end
  594. def handleX86IntBranch(branchOpcode, kind)
  595. handleX86IntCompare(branchOpcode[1..-1], kind)
  596. $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
  597. end
  598. def handleX86Set(setOpcode, operand)
  599. if operand.supports8BitOnX86
  600. $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
  601. if !isIntelSyntax
  602. $asm.puts "movzbl #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
  603. else
  604. $asm.puts "movzx #{orderOperands(operand.x86Operand(:byte), operand.x86Operand(:int))}"
  605. end
  606. else
  607. ax = RegisterID.new(nil, "r0")
  608. $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
  609. $asm.puts "#{setOpcode} #{ax.x86Operand(:byte)}"
  610. if !isIntelSyntax
  611. $asm.puts "movzbl #{ax.x86Operand(:byte)}, #{ax.x86Operand(:int)}"
  612. else
  613. $asm.puts "movzx #{ax.x86Operand(:int)}, #{ax.x86Operand(:byte)}"
  614. end
  615. $asm.puts "xchg#{x86Suffix(:ptr)} #{operand.x86Operand(:ptr)}, #{ax.x86Operand(:ptr)}"
  616. end
  617. end
  618. def handleX86IntCompareSet(setOpcode, kind)
  619. handleX86IntCompare(setOpcode[3..-1], kind)
  620. handleX86Set(setOpcode, operands[2])
  621. end
  622. def handleX86FPCompareSet(kind, setOpcode, order = :normal)
  623. is_special = setOpcode.is_a? Symbol
  624. left = operands[0]
  625. right = operands[1]
  626. target = operands[2]
  627. compare = lambda do |lhs, rhs|
  628. $asm.puts "ucomi#{x86Suffix(kind)} #{orderOperands(lhs.x86Operand(:double), rhs.x86Operand(:double))}"
  629. end
  630. if is_special
  631. case setOpcode
  632. when :eq
  633. if left == right
  634. compare.call(right, left)
  635. handleX86Set("setnp", operands[2])
  636. return
  637. end
  638. isUnordered = LocalLabel.unique("isUnordered")
  639. $asm.puts "movq $0, #{target.x86Operand(:quad)}"
  640. compare.call(right, left)
  641. $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
  642. handleX86Set("sete", target)
  643. isUnordered.lower($activeBackend)
  644. return
  645. when :nequn
  646. if left == right
  647. compare.call(right, left)
  648. handleX86Set("setp", target)
  649. return
  650. end
  651. isUnordered = LocalLabel.unique("isUnordered")
  652. $asm.puts "movq $1, #{target.x86Operand(:quad)}"
  653. compare.call(right, left);
  654. $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
  655. handleX86Set("setne", target)
  656. isUnordered.lower($activeBackend)
  657. return
  658. else
  659. raise "Uhandled special opcode: #{setOpcode}"
  660. end
  661. end
  662. if order == :normal
  663. compare.call(right, left)
  664. else
  665. compare.call(left, right)
  666. end
  667. handleX86Set(setOpcode, target)
  668. end
  669. def handleX86Test(kind)
  670. value = operands[0]
  671. case operands.size
  672. when 2
  673. mask = Immediate.new(codeOrigin, -1)
  674. when 3
  675. mask = operands[1]
  676. else
  677. raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
  678. end
  679. if mask.is_a? Immediate and mask.value == -1
  680. if value.is_a? RegisterID
  681. $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
  682. else
  683. $asm.puts "cmp#{x86Suffix(kind)} #{orderOperands(const(0), value.x86Operand(kind))}"
  684. end
  685. else
  686. $asm.puts "test#{x86Suffix(kind)} #{orderOperands(mask.x86Operand(kind), value.x86Operand(kind))}"
  687. end
  688. end
  689. def handleX86BranchTest(branchOpcode, kind)
  690. handleX86Test(kind)
  691. $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
  692. end
  693. def handleX86SetTest(setOpcode, kind)
  694. handleX86Test(kind)
  695. handleX86Set(setOpcode, operands.last)
  696. end
  697. def handleX86OpBranch(opcode, branchOpcode, kind)
  698. handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
  699. case operands.size
  700. when 4
  701. jumpTarget = operands[3]
  702. when 3
  703. jumpTarget = operands[2]
  704. else
  705. raise self.inspect
  706. end
  707. $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
  708. end
  709. def handleX86SubBranch(branchOpcode, kind)
  710. if operands.size == 4 and operands[1] == operands[2]
  711. $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
  712. $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  713. else
  714. handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
  715. end
  716. case operands.size
  717. when 4
  718. jumpTarget = operands[3]
  719. when 3
  720. jumpTarget = operands[2]
  721. else
  722. raise self.inspect
  723. end
  724. $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
  725. end
  726. def handleX86Add(kind)
  727. if operands.size == 3 and operands[1] == operands[2]
  728. unless Immediate.new(nil, 0) == operands[0]
  729. $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  730. end
  731. elsif operands.size == 3 and operands[0].is_a? Immediate
  732. raise unless operands[1].is_a? RegisterID
  733. raise unless operands[2].is_a? RegisterID
  734. if operands[0].value == 0
  735. if operands[1] != operands[2]
  736. $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
  737. end
  738. else
  739. $asm.puts "lea#{x86Suffix(kind)} #{orderOperands(offsetRegister(operands[0].value, operands[1].x86Operand(kind)), operands[2].x86Operand(kind))}"
  740. end
  741. elsif operands.size == 3 and operands[0].is_a? RegisterID
  742. raise unless operands[1].is_a? RegisterID
  743. raise unless operands[2].is_a? RegisterID
  744. if operands[0] == operands[2]
  745. $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[2].x86Operand(kind))}"
  746. else
  747. if !isIntelSyntax
  748. $asm.puts "lea#{x86Suffix(kind)} (#{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}), #{operands[2].x86Operand(kind)}"
  749. else
  750. $asm.puts "lea#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}, [#{operands[0].x86Operand(kind)} + #{operands[1].x86Operand(kind)}]"
  751. end
  752. end
  753. else
  754. unless Immediate.new(nil, 0) == operands[0]
  755. $asm.puts "add#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
  756. end
  757. end
  758. end
  759. def handleX86Sub(kind)
  760. if operands.size == 3
  761. if Immediate.new(nil, 0) == operands[1]
  762. raise unless operands[0].is_a? RegisterID
  763. raise unless operands[2].is_a? RegisterID
  764. if operands[0] != operands[2]
  765. $asm.puts "mov#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  766. end
  767. return
  768. end
  769. if operands[1] == operands[2]
  770. $asm.puts "neg#{x86Suffix(kind)} #{operands[2].x86Operand(kind)}"
  771. if Immediate.new(nil, 0) != operands[0]
  772. $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  773. end
  774. return
  775. end
  776. end
  777. if operands.size == 2
  778. if Immediate.new(nil, 0) == operands[0]
  779. return
  780. end
  781. end
  782. handleX86Op("sub#{x86Suffix(kind)}", kind)
  783. end
  784. def handleX86Mul(kind)
  785. if operands.size == 3 and operands[0].is_a? Immediate
  786. $asm.puts "imul#{x86Suffix(kind)} #{x86Operands(kind, kind, kind)}"
  787. return
  788. end
  789. if operands.size == 2 and operands[0].is_a? Immediate
  790. imm = operands[0].value
  791. if imm > 0 and isPowerOfTwo(imm)
  792. $asm.puts "sal#{x86Suffix(kind)} #{orderOperands(Immediate.new(nil, Math.log2(imm).to_i).x86Operand(kind), operands[1].x86Operand(kind))}"
  793. return
  794. end
  795. end
  796. handleX86Op("imul#{x86Suffix(kind)}", kind)
  797. end
  798. def handleX86AddFP(kind)
  799. if operands.size == 2
  800. $asm.puts "add#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
  801. elsif operands.size == 3
  802. $asm.puts "vadd#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  803. else
  804. raise "Unexpected number of operands for floating point addition: #{operands.size}"
  805. end
  806. end
  807. def handleX86SubFP(kind)
  808. if operands.size == 2
  809. $asm.puts "sub#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
  810. elsif operands.size == 3
  811. $asm.puts "vsub#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  812. else
  813. raise "Unexpected number of operands for floating point addition: #{operands.size}"
  814. end
  815. end
  816. def handleX86MulFP(kind)
  817. if operands.size == 2
  818. $asm.puts "mul#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
  819. elsif operands.size == 3
  820. $asm.puts "vmul#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  821. else
  822. raise "Unexpected number of operands for floating point addition: #{operands.size}"
  823. end
  824. end
  825. def handleX86DivFP(kind)
  826. if operands.size == 2
  827. $asm.puts "div#{x86Suffix(kind)} #{orderOperands(operands[0].x86Operand(kind), operands[1].x86Operand(kind))}"
  828. elsif operands.size == 3
  829. $asm.puts "vdiv#{x86Suffix(kind)} #{orderOperands(operands[1].x86Operand(kind), operands[0].x86Operand(kind), operands[2].x86Operand(kind))}"
  830. else
  831. raise "Unexpected number of operands for floating point addition: #{operands.size}"
  832. end
  833. end
  834. def handleX86Peek()
  835. sp = RegisterID.new(nil, "sp")
  836. opA = offsetRegister(operands[0].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
  837. opB = operands[1].x86Operand(:ptr)
  838. $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
  839. end
  840. def handleX86Poke()
  841. sp = RegisterID.new(nil, "sp")
  842. opA = operands[0].x86Operand(:ptr)
  843. opB = offsetRegister(operands[1].value * x86Bytes(:ptr), sp.x86Operand(:ptr))
  844. $asm.puts "mov#{x86Suffix(:ptr)} #{orderOperands(opA, opB)}"
  845. end
  846. def handleMove
  847. if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
  848. if isX64
  849. $asm.puts "xor#{x86Suffix(:quad)} #{operands[1].x86Operand(:quad)}, #{operands[1].x86Operand(:quad)}"
  850. else
  851. $asm.puts "xor#{x86Suffix(:ptr)} #{operands[1].x86Operand(:ptr)}, #{operands[1].x86Operand(:ptr)}"
  852. end
  853. elsif operands[0] != operands[1]
  854. if isX64
  855. $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
  856. else
  857. $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
  858. end
  859. end
  860. end
  861. def countLeadingZeros(kind)
  862. target = operands[1]
  863. srcIsNonZero = LocalLabel.unique("srcIsNonZero")
  864. skipNonZeroCase = LocalLabel.unique("skipNonZeroCase")
  865. zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8)
  866. xorValue = Immediate.new(codeOrigin, kind == :quad ? 0x3f : 0x1f)
  867. xor = kind == :quad ? "xorq" : "xori"
  868. $asm.puts "bsr#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
  869. Sequence.new(codeOrigin, [
  870. Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]),
  871. Instruction.new(codeOrigin, "move", [zeroValue, target]),
  872. Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, skipNonZeroCase)]),
  873. srcIsNonZero,
  874. Instruction.new(codeOrigin, xor, [xorValue, target]),
  875. skipNonZeroCase,
  876. ]).lower($activeBackend)
  877. end
  878. def countTrailingZeros(kind)
  879. target = operands[1]
  880. srcIsNonZero = LocalLabel.unique("srcIsNonZero")
  881. zeroValue = Immediate.new(codeOrigin, x86Bytes(kind) * 8)
  882. $asm.puts "bsf#{x86Suffix(kind)} #{x86Operands(kind, kind)}"
  883. Sequence.new(codeOrigin, [
  884. Instruction.new(codeOrigin, "bnz", [LocalLabelReference.new(codeOrigin, srcIsNonZero)]),
  885. Instruction.new(codeOrigin, "move", [zeroValue, target]),
  886. srcIsNonZero,
  887. ]).lower($activeBackend)
  888. end
  889. def truncateFloatingPointToQuad(kind)
  890. src = operands[0]
  891. dst = operands[1]
  892. slow = LocalLabel.unique("slow")
  893. done = LocalLabel.unique("done")
  894. gprScratch = X64_SCRATCH_REGISTER
  895. fprScratch = FPRegisterID.forName(codeOrigin, "wfa7")
  896. int64SignBit = Immediate.new(codeOrigin, 0x8000000000000000)
  897. case kind
  898. when :float
  899. int64Min = Immediate.new(codeOrigin, 0xdf000000)
  900. negInt64Min = Immediate.new(codeOrigin, 0x5f000000)
  901. integerSuffix = "i"
  902. floatingSuffix = "f"
  903. when :double
  904. int64Min = Immediate.new(codeOrigin, 0xc3e0000000000000)
  905. negInt64Min = Immediate.new(codeOrigin, 0x43e0000000000000)
  906. integerSuffix = "q"
  907. floatingSuffix = "d"
  908. else
  909. raise
  910. end
  911. Sequence.new(codeOrigin, [
  912. Instruction.new(codeOrigin, "move", [negInt64Min, gprScratch]),
  913. Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]),
  914. Instruction.new(codeOrigin, "b#{floatingSuffix}gteq", [src, fprScratch, LocalLabelReference.new(codeOrigin, slow)]),
  915. Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [src, dst]),
  916. Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]),
  917. slow,
  918. Instruction.new(codeOrigin, "move", [int64Min, gprScratch]),
  919. Instruction.new(codeOrigin, "f#{integerSuffix}2#{floatingSuffix}", [gprScratch, fprScratch]),
  920. Instruction.new(codeOrigin, "add#{floatingSuffix}", [src, fprScratch]),
  921. Instruction.new(codeOrigin, "truncate#{floatingSuffix}2qs", [fprScratch, dst]),
  922. Instruction.new(codeOrigin, "move", [int64SignBit, gprScratch]),
  923. Instruction.new(codeOrigin, "orq", [gprScratch, dst]),
  924. done,
  925. ]).lower($activeBackend)
  926. end
  927. def convertQuadToFloatingPoint(kind)
  928. src = operands[0]
  929. scratch1 = operands[1]
  930. dst = operands[2]
  931. slow = LocalLabel.unique("slow")
  932. done = LocalLabel.unique("done")
  933. scratch2 = X64_SCRATCH_REGISTER
  934. one = Immediate.new(codeOrigin, 0x1)
  935. case kind
  936. when :float
  937. floatingSuffix = "f"
  938. when :double
  939. floatingSuffix = "d"
  940. else
  941. raise
  942. end
  943. Sequence.new(codeOrigin, [
  944. Instruction.new(codeOrigin, "btqs", [src, LocalLabelReference.new(codeOrigin, slow)]),
  945. Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [src, dst]),
  946. Instruction.new(codeOrigin, "jmp", [LocalLabelReference.new(codeOrigin, done)]),
  947. slow,
  948. Instruction.new(codeOrigin, "move", [src, scratch1]),
  949. Instruction.new(codeOrigin, "move", [src, scratch2]),
  950. Instruction.new(codeOrigin, "urshiftq", [one, scratch1]),
  951. Instruction.new(codeOrigin, "andq", [one, scratch2]),
  952. Instruction.new(codeOrigin, "orq", [scratch1, scratch2]),
  953. Instruction.new(codeOrigin, "cq2#{floatingSuffix}s", [scratch2, dst]),
  954. Instruction.new(codeOrigin, "add#{floatingSuffix}", [dst, dst]),
  955. done,
  956. ]).lower($activeBackend)
  957. end
  958. def lowerX86
  959. raise unless $activeBackend == "X86"
  960. lowerX86Common
  961. end
  962. def lowerX86_WIN
  963. raise unless $activeBackend == "X86_WIN"
  964. lowerX86Common
  965. end
  966. def lowerX86_64
  967. raise unless $activeBackend == "X86_64"
  968. lowerX86Common
  969. end
  970. def lowerX86_64_WIN
  971. raise unless $activeBackend == "X86_64_WIN"
  972. lowerX86Common
  973. end
  974. def lowerX86Common
  975. case opcode
  976. when "addi"
  977. handleX86Add(:int)
  978. when "addp"
  979. handleX86Add(:ptr)
  980. when "addq"
  981. handleX86Add(:quad)
  982. when "andi"
  983. handleX86Op("and#{x86Suffix(:int)}", :int)
  984. when "andp"
  985. handleX86Op("and#{x86Suffix(:ptr)}", :ptr)
  986. when "andq"
  987. handleX86Op("and#{x86Suffix(:quad)}", :quad)
  988. when "andf"
  989. handleX86Op("andps", :float)
  990. when "andd"
  991. handleX86Op("andpd", :double)
  992. when "lshifti"
  993. handleX86Shift("sal#{x86Suffix(:int)}", :int)
  994. when "lshiftp"
  995. handleX86Shift("sal#{x86Suffix(:ptr)}", :ptr)
  996. when "lshiftq"
  997. handleX86Shift("sal#{x86Suffix(:quad)}", :quad)
  998. when "muli"
  999. handleX86Mul(:int)
  1000. when "mulp"
  1001. handleX86Mul(:ptr)
  1002. when "mulq"
  1003. handleX86Mul(:quad)
  1004. when "negi"
  1005. $asm.puts "neg#{x86Suffix(:int)} #{x86Operands(:int)}"
  1006. when "negp"
  1007. $asm.puts "neg#{x86Suffix(:ptr)} #{x86Operands(:ptr)}"
  1008. when "negq"
  1009. $asm.puts "neg#{x86Suffix(:quad)} #{x86Operands(:quad)}"
  1010. when "noti"
  1011. $asm.puts "not#{x86Suffix(:int)} #{x86Operands(:int)}"
  1012. when "ori"
  1013. handleX86Op("or#{x86Suffix(:int)}", :int)
  1014. when "orp"
  1015. handleX86Op("or#{x86Suffix(:ptr)}", :ptr)
  1016. when "orq"
  1017. handleX86Op("or#{x86Suffix(:quad)}", :quad)
  1018. when "orf"
  1019. handleX86Op("orps", :float)
  1020. when "ord"
  1021. handleX86Op("orpd", :double)
  1022. when "orh"
  1023. handleX86Op("or#{x86Suffix(:half)}", :half)
  1024. when "rshifti"
  1025. handleX86Shift("sar#{x86Suffix(:int)}", :int)
  1026. when "rshiftp"
  1027. handleX86Shift("sar#{x86Suffix(:ptr)}", :ptr)
  1028. when "rshiftq"
  1029. handleX86Shift("sar#{x86Suffix(:quad)}", :quad)
  1030. when "urshifti"
  1031. handleX86Shift("shr#{x86Suffix(:int)}", :int)
  1032. when "urshiftp"
  1033. handleX86Shift("shr#{x86Suffix(:ptr)}", :ptr)
  1034. when "urshiftq"
  1035. handleX86Shift("shr#{x86Suffix(:quad)}", :quad)
  1036. when "rrotatei"
  1037. handleX86Shift("ror#{x86Suffix(:int)}", :int)
  1038. when "rrotateq"
  1039. handleX86Shift("ror#{x86Suffix(:quad)}", :quad)
  1040. when "lrotatei"
  1041. handleX86Shift("rol#{x86Suffix(:int)}", :int)
  1042. when "lrotateq"
  1043. handleX86Shift("rol#{x86Suffix(:quad)}", :quad)
  1044. when "subi"
  1045. handleX86Sub(:int)
  1046. when "subp"
  1047. handleX86Sub(:ptr)
  1048. when "subq"
  1049. handleX86Sub(:quad)
  1050. when "xori"
  1051. handleX86Op("xor#{x86Suffix(:int)}", :int)
  1052. when "xorp"
  1053. handleX86Op("xor#{x86Suffix(:ptr)}", :ptr)
  1054. when "xorq"
  1055. handleX86Op("xor#{x86Suffix(:quad)}", :quad)
  1056. when "leap"
  1057. emitX86Lea(operands[0], operands[1], :ptr)
  1058. when "loadi"
  1059. $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
  1060. when "storei"
  1061. $asm.puts "mov#{x86Suffix(:int)} #{x86Operands(:int, :int)}"
  1062. when "loadis"
  1063. if isX64
  1064. if !isIntelSyntax
  1065. $asm.puts "movslq #{x86LoadOperands(:int, :quad)}"
  1066. else
  1067. $asm.puts "movsxd #{x86LoadOperands(:int, :quad)}"
  1068. end
  1069. else
  1070. $asm.puts "mov#{x86Suffix(:int)} #{x86LoadOperands(:int, :int)}"
  1071. end
  1072. when "loadp"
  1073. $asm.puts "mov#{x86Suffix(:ptr)} #{x86LoadOperands(:ptr, :ptr)}"
  1074. when "storep"
  1075. $asm.puts "mov#{x86Suffix(:ptr)} #{x86Operands(:ptr, :ptr)}"
  1076. when "loadq"
  1077. $asm.puts "mov#{x86Suffix(:quad)} #{x86LoadOperands(:quad, :quad)}"
  1078. when "storeq"
  1079. $asm.puts "mov#{x86Suffix(:quad)} #{x86Operands(:quad, :quad)}"
  1080. when "loadb"
  1081. if !isIntelSyntax
  1082. $asm.puts "movzbl #{x86LoadOperands(:byte, :int)}"
  1083. else
  1084. $asm.puts "movzx #{x86LoadOperands(:byte, :int)}"
  1085. end
  1086. when "loadbsi"
  1087. if !isIntelSyntax
  1088. $asm.puts "movsbl #{x86LoadOperands(:byte, :int)}"
  1089. else
  1090. $asm.puts "movsx #{x86LoadOperands(:byte, :int)}"
  1091. end
  1092. when "loadbsq"
  1093. if !isIntelSyntax
  1094. $asm.puts "movsbq #{x86LoadOperands(:byte, :quad)}"
  1095. else
  1096. $asm.puts "movsx #{x86LoadOperands(:byte, :quad)}"
  1097. end
  1098. when "loadh"
  1099. if !isIntelSyntax
  1100. $asm.puts "movzwl #{x86LoadOperands(:half, :int)}"
  1101. else
  1102. $asm.puts "movzx #{x86LoadOperands(:half, :int)}"
  1103. end
  1104. when "loadhsi"
  1105. if !isIntelSyntax
  1106. $asm.puts "movswl #{x86LoadOperands(:half, :int)}"
  1107. else
  1108. $asm.puts "movsx #{x86LoadOperands(:half, :int)}"
  1109. end
  1110. when "loadhsq"
  1111. if !isIntelSyntax
  1112. $asm.puts "movswq #{x86LoadOperands(:half, :quad)}"
  1113. else
  1114. $asm.puts "movsx #{x86LoadOperands(:half, :quad)}"
  1115. end
  1116. when "storeb"
  1117. $asm.puts "mov#{x86Suffix(:byte)} #{x86Operands(:byte, :byte)}"
  1118. when "storeh"
  1119. $asm.puts "mov#{x86Suffix(:half)} #{x86Operands(:half, :half)}"
  1120. when "loadf"
  1121. $asm.puts "movss #{x86Operands(:float, :float)}"
  1122. when "loadd"
  1123. $asm.puts "movsd #{x86Operands(:double, :double)}"
  1124. when "moved"
  1125. $asm.puts "movsd #{x86Operands(:double, :double)}"
  1126. when "storef"
  1127. $asm.puts "movss #{x86Operands(:float, :float)}"
  1128. when "stored"
  1129. $asm.puts "movsd #{x86Operands(:double, :double)}"
  1130. when "addf"
  1131. handleX86AddFP(:float)
  1132. when "addd"
  1133. handleX86AddFP(:double)
  1134. when "mulf"
  1135. handleX86MulFP(:float)
  1136. when "muld"
  1137. handleX86MulFP(:double)
  1138. when "subf"
  1139. handleX86SubFP(:float)
  1140. when "subd"
  1141. handleX86SubFP(:double)
  1142. when "divf"
  1143. handleX86DivFP(:float)
  1144. when "divd"
  1145. handleX86DivFP(:double)
  1146. when "sqrtf"
  1147. $asm.puts "sqrtss #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:float)}"
  1148. when "sqrtd"
  1149. $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1150. when "roundf"
  1151. $asm.puts "roundss $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1152. when "roundd"
  1153. $asm.puts "roundsd $0, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1154. when "floorf"
  1155. $asm.puts "roundss $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1156. when "floord"
  1157. $asm.puts "roundsd $1, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1158. when "ceilf"
  1159. $asm.puts "roundss $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1160. when "ceild"
  1161. $asm.puts "roundsd $2, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1162. when "truncatef"
  1163. $asm.puts "roundss $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1164. when "truncated"
  1165. $asm.puts "roundsd $3, #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
  1166. when "truncatef2i"
  1167. $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}"
  1168. when "truncated2i"
  1169. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
  1170. when "truncatef2q"
  1171. truncateFloatingPointToQuad(:float)
  1172. when "truncated2q"
  1173. truncateFloatingPointToQuad(:double)
  1174. when "truncatef2is"
  1175. $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:int)}"
  1176. when "truncatef2qs"
  1177. $asm.puts "cvttss2si #{operands[0].x86Operand(:float)}, #{operands[1].x86Operand(:quad)}"
  1178. when "truncated2is"
  1179. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
  1180. when "truncated2qs"
  1181. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:quad)}"
  1182. when "ci2d"
  1183. $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}"
  1184. when "ci2ds"
  1185. $asm.puts "cvtsi2sd #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:double))}"
  1186. when "ci2fs"
  1187. $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:int), operands[1].x86Operand(:float))}"
  1188. when "ci2f"
  1189. $asm.puts "cvtsi2ss #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}"
  1190. when "cq2f"
  1191. convertQuadToFloatingPoint(:float)
  1192. when "cq2d"
  1193. convertQuadToFloatingPoint(:double)
  1194. when "cq2fs"
  1195. $asm.puts "cvtsi2ssq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:float))}"
  1196. when "cq2ds"
  1197. $asm.puts "cvtsi2sdq #{orderOperands(operands[0].x86Operand(:quad), operands[1].x86Operand(:double))}"
  1198. when "cd2f"
  1199. $asm.puts "cvtsd2ss #{x86Operands(:double, :float)}"
  1200. when "cf2d"
  1201. $asm.puts "cvtss2sd #{x86Operands(:float, :double)}"
  1202. when "bdeq"
  1203. $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
  1204. if operands[0] == operands[1]
  1205. # This is just a jump ordered, which is a jnp.
  1206. $asm.puts "jnp #{operands[2].asmLabel}"
  1207. else
  1208. isUnordered = LocalLabel.unique("bdeq")
  1209. $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
  1210. $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}"
  1211. isUnordered.lower($activeBackend)
  1212. end
  1213. when "bdneq"
  1214. handleX86FPBranch(:double, "jne", :normal)
  1215. when "bdgt"
  1216. handleX86FPBranch(:double, "ja", :normal)
  1217. when "bdgteq"
  1218. handleX86FPBranch(:double, "jae", :normal)
  1219. when "bdlt"
  1220. handleX86FPBranch(:double, "ja", :reverse)
  1221. when "bdlteq"
  1222. handleX86FPBranch(:double, "jae", :reverse)
  1223. when "bdequn"
  1224. handleX86FPBranch(:double, "je", :normal)
  1225. when "bdnequn"
  1226. $asm.puts "ucomisd #{orderOperands(operands[0].x86Operand(:double), operands[1].x86Operand(:double))}"
  1227. if operands[0] == operands[1]
  1228. # This is just a jump unordered, which is a jp.
  1229. $asm.puts "jp #{operands[2].asmLabel}"
  1230. else
  1231. isUnordered = LocalLabel.unique("bdnequn")
  1232. isEqual = LocalLabel.unique("bdnequn")
  1233. $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
  1234. $asm.puts "je #{LocalLabelReference.new(codeOrigin, isEqual).asmLabel}"
  1235. isUnordered.lower($activeBackend)
  1236. $asm.puts "jmp #{operands[2].asmLabel}"
  1237. isEqual.lower($activeBackend)
  1238. end
  1239. when "bdgtun"
  1240. handleX86FPBranch(:double, "jb", :reverse)
  1241. when "bdgtequn"
  1242. handleX86FPBranch(:double, "jbe", :reverse)
  1243. when "bdltun"
  1244. handleX86FPBranch(:double, "jb", :normal)
  1245. when "bdltequn"
  1246. handleX86FPBranch(:double, "jbe", :normal)
  1247. when "bfeq"
  1248. $asm.puts "ucomiss #{orderOperands(operands[0].x86Operand(:float), operands[1].x86Operand(:float))}"
  1249. if operands[0] == operands[1]
  1250. # This is just a jump ordered, which is a jnp.
  1251. $asm.puts "jnp #{operands[2].asmLabel}"
  1252. else
  1253. isUnordered = LocalLabel.unique("bfeq")
  1254. $asm.puts "jp #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}"
  1255. $asm.puts "je #{LocalLabelReference.new(codeOrigin, operands[2]).asmLabel}"
  1256. isUnordered.lower($activeBackend)
  1257. end
  1258. when "bfgt"
  1259. handleX86FPBranch(:float, "ja", :normal)
  1260. when "bfgteq"
  1261. handleX86FPBranch(:float, "jae", :normal)
  1262. when "bflt"
  1263. handleX86FPBranch(:float, "ja", :reverse)
  1264. when "bfgtun"
  1265. handleX86FPBranch(:float, "jb", :reverse)
  1266. when "bfgtequn"
  1267. handleX86FPBranch(:float, "jbe", :reverse)
  1268. when "bfltun"
  1269. handleX86FPBranch(:float, "jb", :normal)
  1270. when "bfltequn"
  1271. handleX86FPBranch(:float, "jbe", :normal)
  1272. when "btd2i"
  1273. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
  1274. $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
  1275. $asm.puts "je #{operands[2].asmLabel}"
  1276. when "td2i"
  1277. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
  1278. when "bcd2i"
  1279. $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
  1280. $asm.puts "test#{x86Suffix(:int)} #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
  1281. $asm.puts "je #{operands[2].asmLabel}"
  1282. $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
  1283. $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
  1284. $asm.puts "jp #{operands[2].asmLabel}"
  1285. $asm.puts "jne #{operands[2].asmLabel}"
  1286. when "movdz"
  1287. $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}…

Large files files are truncated, but you can click here to view the full file