]>
git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/armv7.rb
1 # Copyright (C) 2011 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.
29 doubleOperand
= armV7Operand
30 raise "Bogus register name #{doubleOperand}" unless doubleOperand
=~
/^d/
31 "s" +
($~
.post_match
.to_i
* 2).to_s
35 class SpecialRegister
< NoChildren
41 ARMv7_EXTRA_GPRS
= [SpecialRegister
.new("r9"), SpecialRegister
.new("r8"), SpecialRegister
.new("r3")]
42 ARMv7_EXTRA_FPRS
= [SpecialRegister
.new("d7")]
43 ARMv7_SCRATCH_FPR
= SpecialRegister
.new("d8")
45 def armV7MoveImmediate(value
, register
)
46 # Currently we only handle the simple cases, and fall back to mov/movt for the complex ones.
47 if value
>= 0 && value
< 256
48 $asm.puts
"movw #{register.armV7Operand}, \##{value}"
49 elsif (~value
) >= 0 && (~value
) < 256
50 $asm.puts
"mvn #{register.armV7Operand}, \##{~value}"
52 $asm.puts
"movw #{register.armV7Operand}, \##{value & 0xffff}"
53 if (value
& 0xffff0000) !
= 0
54 $asm.puts
"movt #{register.armV7Operand}, \##{value >> 16}"
81 raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
102 raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
109 raise "Invalid immediate #{value} at #{codeOriginString}" if value
< 0 or value
> 255
116 raise "Bad offset at #{codeOriginString}" if offset
.value
< -0xff or offset
.value
> 0xfff
117 "[#{base.armV7Operand}, \##{offset.value}]"
123 raise "Bad offset at #{codeOriginString}" if offset
.value !
= 0
124 "[#{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}]"
128 class AbsoluteAddress
130 raise "Unconverted absolute address at #{codeOriginString}"
135 # Lowering of branch ops. For example:
137 # baddiz foo, bar, baz
145 def armV7LowerBranchOps(list
)
149 if node
.is_a
? Instruction
151 when /^b(addi|subi|ori|addp)/
153 branch
= "b" + $~
.post_match
164 newList
<< Instruction
.new(node
.codeOrigin
, op
, node
.operands
[0..-2])
165 newList
<< Instruction
.new(node
.codeOrigin
, branch
, [node
.operands
[-1]])
167 tmp1
= Tmp
.new(node
.codeOrigin
, :gpr)
168 tmp2
= Tmp
.new(node
.codeOrigin
, :gpr)
169 newList
<< Instruction
.new(node
.codeOrigin
, "smulli", [node
.operands
[0], node
.operands
[1], node
.operands
[1], tmp1
])
170 newList
<< Instruction
.new(node
.codeOrigin
, "rshifti", [node
.operands
[-2], Immediate
.new(node
.codeOrigin
, 31), tmp2
])
171 newList
<< Instruction
.new(node
.codeOrigin
, "bineq", [tmp1
, tmp2
, node
.operands
[-1]])
173 condition
= $~
.post_match
174 newList
<< Instruction
.new(node
.codeOrigin
, "muli", node
.operands
[0..-2])
175 newList
<< Instruction
.new(node
.codeOrigin
, "bti" + condition
, [node
.operands
[-2], node
.operands
[-1]])
187 # Lowering of shift ops. For example:
197 def armV7SanitizeShift(operand
, list
)
198 return operand
if operand
.immediate
?
200 tmp
= Tmp
.new(operand
.codeOrigin
, :gpr)
201 list
<< Instruction
.new(operand
.codeOrigin
, "andi", [operand
, Immediate
.new(operand
.codeOrigin
, 31), tmp
])
205 def armV7LowerShiftOps(list
)
209 if node
.is_a
? Instruction
211 when "lshifti", "rshifti", "urshifti", "lshiftp", "rshiftp", "urshiftp"
212 if node
.operands
.size
== 2
213 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [armV7SanitizeShift(node
.operands
[0], newList
), node
.operands
[1]])
215 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [node
.operands
[0], armV7SanitizeShift(node
.operands
[1], newList
), node
.operands
[2]])
216 raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node
.operands
.size
== 3
229 # Lowering of malformed addresses. For example:
231 # loadp 10000[foo], bar
241 def armV7LowerMalformedAddressesRecurse(list
)
244 node
.armV7LowerMalformedAddressesRecurse(list
)
250 def armV7LowerMalformedAddressesRecurse(list
)
251 if offset
.value
< -0xff or offset
.value
> 0xfff
252 tmp
= Tmp
.new(codeOrigin
, :gpr)
253 list
<< Instruction
.new(codeOrigin
, "move", [offset
, tmp
])
254 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp
])
255 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
263 def armV7LowerMalformedAddressesRecurse(list
)
265 tmp
= Tmp
.new(codeOrigin
, :gpr)
266 list
<< Instruction
.new(codeOrigin
, "move", [offset
, tmp
])
267 list
<< Instruction
.new(codeOrigin
, "addp", [base
, tmp
])
268 BaseIndex
.new(codeOrigin
, tmp
, index
, scale
, Immediate
.new(codeOrigin
, 0))
275 class AbsoluteAddress
276 def armV7LowerMalformedAddressesRecurse(list
)
277 tmp
= Tmp
.new(codeOrigin
, :gpr)
278 list
<< Instruction
.new(codeOrigin
, "move", [address
, tmp
])
279 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
283 def armV7LowerMalformedAddresses(list
)
287 newList
<< node
.armV7LowerMalformedAddressesRecurse(newList
)
293 # Lowering of malformed addresses in double loads and stores. For example:
295 # loadd [foo, bar, 8], baz
299 # leap [foo, bar, 8], tmp
304 def armV7DoubleAddress(list
)
310 def armV7DoubleAddress(list
)
311 tmp
= Tmp
.new(codeOrigin
, :gpr)
312 list
<< Instruction
.new(codeOrigin
, "leap", [self, tmp
])
313 Address
.new(codeOrigin
, tmp
, Immediate
.new(codeOrigin
, 0))
317 def armV7LowerMalformedAddressesDouble(list
)
321 if node
.is_a
? Instruction
324 newList
<< Instruction
.new(node
.codeOrigin
, "loadd", [node
.operands
[0].armV7DoubleAddress(newList
), node
.operands
[1]])
326 newList
<< Instruction
.new(node
.codeOrigin
, "stored", [node
.operands
[0], node
.operands
[1].armV7DoubleAddress(newList
)])
338 # Lowering of misplaced immediates. For example:
348 def armV7LowerMisplacedImmediates(list
)
352 if node
.is_a
? Instruction
354 when "storei", "storep"
355 operands
= node
.operands
359 if operand
.is_a
? Immediate
360 tmp
= Tmp
.new(operand
.codeOrigin
, :gpr)
361 newList
<< Instruction
.new(operand
.codeOrigin
, "move", [operand
, tmp
])
364 newOperands
<< operand
367 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, newOperands
)
379 # Lowering of malformed immediates except when used in a "move" instruction.
391 def armV7LowerMalformedImmediatesRecurse(list
)
394 node
.armV7LowerMalformedImmediatesRecurse(list
)
400 def armV7LowerMalformedImmediatesRecurse(list
)
406 def armV7LowerMalformedImmediatesRecurse(list
)
411 class AbsoluteAddress
412 def armV7LowerMalformedImmediatesRecurse(list
)
418 def armV7LowerMalformedImmediatesRecurse(list
)
419 if value
< 0 or value
> 255
420 tmp
= Tmp
.new(codeOrigin
, :gpr)
421 list
<< Instruction
.new(codeOrigin
, "move", [self, tmp
])
429 def armV7LowerMalformedImmediates(list
)
433 if node
.is_a
? Instruction
437 when "addi", "addp", "addis", "subi", "subp", "subis"
438 if node
.operands
[0].is_a
? Immediate
and
439 node
.operands
[0].value
< 0 and
440 node
.operands
[0].value
>= 255 and
441 node
.operands
.size
== 2
442 if node
.opcode
=~
/add/
443 newOpcode
= "sub" + node
.opcode
[-1..-1]
445 newOpcode
= "add" + node
.opcode
[-1..-1]
447 newList
<< Instruction
.new(node
.codeOrigin
, newOpcode
,
448 [Immediate
.new(-node
.operands
[0].value
)] + node
.operands
[1..-1])
450 newList
<< node
.armV7LowerMalformedImmediatesRecurse(newList
)
453 if node
.operands
[0].is_a
? Immediate
454 tmp
= Tmp
.new(codeOrigin
, :gpr)
455 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
])
456 newList
<< Instruction
.new(node
.codeOrigin
, "muli", [tmp
] + node
.operands
[1..-1])
458 newList
<< node
.armV7LowerMalformedImmediatesRecurse(newList
)
461 newList
<< node
.armV7LowerMalformedImmediatesRecurse(newList
)
471 # Lowering of misplaced addresses. For example:
491 def armV7AsRegister(preList
, postList
, operand
, suffix
, needStore
)
492 return operand
unless operand
.address
?
494 tmp
= Tmp
.new(operand
.codeOrigin
, if suffix
== "d" then :fpr else :gpr end)
495 preList
<< Instruction
.new(operand
.codeOrigin
, "load" + suffix
, [operand
, tmp
])
497 postList
<< Instruction
.new(operand
.codeOrigin
, "store" + suffix
, [tmp
, operand
])
502 def armV7AsRegisters(preList
, postList
, operands
, suffix
)
504 operands
.each_with_index
{
506 newOperands
<< armV7AsRegister(preList
, postList
, operand
, suffix
, index
== operands
.size
- 1)
511 def armV7LowerMisplacedAddresses(list
)
515 if node
.is_a
? Instruction
516 postInstructions
= []
518 when "addi", "addp", "addis", "andi", "andp", "lshifti", "lshiftp", "muli", "mulp", "negi",
519 "negp", "noti", "ori", "oris", "orp", "rshifti", "urshifti", "rshiftp", "urshiftp", "subi",
520 "subp", "subis", "xori", "xorp", /^bi/, /^bp/, /^bti/, /^btp/, /^ci/, /^cp/, /^ti/
521 newList
<< Instruction
.new(node
.codeOrigin
,
523 armV7AsRegisters(newList
, postInstructions
, node
.operands
, "i"))
524 when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbo", "btbz", "btbnz", "tbz", "tbnz",
525 "tbo", "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq"
526 newList
<< Instruction
.new(node
.codeOrigin
,
528 armV7AsRegisters(newList
, postInstructions
, node
.operands
, "b"))
529 when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs", "cbgt", "cbgteq", "cblt", "cblteq"
530 newList
<< Instruction
.new(node
.codeOrigin
,
532 armV7AsRegisters(newList
, postInstructions
, node
.operands
, "bs"))
533 when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
534 newList
<< Instruction
.new(node
.codeOrigin
,
536 armV7AsRegisters(newList
, postInstructions
, node
.operands
, "d"))
538 newList
<< Instruction
.new(node
.codeOrigin
,
540 [armV7AsRegister(newList
, postInstructions
, node
.operands
[0], "p", false)])
544 newList +
= postInstructions
553 # Lowering of register reuse in compare instructions. For example:
563 def armV7LowerRegisterReuse(list
)
567 if node
.is_a
? Instruction
569 when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
570 "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
571 "tio", "tis", "tiz", "tinz", "tbo", "tbs", "tbz", "tbnz", "tpo", "tps", "tpz", "tpnz",
572 "cbeq", "cbneq", "cba", "cbaeq", "cbb", "cbbeq", "cbgt", "cbgteq", "cblt", "cblteq"
573 if node
.operands
.size
== 2
574 if node
.operands
[0] == node
.operands
[1]
575 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
576 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
])
577 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
, node
.operands
[1]])
582 raise "Wrong number of arguments at #{node.codeOriginString}" unless node
.operands
.size
== 3
583 if node
.operands
[0] == node
.operands
[2]
584 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
585 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[0], tmp
])
586 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [tmp
, node
.operands
[1], node
.operands
[2]])
587 elsif node
.operands
[1] == node
.operands
[2]
588 tmp
= Tmp
.new(node
.codeOrigin
, :gpr)
589 newList
<< Instruction
.new(node
.codeOrigin
, "move", [node
.operands
[1], tmp
])
590 newList
<< Instruction
.new(node
.codeOrigin
, node
.opcode
, [node
.operands
[0], tmp
, node
.operands
[2]])
610 def armV7EmitLea(destination
)
611 if destination
== base
612 $asm.puts
"adds #{destination.armV7Operand}, \##{offset.value}"
614 $asm.puts
"adds #{destination.armV7Operand}, #{base.armV7Operand}, \##{offset.value}"
620 def armV7EmitLea(destination
)
621 raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset
.value
== 0
622 $asm.puts
"add.w #{destination.armV7Operand}, #{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}"
626 # FIXME: we could support AbsoluteAddress for lea, but we don't.
629 # Actual lowering code follows.
633 def getModifiedListARMv7
636 # Verify that we will only see instructions and labels.
639 unless node
.is_a
? Instruction
or
641 node
.is_a
? LocalLabel
or
643 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
647 myList
= armV7LowerBranchOps(myList
)
648 myList
= armV7LowerShiftOps(myList
)
649 myList
= armV7LowerMalformedAddresses(myList
)
650 myList
= armV7LowerMalformedAddressesDouble(myList
)
651 myList
= armV7LowerMisplacedImmediates(myList
)
652 myList
= armV7LowerMalformedImmediates(myList
)
653 myList
= armV7LowerMisplacedAddresses(myList
)
654 myList
= armV7LowerRegisterReuse(myList
)
655 myList
= assignRegistersToTemporaries(myList
, :gpr, ARMv7_EXTRA_GPRS
)
656 myList
= assignRegistersToTemporaries(myList
, :fpr, ARMv7_EXTRA_FPRS
)
662 def armV7Operands(operands
)
663 operands
.map
{|v
| v
.armV7Operand
}.join(", ")
666 def armV7FlippedOperands(operands
)
667 armV7Operands([operands
[-1]] + operands
[0..-2])
670 def emitArmV7Compact(opcode2
, opcode3
, operands
)
671 if operands
.size
== 3
672 $asm.puts
"#{opcode3} #{armV7FlippedOperands(operands)}"
674 raise unless operands
.size
== 2
675 raise unless operands
[1].is_a
? RegisterID
676 if operands
[0].is_a
? Immediate
677 $asm.puts
"#{opcode3} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
679 $asm.puts
"#{opcode2} #{armV7FlippedOperands(operands)}"
684 def emitArmV7(opcode
, operands
)
685 if operands
.size
== 3
686 $asm.puts
"#{opcode} #{armV7FlippedOperands(operands)}"
688 raise unless operands
.size
== 2
689 $asm.puts
"#{opcode} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
693 def emitArmV7DoubleBranch(branchOpcode
, operands
)
694 $asm.puts
"vcmpe.f64 #{armV7Operands(operands[0..1])}"
695 $asm.puts
"vmrs apsr_nzcv, fpscr"
696 $asm.puts
"#{branchOpcode} #{operands[2].asmLabel}"
699 def emitArmV7Test(operands
)
703 mask
= Immediate
.new(codeOrigin
, -1)
707 raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
710 if mask
.is_a
? Immediate
and mask
.value
== -1
711 $asm.puts
"tst #{value.armV7Operand}, #{value.armV7Operand}"
712 elsif mask
.is_a
? Immediate
713 $asm.puts
"tst.w #{value.armV7Operand}, #{mask.armV7Operand}"
715 $asm.puts
"tst #{value.armV7Operand}, #{mask.armV7Operand}"
719 def emitArmV7Compare(operands
, code
)
720 $asm.puts
"movs #{operands[2].armV7Operand}, \#0"
721 $asm.puts
"cmp #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
722 $asm.puts
"it #{code}"
723 $asm.puts
"mov#{code} #{operands[2].armV7Operand}, \#1"
726 def emitArmV7TestSet(operands
, code
)
727 $asm.puts
"movs #{operands[-1].armV7Operand}, \#0"
728 emitArmV7Test(operands
)
729 $asm.puts
"it #{code}"
730 $asm.puts
"mov#{code} #{operands[-1].armV7Operand}, \#1"
735 $asm.comment codeOriginString
737 when "addi", "addp", "addis"
743 if operands
.size
== 3 and operands
[0].is_a
? Immediate
744 raise unless operands
[1].is_a
? RegisterID
745 raise unless operands
[2].is_a
? RegisterID
746 if operands
[0].value
== 0 and suffix
.empty
?
747 unless operands
[1] == operands
[2]
748 $asm.puts
"mov #{operands[2].armV7Operand}, #{operands[1].armV7Operand}"
751 $asm.puts
"adds #{operands[2].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
753 elsif operands
.size
== 3 and operands
[0].is_a
? RegisterID
754 raise unless operands
[1].is_a
? RegisterID
755 raise unless operands
[2].is_a
? RegisterID
756 $asm.puts
"adds #{armV7FlippedOperands(operands)}"
758 if operands
[0].is_a
? Immediate
759 unless Immediate
.new(nil, 0) == operands
[0]
760 $asm.puts
"adds #{armV7FlippedOperands(operands)}"
763 $asm.puts
"add#{suffix} #{armV7FlippedOperands(operands)}"
767 emitArmV7Compact("ands", "and", operands
)
769 emitArmV7Compact("orrs", "orr", operands
)
771 emitArmV7Compact("orrs", "orrs", operands
)
773 emitArmV7Compact("eors", "eor", operands
)
774 when "lshifti", "lshiftp"
775 emitArmV7Compact("lsls", "lsls", operands
)
776 when "rshifti", "rshiftp"
777 emitArmV7Compact("asrs", "asrs", operands
)
778 when "urshifti", "urshiftp"
779 emitArmV7Compact("lsrs", "lsrs", operands
)
781 emitArmV7("mul", operands
)
782 when "subi", "subp", "subis"
783 emitArmV7Compact("subs", "subs", operands
)
785 $asm.puts
"rsbs #{operands[0].armV7Operand}, #{operands[0].armV7Operand}, \#0"
787 $asm.puts
"mvns #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
788 when "loadi", "loadis", "loadp"
789 $asm.puts
"ldr #{armV7FlippedOperands(operands)}"
790 when "storei", "storep"
791 $asm.puts
"str #{armV7Operands(operands)}"
793 $asm.puts
"ldrb #{armV7FlippedOperands(operands)}"
795 $asm.puts
"ldrsb.w #{armV7FlippedOperands(operands)}"
797 $asm.puts
"strb #{armV7Operands(operands)}"
799 $asm.puts
"ldrh #{armV7FlippedOperands(operands)}"
801 $asm.puts
"ldrsh.w #{armV7FlippedOperands(operands)}"
803 $asm.puts
"strh #{armV7Operands(operands)}"
805 $asm.puts
"vldr.64 #{armV7FlippedOperands(operands)}"
807 $asm.puts
"vstr.64 #{armV7Operands(operands)}"
809 emitArmV7("vadd.f64", operands
)
811 emitArmV7("vdiv.f64", operands
)
813 emitArmV7("vsub.f64", operands
)
815 emitArmV7("vmul.f64", operands
)
817 $asm.puts
"vsqrt.f64 #{armV7FlippedOperands(operands)}"
819 $asm.puts
"vmov #{operands[1].armV7Single}, #{operands[0].armV7Operand}"
820 $asm.puts
"vcvt.f64.s32 #{operands[1].armV7Operand}, #{operands[1].armV7Single}"
822 emitArmV7DoubleBranch("beq", operands
)
824 $asm.puts
"vcmpe.f64 #{armV7Operands(operands[0..1])}"
825 $asm.puts
"vmrs apsr_nzcv, fpscr"
826 isUnordered
= LocalLabel
.unique("bdneq")
827 $asm.puts
"bvs #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
828 $asm.puts
"bne #{operands[2].asmLabel}"
829 isUnordered
.lower("ARMv7")
831 emitArmV7DoubleBranch("bgt", operands
)
833 emitArmV7DoubleBranch("bge", operands
)
835 emitArmV7DoubleBranch("bmi", operands
)
837 emitArmV7DoubleBranch("bls", operands
)
839 $asm.puts
"vcmpe.f64 #{armV7Operands(operands[0..1])}"
840 $asm.puts
"vmrs apsr_nzcv, fpscr"
841 $asm.puts
"bvs #{operands[2].asmLabel}"
842 $asm.puts
"beq #{operands[2].asmLabel}"
844 emitArmV7DoubleBranch("bne", operands
)
846 emitArmV7DoubleBranch("bhi", operands
)
848 emitArmV7DoubleBranch("bpl", operands
)
850 emitArmV7DoubleBranch("blt", operands
)
852 emitArmV7DoubleBranch("ble", operands
)
854 # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
855 # currently does not use it.
856 raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
858 $asm.puts
"vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
859 $asm.puts
"vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
861 $asm.puts
"vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
862 $asm.puts
"vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
863 $asm.puts
"vcvt.f64.s32 #{ARMv7_SCRATCH_FPR.armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
864 emitArmV7DoubleBranch("bne", [ARMv7_SCRATCH_FPR
, operands
[0], operands
[2]])
865 $asm.puts
"tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
866 $asm.puts
"beq #{operands[2].asmLabel}"
868 # FIXME: either support this or remove it.
869 raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
871 $asm.puts
"pop #{operands[0].armV7Operand}"
873 $asm.puts
"push #{operands[0].armV7Operand}"
874 when "move", "sxi2p", "zxi2p"
875 if operands
[0].is_a
? Immediate
876 armV7MoveImmediate(operands
[0].value
, operands
[1])
878 $asm.puts
"mov #{armV7FlippedOperands(operands)}"
882 when "bieq", "bpeq", "bbeq"
883 if Immediate
.new(nil, 0) == operands
[0]
884 $asm.puts
"tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
885 elsif Immediate
.new(nil, 0) == operands
[1]
886 $asm.puts
"tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
888 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
890 $asm.puts
"beq #{operands[2].asmLabel}"
891 when "bineq", "bpneq", "bbneq"
892 if Immediate
.new(nil, 0) == operands
[0]
893 $asm.puts
"tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
894 elsif Immediate
.new(nil, 0) == operands
[1]
895 $asm.puts
"tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
897 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
899 $asm.puts
"bne #{operands[2].asmLabel}"
900 when "bia", "bpa", "bba"
901 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
902 $asm.puts
"bhi #{operands[2].asmLabel}"
903 when "biaeq", "bpaeq", "bbaeq"
904 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
905 $asm.puts
"bhs #{operands[2].asmLabel}"
906 when "bib", "bpb", "bbb"
907 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
908 $asm.puts
"blo #{operands[2].asmLabel}"
909 when "bibeq", "bpbeq", "bbbeq"
910 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
911 $asm.puts
"bls #{operands[2].asmLabel}"
912 when "bigt", "bpgt", "bbgt"
913 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
914 $asm.puts
"bgt #{operands[2].asmLabel}"
915 when "bigteq", "bpgteq", "bbgteq"
916 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
917 $asm.puts
"bge #{operands[2].asmLabel}"
918 when "bilt", "bplt", "bblt"
919 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
920 $asm.puts
"blt #{operands[2].asmLabel}"
921 when "bilteq", "bplteq", "bblteq"
922 $asm.puts
"cmp #{armV7Operands(operands[0..1])}"
923 $asm.puts
"ble #{operands[2].asmLabel}"
924 when "btiz", "btpz", "btbz"
925 emitArmV7Test(operands
)
926 $asm.puts
"beq #{operands[-1].asmLabel}"
927 when "btinz", "btpnz", "btbnz"
928 emitArmV7Test(operands
)
929 $asm.puts
"bne #{operands[-1].asmLabel}"
930 when "btio", "btpo", "btbo"
931 emitArmV7Test(operands
)
932 $asm.puts
"bvs #{operands[-1].asmLabel}"
933 when "btis", "btps", "btbs"
934 emitArmV7Test(operands
)
935 $asm.puts
"bmi #{operands[-1].asmLabel}"
937 if operands
[0].label
?
938 $asm.puts
"b #{operands[0].asmLabel}"
940 $asm.puts
"mov pc, #{operands[0].armV7Operand}"
943 if operands
[0].label
?
944 $asm.puts
"blx #{operands[0].asmLabel}"
946 $asm.puts
"blx #{operands[0].armV7Operand}"
952 when "cieq", "cpeq", "cbeq"
953 emitArmV7Compare(operands
, "eq")
954 when "cineq", "cpneq", "cbneq"
955 emitArmV7Compare(operands
, "ne")
956 when "cia", "cpa", "cba"
957 emitArmV7Compare(operands
, "hi")
958 when "ciaeq", "cpaeq", "cbaeq"
959 emitArmV7Compare(operands
, "hs")
960 when "cib", "cpb", "cbb"
961 emitArmV7Compare(operands
, "lo")
962 when "cibeq", "cpbeq", "cbbeq"
963 emitArmV7Compare(operands
, "ls")
964 when "cigt", "cpgt", "cbgt"
965 emitArmV7Compare(operands
, "gt")
966 when "cigteq", "cpgteq", "cbgteq"
967 emitArmV7Compare(operands
, "ge")
968 when "cilt", "cplt", "cblt"
969 emitArmV7Compare(operands
, "lt")
970 when "cilteq", "cplteq", "cblteq"
971 emitArmV7Compare(operands
, "le")
972 when "tio", "tbo", "tpo"
973 emitArmV7TestSet(operands
, "vs")
974 when "tis", "tbs", "tps"
975 emitArmV7TestSet(operands
, "mi")
976 when "tiz", "tbz", "tpz"
977 emitArmV7TestSet(operands
, "eq")
978 when "tinz", "tbnz", "tpnz"
979 emitArmV7TestSet(operands
, "ne")
981 $asm.puts
"ldr #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
983 $asm.puts
"str #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
985 $asm.puts
"vmov #{operands[2].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
987 $asm.puts
"vmov #{operands[1].armV7Operand}, #{operands[2].armV7Operand}, #{operands[0].armV7Operand}"
989 $asm.puts
"bvs #{operands[0].asmLabel}"
991 $asm.puts
"bmi #{operands[0].asmLabel}"
993 $asm.puts
"beq #{operands[0].asmLabel}"
995 $asm.puts
"bne #{operands[0].asmLabel}"
997 operands
[0].armV7EmitLea(operands
[1])
999 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands
.length
== 4
1000 $asm.puts
"smull #{operands[2].armV7Operand}, #{operands[3].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
1002 raise "Unhandled opcode #{opcode} at #{codeOriginString}"