mips.rb 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. # Copyright (C) 2012 Apple Inc. All rights reserved.
  2. # Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
  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 MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
  14. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
  17. # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. require 'risc'
  25. class Assembler
  26. def putStr(str)
  27. @outp.puts str
  28. end
  29. end
  30. class Node
  31. def mipsSingleHi
  32. doubleOperand = mipsOperand
  33. raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
  34. "$f" + ($~.post_match.to_i + 1).to_s
  35. end
  36. def mipsSingleLo
  37. doubleOperand = mipsOperand
  38. raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
  39. doubleOperand
  40. end
  41. end
  42. class SpecialRegister < NoChildren
  43. def mipsOperand
  44. @name
  45. end
  46. def dump
  47. @name
  48. end
  49. def register?
  50. true
  51. end
  52. end
  53. MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"),
  54. SpecialRegister.new("$t8")]
  55. MIPS_ZERO_REG = SpecialRegister.new("$zero")
  56. MIPS_GP_REG = SpecialRegister.new("$gp")
  57. MIPS_GPSAVE_REG = SpecialRegister.new("$s4")
  58. MIPS_JUMP_REG = SpecialRegister.new("$ra")
  59. MIPS_CALL_REG = SpecialRegister.new("$t9")
  60. MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")]
  61. MIPS_SCRATCH_FPR = SpecialRegister.new("$f18")
  62. def mipsMoveImmediate(value, register)
  63. if value == 0
  64. $asm.puts "add #{register.mipsOperand}, $zero, $zero"
  65. else
  66. $asm.puts "li #{register.mipsOperand}, #{value}"
  67. end
  68. end
  69. class RegisterID
  70. def mipsOperand
  71. case name
  72. when "a0"
  73. "$a0"
  74. when "a1"
  75. "$a1"
  76. when "r0", "t0"
  77. "$v0"
  78. when "r1", "t1"
  79. "$v1"
  80. when "t2"
  81. "$t2"
  82. when "t3"
  83. "$s3"
  84. when "t4" # PC reg in llint
  85. "$s2"
  86. when "t5"
  87. "$t5"
  88. when "t6"
  89. "$t6"
  90. when "t7"
  91. "$t7"
  92. when "t8"
  93. "$t8"
  94. when "cfr"
  95. "$s0"
  96. when "lr"
  97. "$ra"
  98. when "sp"
  99. "$sp"
  100. else
  101. raise "Bad register #{name} for MIPS at #{codeOriginString}"
  102. end
  103. end
  104. end
  105. class FPRegisterID
  106. def mipsOperand
  107. case name
  108. when "ft0", "fr"
  109. "$f0"
  110. when "ft1"
  111. "$f2"
  112. when "ft2"
  113. "$f4"
  114. when "ft3"
  115. "$f6"
  116. when "ft4"
  117. "$f8"
  118. when "ft5"
  119. "$f10"
  120. when "fa0"
  121. "$f12"
  122. when "fa1"
  123. "$f14"
  124. else
  125. raise "Bad register #{name} for MIPS at #{codeOriginString}"
  126. end
  127. end
  128. end
  129. class Immediate
  130. def mipsOperand
  131. raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0x7fff
  132. "#{value}"
  133. end
  134. end
  135. class Address
  136. def mipsOperand
  137. raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff
  138. "#{offset.value}(#{base.mipsOperand})"
  139. end
  140. end
  141. class AbsoluteAddress
  142. def mipsOperand
  143. raise "Unconverted absolute address at #{codeOriginString}"
  144. end
  145. end
  146. #
  147. # Lower 'and' masked branches
  148. #
  149. def lowerMIPSCondBranch(list, condOp, node)
  150. if node.operands.size == 2
  151. list << Instruction.new(node.codeOrigin,
  152. condOp,
  153. [node.operands[0], MIPS_ZERO_REG, node.operands[-1]],
  154. node.annotation)
  155. elsif node.operands.size == 3
  156. tmp = Tmp.new(node.codeOrigin, :gpr)
  157. list << Instruction.new(node.codeOrigin,
  158. "andi",
  159. [node.operands[0], node.operands[1], tmp],
  160. node.annotation)
  161. list << Instruction.new(node.codeOrigin,
  162. condOp,
  163. [tmp, MIPS_ZERO_REG, node.operands[-1]])
  164. else
  165. raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
  166. end
  167. end
  168. #
  169. # Lowering of branch ops. For example:
  170. #
  171. # baddiz foo, bar, baz
  172. #
  173. # will become:
  174. #
  175. # addi foo, bar
  176. # bz baz
  177. #
  178. def mipsLowerSimpleBranchOps(list)
  179. newList = []
  180. list.each {
  181. | node |
  182. if node.is_a? Instruction
  183. annotation = node.annotation
  184. case node.opcode
  185. when /^b(addi|subi|ori|addp)/
  186. op = $1
  187. bc = $~.post_match
  188. branch = "b" + bc
  189. case op
  190. when "addi", "addp"
  191. op = "addi"
  192. when "subi"
  193. op = "subi"
  194. when "ori"
  195. op = "ori"
  196. end
  197. if bc == "o"
  198. case op
  199. when "addi"
  200. # addu $s0, $s1, $s2
  201. # xor $t0, $s1, $s2
  202. # blt $t0, $zero, no overflow
  203. # xor $t0, $s0, $s1
  204. # blt $t0, $zero, overflow
  205. # no overflow:
  206. #
  207. tr = Tmp.new(node.codeOrigin, :gpr)
  208. tmp = Tmp.new(node.codeOrigin, :gpr)
  209. noFlow = LocalLabel.unique("noflow")
  210. noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
  211. newList << Instruction.new(node.codeOrigin, op, [node.operands[0], node.operands[1], tr], annotation)
  212. newList << Instruction.new(node.codeOrigin, "xori", [node.operands[0], node.operands[1], tmp])
  213. newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, noFlowRef])
  214. newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[0], tmp])
  215. newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
  216. newList << noFlow
  217. newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
  218. when "subi"
  219. # subu $s0, $s1, $s2
  220. # xor $t0, $s1, $s2
  221. # bge $t0, $zero, no overflow
  222. # xor $t0, $s0, $s1
  223. # blt $t0, $zero, overflow
  224. # no overflow:
  225. #
  226. tr = Tmp.new(node.codeOrigin, :gpr)
  227. tmp = Tmp.new(node.codeOrigin, :gpr)
  228. noFlow = LocalLabel.unique("noflow")
  229. noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
  230. newList << Instruction.new(node.codeOrigin, op, [node.operands[1], node.operands[0], tr], annotation)
  231. newList << Instruction.new(node.codeOrigin, "xori", [node.operands[1], node.operands[0], tmp])
  232. newList << Instruction.new(node.codeOrigin, "bigteq", [tmp, MIPS_ZERO_REG, noFlowRef])
  233. newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[1], tmp])
  234. newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
  235. newList << noFlow
  236. newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
  237. when "ori"
  238. # no ovwerflow at ori
  239. newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation)
  240. end
  241. else
  242. if node.operands[1].is_a? Address
  243. addr = node.operands[1]
  244. tr = Tmp.new(node.codeOrigin, :gpr)
  245. newList << Instruction.new(node.codeOrigin, "loadp", [addr, tr], annotation)
  246. newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tr])
  247. newList << Instruction.new(node.codeOrigin, "storep", [tr, addr])
  248. else
  249. tr = node.operands[1]
  250. newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
  251. end
  252. newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]])
  253. end
  254. when "bia", "bpa", "bba"
  255. tmp = Tmp.new(node.codeOrigin, :gpr)
  256. comp = node.opcode[1] == ?b ? "sltub" : "sltu"
  257. newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
  258. newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
  259. when "biaeq", "bpaeq", "bbaeq"
  260. tmp = Tmp.new(node.codeOrigin, :gpr)
  261. comp = node.opcode[1] == ?b ? "sltub" : "sltu"
  262. newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
  263. newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
  264. when "bib", "bpb", "bbb"
  265. tmp = Tmp.new(node.codeOrigin, :gpr)
  266. comp = node.opcode[1] == ?b ? "sltub" : "sltu"
  267. newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
  268. newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
  269. when "bibeq", "bpbeq", "bbbeq"
  270. tmp = Tmp.new(node.codeOrigin, :gpr)
  271. comp = node.opcode[1] == ?b ? "sltub" : "sltu"
  272. newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
  273. newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
  274. when /^bt(i|p|b)/
  275. lowerMIPSCondBranch(newList, "b" + $~.post_match + $1, node)
  276. else
  277. newList << node
  278. end
  279. else
  280. newList << node
  281. end
  282. }
  283. newList
  284. end
  285. #
  286. # Specialization of lowering of malformed BaseIndex addresses.
  287. #
  288. class Node
  289. def mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block)
  290. mapChildren {
  291. | subNode |
  292. subNode.mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block)
  293. }
  294. end
  295. end
  296. class Address
  297. def mipsLowerMalformedAddressesRecurse(list, node, &block)
  298. riscLowerMalformedAddressesRecurse(list, node, &block)
  299. end
  300. end
  301. class BaseIndex
  302. def mipsLowerMalformedAddressesRecurse(list, node, &block)
  303. if scaleShift == 0
  304. tmp0 = Tmp.new(codeOrigin, :gpr)
  305. list << Instruction.new(codeOrigin, "addp", [base, index, tmp0])
  306. Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value));
  307. else
  308. tmp0 = Tmp.new(codeOrigin, :gpr)
  309. list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp0]);
  310. list << Instruction.new(codeOrigin, "addp", [base, tmp0])
  311. Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value));
  312. end
  313. end
  314. end
  315. class AbsoluteAddress
  316. def mipsLowerMalformedAddressesRecurse(list, node, &block)
  317. riscLowerMalformedAddressesRecurse(list, node, &block)
  318. end
  319. end
  320. def mipsLowerMalformedAddresses(list, &block)
  321. newList = []
  322. list.each {
  323. | node |
  324. newList << node.mipsLowerMalformedAddressesRecurse(newList, node, &block)
  325. }
  326. newList
  327. end
  328. #
  329. # Lowering of misplaced immediates of MIPS specific instructions. For example:
  330. #
  331. # sltu reg, 4, 2
  332. #
  333. # will become:
  334. #
  335. # move 4, tmp
  336. # sltu reg, tmp, 2
  337. #
  338. def mipsLowerMisplacedImmediates(list)
  339. newList = []
  340. list.each {
  341. | node |
  342. if node.is_a? Instruction
  343. case node.opcode
  344. when "slt", "sltu", "sltb", "sltub"
  345. if node.operands[1].is_a? Immediate
  346. tmp = Tmp.new(node.codeOrigin, :gpr)
  347. newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], node.annotation)
  348. newList << Instruction.new(node.codeOrigin, node.opcode,
  349. [node.operands[0], tmp, node.operands[2]],
  350. node.annotation)
  351. else
  352. newList << node
  353. end
  354. else
  355. newList << node
  356. end
  357. else
  358. newList << node
  359. end
  360. }
  361. newList
  362. end
  363. #
  364. # Specialization of lowering of misplaced addresses.
  365. #
  366. def mipsLowerMisplacedAddresses(list)
  367. newList = []
  368. list.each {
  369. | node |
  370. if node.is_a? Instruction
  371. postInstructions = []
  372. annotation = node.annotation
  373. case node.opcode
  374. when "jmp"
  375. if node.operands[0].address?
  376. newList << Instruction.new(node.operands[0].codeOrigin, "loadi", [node.operands[0], MIPS_JUMP_REG])
  377. newList << Instruction.new(node.codeOrigin, node.opcode, [MIPS_JUMP_REG])
  378. else
  379. newList << Instruction.new(node.codeOrigin,
  380. node.opcode,
  381. [riscAsRegister(newList, postInstructions, node.operands[0], "p", false)])
  382. end
  383. when "call"
  384. restoreGP = false;
  385. tmp = MIPS_CALL_REG
  386. if node.operands[0].address?
  387. newList << Instruction.new(node.operands[0].codeOrigin, "loadp", [node.operands[0], MIPS_CALL_REG])
  388. restoreGP = true;
  389. elsif node.operands[0].is_a? LabelReference
  390. tmp = node.operands[0]
  391. restoreGP = true;
  392. elsif node.operands[0].register?
  393. newList << Instruction.new(node.operands[0].codeOrigin, "move", [node.operands[0], MIPS_CALL_REG])
  394. restoreGP = true;
  395. else
  396. tmp = node.operands[0]
  397. end
  398. newList << Instruction.new(node.codeOrigin, node.opcode, [tmp])
  399. if restoreGP
  400. newList << Instruction.new(node.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG])
  401. end
  402. when "slt", "sltu"
  403. newList << Instruction.new(node.codeOrigin,
  404. node.opcode,
  405. riscAsRegisters(newList, [], node.operands, "i"))
  406. when "sltub", "sltb"
  407. newList << Instruction.new(node.codeOrigin,
  408. node.opcode,
  409. riscAsRegisters(newList, [], node.operands, "b"))
  410. when /^(bz|bnz|bs|bo)/
  411. tl = $~.post_match == "" ? "i" : $~.post_match
  412. newList << Instruction.new(node.codeOrigin,
  413. node.opcode,
  414. riscAsRegisters(newList, [], node.operands, tl))
  415. else
  416. newList << node
  417. end
  418. newList += postInstructions
  419. else
  420. newList << node
  421. end
  422. }
  423. newList
  424. end
  425. #
  426. # Lowering compares and tests.
  427. #
  428. def mipsLowerCompareTemplate(list, node, opCmp, opMov)
  429. tmp0 = Tmp.new(node.codeOrigin, :gpr)
  430. tmp1 = Tmp.new(node.codeOrigin, :gpr)
  431. list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 0), node.operands[2]])
  432. list << Instruction.new(node.codeOrigin, opCmp, [node.operands[1], node.operands[0], tmp0])
  433. list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 1), tmp1])
  434. list << Instruction.new(node.codeOrigin, opMov, [node.operands[2], tmp1, tmp0])
  435. end
  436. def mipsLowerCompares(list)
  437. newList = []
  438. list.each {
  439. | node |
  440. if node.is_a? Instruction
  441. case node.opcode
  442. when "cieq", "cpeq", "cbeq"
  443. mipsLowerCompareTemplate(newList, node, "subp", "movz")
  444. when "cineq", "cpneq", "cbneq"
  445. mipsLowerCompareTemplate(newList, node, "subp", "movn")
  446. when "tiz", "tbz", "tpz"
  447. mipsLowerCompareTemplate(newList, node, "andp", "movz")
  448. when "tinz", "tbnz", "tpnz"
  449. mipsLowerCompareTemplate(newList, node, "andp", "movn")
  450. when "tio", "tbo", "tpo"
  451. tmp = Tmp.new(node.codeOrigin, :gpr)
  452. list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
  453. list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], MIPS_ZERO_REG, tmp])
  454. when "tis", "tbs", "tps"
  455. tmp = Tmp.new(node.codeOrigin, :gpr)
  456. list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
  457. list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], tmp, MIPS_ZERO_REG])
  458. else
  459. newList << node
  460. end
  461. else
  462. newList << node
  463. end
  464. }
  465. newList
  466. end
  467. #
  468. # Lea support.
  469. #
  470. class Address
  471. def mipsEmitLea(destination)
  472. if destination == base
  473. $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}"
  474. else
  475. $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
  476. end
  477. end
  478. end
  479. #
  480. # Add PIC compatible header code to prologue/entry rutins.
  481. #
  482. def mipsAddPICCode(list)
  483. myList = []
  484. list.each {
  485. | node |
  486. myList << node
  487. if node.is_a? Label
  488. if /_prologue$/.match(node.name) || /^_llint_function_/.match(node.name)
  489. # Functions called from trampoline/JIT codes.
  490. myList << Instruction.new(node.codeOrigin, "pichdr", [])
  491. elsif /_llint_op_catch/.match(node.name)
  492. # Exception cactcher entry point function.
  493. myList << Instruction.new(node.codeOrigin, "pichdrra", [])
  494. end
  495. end
  496. }
  497. myList
  498. end
  499. #
  500. # Actual lowering code follows.
  501. #
  502. class Sequence
  503. def getModifiedListMIPS
  504. result = @list
  505. # Verify that we will only see instructions and labels.
  506. result.each {
  507. | node |
  508. unless node.is_a? Instruction or
  509. node.is_a? Label or
  510. node.is_a? LocalLabel or
  511. node.is_a? Skip
  512. raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
  513. end
  514. }
  515. result = mipsAddPICCode(result)
  516. result = mipsLowerSimpleBranchOps(result)
  517. result = riscLowerSimpleBranchOps(result)
  518. result = riscLowerHardBranchOps(result)
  519. result = riscLowerShiftOps(result)
  520. result = mipsLowerMalformedAddresses(result) {
  521. | node, address |
  522. if address.is_a? Address
  523. (-0xffff..0xffff).include? address.offset.value
  524. else
  525. false
  526. end
  527. }
  528. result = riscLowerMalformedAddressesDouble(result)
  529. result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep"])
  530. result = mipsLowerMisplacedImmediates(result)
  531. result = riscLowerMalformedImmediates(result, -0xffff..0xffff)
  532. result = mipsLowerMisplacedAddresses(result)
  533. result = riscLowerMisplacedAddresses(result)
  534. result = riscLowerRegisterReuse(result)
  535. result = mipsLowerCompares(result)
  536. result = assignRegistersToTemporaries(result, :gpr, MIPS_TEMP_GPRS)
  537. result = assignRegistersToTemporaries(result, :fpr, MIPS_TEMP_FPRS)
  538. return result
  539. end
  540. end
  541. def mipsOperands(operands)
  542. operands.map{|v| v.mipsOperand}.join(", ")
  543. end
  544. def mipsFlippedOperands(operands)
  545. mipsOperands([operands[-1]] + operands[0..-2])
  546. end
  547. def getMIPSOpcode(opcode, suffix)
  548. end
  549. def emitMIPSCompact(opcode, opcodei, operands)
  550. postfix = ""
  551. if opcode == "sub"
  552. if operands[0].is_a? Immediate
  553. opcode = "add"
  554. operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value)
  555. elsif operands[1].is_a? Immediate
  556. opcode = "add"
  557. operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value)
  558. end
  559. postfix = "u"
  560. elsif opcode == "add"
  561. postfix = "u"
  562. end
  563. if operands.size == 3
  564. if operands[0].is_a? Immediate
  565. $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
  566. elsif operands[1].is_a? Immediate
  567. $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
  568. else
  569. $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
  570. end
  571. else
  572. raise unless operands.size == 2
  573. raise unless operands[1].register?
  574. if operands[0].is_a? Immediate
  575. $asm.puts "#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  576. else
  577. $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  578. end
  579. end
  580. end
  581. def emitMIPSShiftCompact(opcode, operands)
  582. if operands.size == 3
  583. if (operands[1].is_a? Immediate)
  584. $asm.puts "#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
  585. else
  586. $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}"
  587. end
  588. else
  589. raise unless operands.size == 2
  590. if operands[0].register?
  591. $asm.puts "#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  592. else
  593. $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
  594. end
  595. end
  596. end
  597. def emitMIPS(opcode, operands)
  598. if operands.size == 3
  599. $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}"
  600. else
  601. raise unless operands.size == 2
  602. $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  603. end
  604. end
  605. def emitMIPSDoubleBranch(branchOpcode, neg, operands)
  606. $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
  607. if (!neg)
  608. $asm.puts "bc1t #{operands[2].asmLabel}"
  609. else
  610. $asm.puts "bc1f #{operands[2].asmLabel}"
  611. end
  612. end
  613. class Instruction
  614. def lowerMIPS
  615. $asm.comment codeOriginString
  616. case opcode
  617. when "addi", "addp", "addis"
  618. if operands.size == 3 and operands[0].is_a? Immediate
  619. raise unless operands[1].register?
  620. raise unless operands[2].register?
  621. if operands[0].value == 0 #and suffix.empty?
  622. unless operands[1] == operands[2]
  623. $asm.puts "move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
  624. end
  625. else
  626. $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  627. end
  628. elsif operands.size == 3 and operands[0].register?
  629. raise unless operands[1].register?
  630. raise unless operands[2].register?
  631. $asm.puts "addu #{mipsFlippedOperands(operands)}"
  632. else
  633. if operands[0].is_a? Immediate
  634. unless Immediate.new(nil, 0) == operands[0]
  635. $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
  636. end
  637. else
  638. $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  639. end
  640. end
  641. when "andi", "andp"
  642. emitMIPSCompact("and", "and", operands)
  643. when "ori", "orp"
  644. emitMIPSCompact("or", "orr", operands)
  645. when "oris"
  646. emitMIPSCompact("or", "orrs", operands)
  647. when "xori", "xorp"
  648. emitMIPSCompact("xor", "eor", operands)
  649. when "lshifti", "lshiftp"
  650. emitMIPSShiftCompact("sll", operands)
  651. when "rshifti", "rshiftp"
  652. emitMIPSShiftCompact("sra", operands)
  653. when "urshifti", "urshiftp"
  654. emitMIPSShiftCompact("srl", operands)
  655. when "muli", "mulp"
  656. emitMIPS("mul", operands)
  657. when "subi", "subp", "subis"
  658. emitMIPSCompact("sub", "subs", operands)
  659. when "negi", "negp"
  660. $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
  661. when "noti"
  662. $asm.puts "nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
  663. when "loadi", "loadis", "loadp"
  664. $asm.puts "lw #{mipsFlippedOperands(operands)}"
  665. when "storei", "storep"
  666. $asm.puts "sw #{mipsOperands(operands)}"
  667. when "loadb"
  668. $asm.puts "lbu #{mipsFlippedOperands(operands)}"
  669. when "loadbs"
  670. $asm.puts "lb #{mipsFlippedOperands(operands)}"
  671. when "storeb"
  672. $asm.puts "sb #{mipsOperands(operands)}"
  673. when "loadh"
  674. $asm.puts "lhu #{mipsFlippedOperands(operands)}"
  675. when "loadhs"
  676. $asm.puts "lh #{mipsFlippedOperands(operands)}"
  677. when "storeh"
  678. $asm.puts "shv #{mipsOperands(operands)}"
  679. when "loadd"
  680. $asm.puts "ldc1 #{mipsFlippedOperands(operands)}"
  681. when "stored"
  682. $asm.puts "sdc1 #{mipsOperands(operands)}"
  683. when "addd"
  684. emitMIPS("add.d", operands)
  685. when "divd"
  686. emitMIPS("div.d", operands)
  687. when "subd"
  688. emitMIPS("sub.d", operands)
  689. when "muld"
  690. emitMIPS("mul.d", operands)
  691. when "sqrtd"
  692. $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}"
  693. when "ci2d"
  694. raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands[1].is_a? FPRegisterID and operands[0].register?
  695. $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  696. $asm.puts "cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
  697. when "bdeq"
  698. emitMIPSDoubleBranch("eq", false, operands)
  699. when "bdneq"
  700. emitMIPSDoubleBranch("ueq", true, operands)
  701. when "bdgt"
  702. emitMIPSDoubleBranch("ule", true, operands)
  703. when "bdgteq"
  704. emitMIPSDoubleBranch("ult", true, operands)
  705. when "bdlt"
  706. emitMIPSDoubleBranch("olt", false, operands)
  707. when "bdlteq"
  708. emitMIPSDoubleBranch("ole", false, operands)
  709. when "bdequn"
  710. emitMIPSDoubleBranch("ueq", false, operands)
  711. when "bdnequn"
  712. emitMIPSDoubleBranch("eq", true, operands)
  713. when "bdgtun"
  714. emitMIPSDoubleBranch("ole", true, operands)
  715. when "bdgtequn"
  716. emitMIPSDoubleBranch("olt", true, operands)
  717. when "bdltun"
  718. emitMIPSDoubleBranch("ult", false, operands)
  719. when "bdltequn"
  720. emitMIPSDoubleBranch("ule", false, operands)
  721. when "btd2i"
  722. # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
  723. # currently does not use it.
  724. raise "MIPS does not support this opcode yet, #{codeOrigin}"
  725. when "td2i"
  726. $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
  727. $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
  728. when "bcd2i"
  729. $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
  730. $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
  731. $asm.puts "cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
  732. emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR, operands[0], operands[2]])
  733. $asm.puts "beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
  734. when "movdz"
  735. # FIXME: either support this or remove it.
  736. raise "MIPS does not support this opcode yet, #{codeOrigin}"
  737. when "pop"
  738. $asm.puts "lw #{operands[0].mipsOperand}, 0($sp)"
  739. $asm.puts "addiu $sp, $sp, 4"
  740. when "push"
  741. $asm.puts "addiu $sp, $sp, -4"
  742. $asm.puts "sw #{operands[0].mipsOperand}, 0($sp)"
  743. when "move", "sxi2p", "zxi2p"
  744. if operands[0].is_a? Immediate
  745. mipsMoveImmediate(operands[0].value, operands[1])
  746. else
  747. $asm.puts "move #{mipsFlippedOperands(operands)}"
  748. end
  749. when "nop"
  750. $asm.puts "nop"
  751. when "bieq", "bpeq", "bbeq"
  752. $asm.puts "beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  753. when "bineq", "bpneq", "bbneq"
  754. $asm.puts "bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  755. when "bigt", "bpgt", "bbgt"
  756. $asm.puts "bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  757. when "bigteq", "bpgteq", "bbgteq"
  758. $asm.puts "bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  759. when "bilt", "bplt", "bblt"
  760. $asm.puts "blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  761. when "bilteq", "bplteq", "bblteq"
  762. $asm.puts "ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
  763. when "jmp"
  764. if operands[0].label?
  765. $asm.puts "j #{operands[0].asmLabel}"
  766. else
  767. $asm.puts "jr #{operands[0].mipsOperand}"
  768. end
  769. when "call"
  770. if operands[0].label?
  771. $asm.puts "jal #{operands[0].asmLabel}"
  772. else
  773. $asm.puts "jalr #{operands[0].mipsOperand}"
  774. end
  775. when "break"
  776. $asm.puts "break"
  777. when "ret"
  778. $asm.puts "jr $ra"
  779. when "cia", "cpa", "cba"
  780. $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  781. when "ciaeq", "cpaeq", "cbaeq"
  782. $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  783. $asm.puts "xori #{operands[2].mipsOperand}, 1"
  784. when "cib", "cpb", "cbb"
  785. $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  786. when "cibeq", "cpbeq", "cbbeq"
  787. $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  788. $asm.puts "xori #{operands[2].mipsOperand}, 1"
  789. when "cigt", "cpgt", "cbgt"
  790. $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  791. when "cigteq", "cpgteq", "cbgteq"
  792. $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  793. $asm.puts "xori #{operands[2].mipsOperand}, 1"
  794. when "cilt", "cplt", "cblt"
  795. $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  796. when "cilteq", "cplteq", "cblteq"
  797. $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
  798. $asm.puts "xori #{operands[2].mipsOperand}, 1"
  799. when "peek"
  800. $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
  801. when "poke"
  802. $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
  803. when "fii2d"
  804. $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
  805. $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
  806. when "fd2ii"
  807. $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
  808. $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
  809. when /^bo/
  810. $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
  811. when /^bs/
  812. $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
  813. when /^bz/
  814. $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
  815. when /^bnz/
  816. $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
  817. when "leai", "leap"
  818. operands[0].mipsEmitLea(operands[1])
  819. when "smulli"
  820. raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
  821. $asm.puts "mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
  822. $asm.puts "mflo #{operands[2].mipsOperand}"
  823. $asm.puts "mfhi #{operands[3].mipsOperand}"
  824. when "movz"
  825. $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
  826. when "movn"
  827. $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
  828. when "slt", "sltb"
  829. $asm.puts "slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
  830. when "sltu", "sltub"
  831. $asm.puts "sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
  832. when "pichdr"
  833. $asm.putStr("OFFLINE_ASM_CPLOAD($25)")
  834. $asm.puts "move $s4, $gp"
  835. when "pichdrra"
  836. $asm.putStr("OFFLINE_ASM_CPLOAD($31)")
  837. $asm.puts "move $s4, $gp"
  838. else
  839. raise "Unhandled opcode #{opcode} at #{codeOriginString}"
  840. end
  841. end
  842. end