]>
git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/risc.rb
1 # Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
28 # This file contains utilities that are useful for implementing a backend
29 # for RISC-like processors (ARM, MIPS, etc).
32 # Lowering of simple branch ops. For example:
34 # baddiz foo, bar, baz
42 def riscLowerSimpleBranchOps(list
)
46 if node
.is_a
? Instruction
47 annotation
= node
.annotation
49 when /^b(addi|subi|ori|addp)/
51 branch
= "b" + $~
.post_match
64 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..-2], annotation
)
65 newList
<< Instruction
.new(node
.codeOrigin
, branch
, [node
.operands
[-1]])
66 when 'bmulis', 'bmulz', 'bmulnz'
67 condition
= $~
.post_match
68 newList
<< Instruction
.new(node
.codeOrigin
, "muli", node
.operands
[0..-2], annotation
)
69 newList
<< Instruction
.new(node
.codeOrigin
, "bti" + condition
, [node
.operands
[-2], node
.operands
[-1]])
81 # Lowing of complex branch ops. For example:
83 # bmulio foo, bar, baz
87 # smulli foo, bar, bar, tmp1
88 # rshifti bar, 31, tmp2
89 # bineq tmp1, tmp2, baz
92 def riscLowerHardBranchOps(list
)
96 if node
.is_a
? Instruction
and node
.opcode
== "bmulio"
97 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
98 tmp2
= Tmp
.new(node
.codeOrigin
, :gpr)
99 newList
<< Instruction
.new(node
.codeOrigin
, "smulli", [node
.operands
[0], node
.operands
[1], node
.operands
[1], tmp1
], node
.annotation
)
100 newList
<< Instruction
.new(node
.codeOrigin
, "rshifti", [node
.operands
[-2], Immediate
.new(node
.codeOrigin
, 31), tmp2
])
101 newList
<< Instruction
.new(node
.codeOrigin
, "bineq", [tmp1
, tmp2
, node
.operands
[-1]])
110 # Lowering of shift ops. For example:
120 def riscSanitizeShift(operand
, list
)
121 return operand
if operand
.immediate
?
123 tmp
= Tmp
.new(operand
.codeOrigin
, :gpr)
124 list
<< Instruction
.new(operand
.codeOrigin
, "andi", [operand
, Immediate
.new(operand
.codeOrigin
, 31), tmp
])
128 def riscLowerShiftOps(list
)
132 if node
.is_a
? Instruction
134 when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
135 if node
.operands
.size
== 2
136 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [riscSanitizeShift(node
.operands
[0], newList
), node
.operands
[1]], node
.annotation
)
138 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [node
.operands
[0], riscSanitizeShift(node
.operands
[1], newList
), node
.operands
[2]], node
.annotation
)
139 raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node
.operands
.size
== 3
152 # Lowering of malformed addresses. For example:
154 # loadp 10000[foo], bar
162 # Note that you use this lowering phase by passing it a block that returns true
163 # if you don't want to lower the address, or false if you do. For example to get
164 # the effect of the example above, the block would have to say something like:
166 # riscLowerMalformedAddresses(thingy) {
168 # if address.is_a? Address
169 # address.offset.value > 1000
171 # true # don't lower anything else, in this example
175 # See arm.rb for a different example, in which we lower all BaseIndex addresses
176 # that have non-zero offset, all Address addresses that have large offsets, and
177 # all other addresses (like AbsoluteAddress).
181 def riscLowerMalformedAddressesRecurse(list
, topLevelNode
, &block
)
184 subNode
.riscLowerMalformedAddressesRecurse(list
, topLevelNode
, &block
)
190 def riscLowerMalformedAddressesRecurse(list
, node
, &block
)
191 return self if yield node
, self
193 tmp
= Tmp
.new(codeOrigin
, :gpr)
194 list
<< Instruction
.new(codeOrigin
, "move", [offset
, tmp
])
195 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp
])
196 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
201 def riscLowerMalformedAddressesRecurse(list
, node
, &block
)
202 return self if yield node
, self
204 tmp
= Tmp
.new(codeOrigin
, :gpr)
205 list
<< Instruction
.new(codeOrigin
, "leap", [BaseIndex
.new(codeOrigin
, base
, index
, scale
, Immediate
.new(codeOrigin
, 0)), tmp
])
206 Address
.new(codeOrigin
, tmp
, offset
).riscLowerMalformedAddressesRecurse(list
, node
, &block
)
210 class AbsoluteAddress
211 def riscLowerMalformedAddressesRecurse(list
, node
, &block
)
212 return self if yield node
, self
214 tmp
= Tmp
.new(codeOrigin
, :gpr)
215 list
<< Instruction
.new(codeOrigin
, "move", [address
, tmp
])
216 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
220 def riscLowerMalformedAddresses(list
, &block
)
224 newList
<< node
.riscLowerMalformedAddressesRecurse(newList
, node
, &block
)
230 # Lowering of malformed addresses in double loads and stores. For example:
232 # loadd [foo, bar, 8], baz
236 # leap [foo, bar, 8], tmp
241 def riscDoubleAddress(list
)
247 def riscDoubleAddress(list
)
248 tmp
= Tmp
.new(codeOrigin
, :gpr)
249 list
<< Instruction
.new(codeOrigin
, "leap", [self, tmp
])
250 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
254 def riscLowerMalformedAddressesDouble(list
)
258 if node
.is_a
? Instruction
261 newList
<< Instruction
.new(node
.codeOrigin
, "loadd", [node
.operands
[0].riscDoubleAddress(newList
), node
.operands
[1]], node
.annotation
)
263 newList
<< Instruction
.new(node
.codeOrigin
, "stored", [node
.operands
[0], node
.operands
[1].riscDoubleAddress(newList
)], node
.annotation
)
275 # Lowering of misplaced immediates for opcodes in opcodeList. For example, if storei is in opcodeList:
285 def riscLowerMisplacedImmediates(list
, opcodeList
)
289 if node
.is_a
? Instruction
290 if opcodeList
.include? node
.opcode
291 operands
= node
.operands
295 if operand
.is_a
? Immediate
296 tmp
= Tmp
.new(operand
.codeOrigin
, :gpr)
297 newList
<< Instruction
.new(operand
.codeOrigin
, "move", [operand
, tmp
])
300 newOperands
<< operand
303 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, newOperands
, node
.annotation
)
315 # Lowering of malformed immediates except when used in a "move" instruction.
327 def riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
330 node
.riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
336 def riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
342 def riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
347 class AbsoluteAddress
348 def riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
354 def riscLowerMalformedImmediatesRecurse(list
, validImmediates
)
355 unless validImmediates
.include? value
356 tmp
= Tmp
.new(codeOrigin
, :gpr)
357 list
<< Instruction
.new(codeOrigin
, "move", [self, tmp
])
365 def riscLowerMalformedImmediates(list
, validImmediates
)
369 if node
.is_a
? Instruction
370 annotation
= node
.annotation
374 when "addi", "addp", "addq", "addis", "subi", "subp", "subq", "subis"
375 if node
.operands
[0].is_a
? Immediate
and
376 (not validImmediates
.include? node
.operands
[0].value
) and
377 validImmediates
.include? -node
.operands
[0].value
378 node
.operands
.size
== 2
379 if node
.opcode
=~
/add/
380 newOpcode
= "sub" + $~
.post_match
382 newOpcode
= "add" + $~
.post_match
384 newList
<< Instruction
.new(node
.codeOrigin
, newOpcode
,
385 [Immediate
.new(node
.codeOrigin
, -node
.operands
[0].value
)] + node
.operands
[1..-1],
388 newList
<< node
.riscLowerMalformedImmediatesRecurse(newList
, validImmediates
)
390 when "muli", "mulp", "mulq"
391 if node
.operands
[0].is_a
? Immediate
392 tmp
= Tmp
.new(codeOrigin
, :gpr)
393 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
], annotation
)
394 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
] + node
.operands
[1..-1])
396 newList
<< node
.riscLowerMalformedImmediatesRecurse(newList
, validImmediates
)
399 newList
<< node
.riscLowerMalformedImmediatesRecurse(newList
, validImmediates
)
409 # Lowering of misplaced addresses. For example:
429 def riscAsRegister(preList
, postList
, operand
, suffix
, needStore
)
430 return operand
unless operand
.address
?
432 tmp
= Tmp
.new(operand
.codeOrigin
, if suffix
== "d" then :fpr else :gpr end)
433 preList
<< Instruction
.new(operand
.codeOrigin
, "load" + suffix
, [operand
, tmp
])
435 postList
<< Instruction
.new(operand
.codeOrigin
, "store" + suffix
, [tmp
, operand
])
440 def riscAsRegisters(preList
, postList
, operands
, suffix
)
442 operands
.each_with_index
{
444 newOperands
<< riscAsRegister(preList
, postList
, operand
, suffix
, index
== operands
.size
- 1)
449 def riscLowerMisplacedAddresses(list
)
453 if node
.is_a
? Instruction
454 postInstructions
= []
455 annotation
= node
.annotation
457 when "addi", "addis", "andi", "lshifti", "muli", "negi", "noti", "ori", "oris",
458 "rshifti", "urshifti", "subi", "subis", "xori", /^bi/, /^bti/, /^ci/, /^ti/
459 newList
<< Instruction
.new(node
.codeOrigin
,
461 riscAsRegisters(newList
, postInstructions
, node
.operands
, "i"),
463 when "addp", "andp", "lshiftp", "mulp", "negp", "orp", "rshiftp", "urshiftp",
464 "subp", "xorp", /^bp/, /^btp/, /^cp/
465 newList
<< Instruction
.new(node
.codeOrigin
,
467 riscAsRegisters(newList
, postInstructions
, node
.operands
, "p"),
469 when "addq", "andq", "lshiftq", "mulq", "negq", "orq", "rshiftq", "urshiftq",
470 "subq", "xorq", /^bq/, /^btq/, /^cq/
471 newList
<< Instruction
.new(node
.codeOrigin
,
473 riscAsRegisters(newList
, postInstructions
, node
.operands
, "q"),
475 when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbz", "btbnz", "tbz", "tbnz",
476 "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
477 newList
<< Instruction
.new(node
.codeOrigin
,
479 riscAsRegisters(newList
, postInstructions
, node
.operands
, "b"),
481 when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
482 newList
<< Instruction
.new(node
.codeOrigin
,
484 riscAsRegisters(newList
, postInstructions
, node
.operands
, "bs"),
486 when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
487 newList
<< Instruction
.new(node
.codeOrigin
,
489 riscAsRegisters(newList
, postInstructions
, node
.operands
, "d"),
492 newList
<< Instruction
.new(node
.codeOrigin
,
494 [riscAsRegister(newList
, postInstructions
, node
.operands
[0], "p", false)],
499 newList +
= postInstructions
508 # Lowering of register reuse in compare instructions. For example:
518 def riscLowerRegisterReuse(list
)
522 if node
.is_a
? Instruction
523 annotation
= node
.annotation
525 when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
526 "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
527 "tis", "tiz", "tinz", "tbs", "tbz", "tbnz", "tps", "tpz", "tpnz", "cbeq", "cbneq",
528 "cba", "cbaeq", "cbb", "cbbeq", "cbgt", "cbgteq", "cblt", "cblteq"
529 if node
.operands
.size
== 2
530 if node
.operands
[0] == node
.operands
[1]
531 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
532 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
], annotation
)
533 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
, node
.operands
[1]])
538 raise "Wrong number of arguments at #{node.codeOriginString}" unless node
.operands
.size
== 3
539 if node
.operands
[0] == node
.operands
[2]
540 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
541 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
], annotation
)
542 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
, node
.operands
[1], node
.operands
[2]])
543 elsif node
.operands
[1] == node
.operands
[2]
544 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
545 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[1], tmp
], annotation
)
546 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [node
.operands
[0], tmp
, node
.operands
[2]])
562 # Lowering of the not instruction. The following:
571 def riscLowerNot(list
)
575 if node
.is_a
? Instruction
578 raise "Wrong nubmer of operands at #{node.codeOriginString}" unless node
.operands
.size
== 1
579 suffix
= node
.opcode
[-1..-1]
580 newList
<< Instruction
.new(node
.codeOrigin
, "xor" + suffix
,
581 [Immediate
.new(node
.codeOrigin
, -1), node
.operands
[0]])
593 # Lowing of complex branch ops on 64-bit. For example:
595 # bmulio foo, bar, baz
599 # smulli foo, bar, bar
600 # rshiftp bar, 32, tmp1
601 # rshifti bar, 31, tmp2
603 # bineq tmp1, tmp2, baz
606 def riscLowerHardBranchOps64(list
)
610 if node
.is_a
? Instruction
and node
.opcode
== "bmulio"
611 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
612 tmp2
= Tmp
.new(node
.codeOrigin
, :gpr)
613 newList
<< Instruction
.new(node
.codeOrigin
, "smulli", [node
.operands
[0], node
.operands
[1], node
.operands
[1]])
614 newList
<< Instruction
.new(node
.codeOrigin
, "rshiftp", [node
.operands
[1], Immediate
.new(node
.codeOrigin
, 32), tmp1
])
615 newList
<< Instruction
.new(node
.codeOrigin
, "rshifti", [node
.operands
[1], Immediate
.new(node
.codeOrigin
, 31), tmp2
])
616 newList
<< Instruction
.new(node
.codeOrigin
, "zxi2p", [node
.operands
[1], node
.operands
[1]])
617 newList
<< Instruction
.new(node
.codeOrigin
, "bineq", [tmp1
, tmp2
, node
.operands
[2]])
626 # Lowering of test instructions. For example:
635 # and another example:
645 def riscLowerTest(list
)
646 def emit(newList
, andOpcode
, branchOpcode
, node
)
647 if node
.operands
.size
== 2
648 newList
<< Instruction
.new(node
.codeOrigin
, branchOpcode
, [node
.operands
[0], Immediate
.new(node
.codeOrigin
, 0), node
.operands
[1]])
652 raise "Incorrect number of operands at #{codeOriginString}" unless node
.operands
.size
== 3
654 if node
.operands
[0].immediate
? and node
.operands
[0].value
== -1
655 newList
<< Instruction
.new(node
.codeOrigin
, branchOpcode
, [node
.operands
[1], Immediate
.new(node
.codeOrigin
, 0), node
.operands
[2]])
659 if node
.operands
[1].immediate
? and node
.operands
[1].value
== -1
660 newList
<< Instruction
.new(node
.codeOrigin
, branchOpcode
, [node
.operands
[0], Immediate
.new(node
.codeOrigin
, 0), node
.operands
[2]])
664 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
665 newList
<< Instruction
.new(node
.codeOrigin
, andOpcode
, [node
.operands
[0], node
.operands
[1], tmp
])
666 newList
<< Instruction
.new(node
.codeOrigin
, branchOpcode
, [tmp
, Immediate
.new(node
.codeOrigin
, 0), node
.operands
[2]])
672 if node
.is_a
? Instruction
675 emit(newList
, "andi", "bilt", node
)
677 emit(newList
, "andi", "bieq", node
)
679 emit(newList
, "andi", "bineq", node
)
681 emit(newList
, "andp", "bplt", node
)
683 emit(newList
, "andp", "bpeq", node
)
685 emit(newList
, "andp", "bpneq", node
)
687 emit(newList
, "andq", "bqlt", node
)
689 emit(newList
, "andq", "bqeq", node
)
691 emit(newList
, "andq", "bqneq", node
)
693 emit(newList
, "andi", "bblt", node
)
695 emit(newList
, "andi", "bbeq", node
)
697 emit(newList
, "andi", "bbneq", node
)
699 emit(newList
, "andi", "cilt", node
)
701 emit(newList
, "andi", "cieq", node
)
703 emit(newList
, "andi", "cineq", node
)
705 emit(newList
, "andp", "cplt", node
)
707 emit(newList
, "andp", "cpeq", node
)
709 emit(newList
, "andp", "cpneq", node
)
711 emit(newList
, "andq", "cqlt", node
)
713 emit(newList
, "andq", "cqeq", node
)
715 emit(newList
, "andq", "cqneq", node
)
717 emit(newList
, "andi", "cblt", node
)
719 emit(newList
, "andi", "cbeq", node
)
721 emit(newList
, "andi", "cbneq", node
)