]>
Commit | Line | Data |
---|---|---|
93a37866 A |
1 | # Copyright (C) 2011, 2012 Apple Inc. All rights reserved. |
2 | # Copyright (C) 2013 University of Szeged. 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 APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | |
14 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | |
15 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | |
17 | # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
18 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
19 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
20 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
21 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
22 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
23 | # THE POSSIBILITY OF SUCH DAMAGE. | |
24 | ||
25 | require "config" | |
26 | require "ast" | |
27 | require "opt" | |
28 | require "risc" | |
29 | ||
30 | def isARMv7 | |
31 | case $activeBackend | |
32 | when "ARMv7" | |
33 | true | |
34 | when "ARMv7_TRADITIONAL", "ARM" | |
35 | false | |
36 | else | |
37 | raise "bad value for $activeBackend: #{$activeBackend}" | |
38 | end | |
39 | end | |
40 | ||
41 | def isARMv7Traditional | |
42 | case $activeBackend | |
43 | when "ARMv7_TRADITIONAL" | |
44 | true | |
45 | when "ARMv7", "ARM" | |
46 | false | |
47 | else | |
48 | raise "bad value for $activeBackend: #{$activeBackend}" | |
49 | end | |
50 | end | |
51 | ||
52 | class Node | |
53 | def armSingle | |
54 | doubleOperand = armOperand | |
55 | raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^d/ | |
56 | "s" + ($~.post_match.to_i * 2).to_s | |
57 | end | |
58 | end | |
59 | ||
60 | class SpecialRegister | |
61 | def armOperand | |
62 | @name | |
63 | end | |
64 | end | |
65 | ||
66 | ARM_EXTRA_GPRS = [SpecialRegister.new("r9"), SpecialRegister.new("r8"), SpecialRegister.new("r3")] | |
67 | ARM_EXTRA_FPRS = [SpecialRegister.new("d7")] | |
68 | ARM_SCRATCH_FPR = SpecialRegister.new("d6") | |
69 | ||
70 | def armMoveImmediate(value, register) | |
71 | # Currently we only handle the simple cases, and fall back to mov/movt for the complex ones. | |
72 | if value >= 0 && value < 256 | |
73 | $asm.puts "mov #{register.armOperand}, \##{value}" | |
74 | elsif (~value) >= 0 && (~value) < 256 | |
75 | $asm.puts "mvn #{register.armOperand}, \##{~value}" | |
76 | elsif isARMv7 or isARMv7Traditional | |
77 | $asm.puts "movw #{register.armOperand}, \##{value & 0xffff}" | |
78 | if (value & 0xffff0000) != 0 | |
79 | $asm.puts "movt #{register.armOperand}, \##{(value >> 16) & 0xffff}" | |
80 | end | |
81 | else | |
82 | $asm.puts "ldr #{register.armOperand}, =#{value}" | |
83 | end | |
84 | end | |
85 | ||
86 | class RegisterID | |
87 | def armOperand | |
88 | case name | |
89 | when "t0", "a0", "r0" | |
90 | "r0" | |
91 | when "t1", "a1", "r1" | |
92 | "r1" | |
93 | when "t2", "a2" | |
94 | "r2" | |
95 | when "a3" | |
96 | "r3" | |
97 | when "t3" | |
98 | "r4" | |
99 | when "t4" | |
100 | "r10" | |
101 | when "cfr" | |
102 | "r5" | |
103 | when "lr" | |
104 | "lr" | |
105 | when "sp" | |
106 | "sp" | |
107 | else | |
108 | raise "Bad register #{name} for ARM at #{codeOriginString}" | |
109 | end | |
110 | end | |
111 | end | |
112 | ||
113 | class FPRegisterID | |
114 | def armOperand | |
115 | case name | |
116 | when "ft0", "fr" | |
117 | "d0" | |
118 | when "ft1" | |
119 | "d1" | |
120 | when "ft2" | |
121 | "d2" | |
122 | when "ft3" | |
123 | "d3" | |
124 | when "ft4" | |
125 | "d4" | |
126 | when "ft5" | |
127 | "d5" | |
128 | else | |
129 | raise "Bad register #{name} for ARM at #{codeOriginString}" | |
130 | end | |
131 | end | |
132 | end | |
133 | ||
134 | class Immediate | |
135 | def armOperand | |
136 | raise "Invalid immediate #{value} at #{codeOriginString}" if value < 0 or value > 255 | |
137 | "\##{value}" | |
138 | end | |
139 | end | |
140 | ||
141 | class Address | |
142 | def armOperand | |
143 | raise "Bad offset at #{codeOriginString}" if offset.value < -0xff or offset.value > 0xfff | |
144 | "[#{base.armOperand}, \##{offset.value}]" | |
145 | end | |
146 | end | |
147 | ||
148 | class BaseIndex | |
149 | def armOperand | |
150 | raise "Bad offset at #{codeOriginString}" if offset.value != 0 | |
151 | "[#{base.armOperand}, #{index.armOperand}, lsl \##{scaleShift}]" | |
152 | end | |
153 | end | |
154 | ||
155 | class AbsoluteAddress | |
156 | def armOperand | |
157 | raise "Unconverted absolute address at #{codeOriginString}" | |
158 | end | |
159 | end | |
160 | ||
161 | # | |
162 | # Lea support. | |
163 | # | |
164 | ||
165 | class Address | |
166 | def armEmitLea(destination) | |
167 | if destination == base | |
168 | $asm.puts "adds #{destination.armOperand}, \##{offset.value}" | |
169 | else | |
170 | $asm.puts "adds #{destination.armOperand}, #{base.armOperand}, \##{offset.value}" | |
171 | end | |
172 | end | |
173 | end | |
174 | ||
175 | class BaseIndex | |
176 | def armEmitLea(destination) | |
177 | raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0 | |
178 | $asm.puts "add #{destination.armOperand}, #{base.armOperand}, #{index.armOperand}, lsl \##{scaleShift}" | |
179 | end | |
180 | end | |
181 | ||
182 | # FIXME: we could support AbsoluteAddress for lea, but we don't. | |
183 | ||
184 | # | |
185 | # Actual lowering code follows. | |
186 | # | |
187 | ||
188 | class Sequence | |
189 | def getModifiedListARM | |
190 | raise unless $activeBackend == "ARM" | |
191 | getModifiedListARMCommon | |
192 | end | |
193 | ||
194 | def getModifiedListARMv7 | |
195 | raise unless $activeBackend == "ARMv7" | |
196 | getModifiedListARMCommon | |
197 | end | |
198 | ||
199 | def getModifiedListARMv7_TRADITIONAL | |
200 | raise unless $activeBackend == "ARMv7_TRADITIONAL" | |
201 | getModifiedListARMCommon | |
202 | end | |
203 | ||
204 | def getModifiedListARMCommon | |
205 | result = @list | |
206 | result = riscLowerSimpleBranchOps(result) | |
207 | result = riscLowerHardBranchOps(result) | |
208 | result = riscLowerShiftOps(result) | |
209 | result = riscLowerMalformedAddresses(result) { | |
210 | | node, address | | |
211 | if address.is_a? BaseIndex | |
212 | address.offset.value == 0 | |
213 | elsif address.is_a? Address | |
214 | (-0xff..0xfff).include? address.offset.value | |
215 | else | |
216 | false | |
217 | end | |
218 | } | |
219 | result = riscLowerMalformedAddressesDouble(result) | |
220 | result = riscLowerMisplacedImmediates(result, ["storeb", "storei", "storep", "storeq"]) | |
221 | result = riscLowerMalformedImmediates(result, 0..0xff) | |
222 | result = riscLowerMisplacedAddresses(result) | |
223 | result = riscLowerRegisterReuse(result) | |
224 | result = assignRegistersToTemporaries(result, :gpr, ARM_EXTRA_GPRS) | |
225 | result = assignRegistersToTemporaries(result, :fpr, ARM_EXTRA_FPRS) | |
226 | return result | |
227 | end | |
228 | end | |
229 | ||
230 | def armOperands(operands) | |
231 | operands.map{|v| v.armOperand}.join(", ") | |
232 | end | |
233 | ||
234 | def armFlippedOperands(operands) | |
235 | armOperands([operands[-1]] + operands[0..-2]) | |
236 | end | |
237 | ||
238 | def emitArmCompact(opcode2, opcode3, operands) | |
239 | if operands.size == 3 | |
240 | $asm.puts "#{opcode3} #{armFlippedOperands(operands)}" | |
241 | else | |
242 | raise unless operands.size == 2 | |
243 | raise unless operands[1].register? | |
244 | if operands[0].immediate? | |
245 | $asm.puts "#{opcode3} #{operands[1].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}" | |
246 | else | |
247 | $asm.puts "#{opcode2} #{armFlippedOperands(operands)}" | |
248 | end | |
249 | end | |
250 | end | |
251 | ||
252 | def emitArm(opcode, operands) | |
253 | if operands.size == 3 | |
254 | $asm.puts "#{opcode} #{armFlippedOperands(operands)}" | |
255 | else | |
256 | raise unless operands.size == 2 | |
257 | $asm.puts "#{opcode} #{operands[1].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}" | |
258 | end | |
259 | end | |
260 | ||
261 | def emitArmDoubleBranch(branchOpcode, operands) | |
262 | $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}" | |
263 | $asm.puts "vmrs apsr_nzcv, fpscr" | |
264 | $asm.puts "#{branchOpcode} #{operands[2].asmLabel}" | |
265 | end | |
266 | ||
267 | def emitArmTest(operands) | |
268 | value = operands[0] | |
269 | case operands.size | |
270 | when 2 | |
271 | mask = Immediate.new(codeOrigin, -1) | |
272 | when 3 | |
273 | mask = operands[1] | |
274 | else | |
275 | raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}" | |
276 | end | |
277 | ||
278 | if mask.immediate? and mask.value == -1 | |
279 | $asm.puts "tst #{value.armOperand}, #{value.armOperand}" | |
280 | else | |
281 | $asm.puts "tst #{value.armOperand}, #{mask.armOperand}" | |
282 | end | |
283 | end | |
284 | ||
285 | def emitArmCompare(operands, code) | |
286 | $asm.puts "movs #{operands[2].armOperand}, \#0" | |
287 | $asm.puts "cmp #{operands[0].armOperand}, #{operands[1].armOperand}" | |
288 | $asm.puts "it #{code}" | |
289 | $asm.puts "mov#{code} #{operands[2].armOperand}, \#1" | |
290 | end | |
291 | ||
292 | def emitArmTestSet(operands, code) | |
293 | $asm.puts "movs #{operands[-1].armOperand}, \#0" | |
294 | emitArmTest(operands) | |
295 | $asm.puts "it #{code}" | |
296 | $asm.puts "mov#{code} #{operands[-1].armOperand}, \#1" | |
297 | end | |
298 | ||
299 | class Instruction | |
300 | def lowerARM | |
301 | raise unless $activeBackend == "ARM" | |
302 | lowerARMCommon | |
303 | end | |
304 | ||
305 | def lowerARMv7 | |
306 | raise unless $activeBackend == "ARMv7" | |
307 | lowerARMCommon | |
308 | end | |
309 | ||
310 | def lowerARMv7_TRADITIONAL | |
311 | raise unless $activeBackend == "ARMv7_TRADITIONAL" | |
312 | lowerARMCommon | |
313 | end | |
314 | ||
315 | def lowerARMCommon | |
316 | $asm.codeOrigin codeOriginString if $enableCodeOriginComments | |
317 | $asm.annotation annotation if $enableInstrAnnotations | |
318 | ||
319 | case opcode | |
320 | when "addi", "addp", "addis", "addps" | |
321 | if opcode == "addis" or opcode == "addps" | |
322 | suffix = "s" | |
323 | else | |
324 | suffix = "" | |
325 | end | |
326 | if operands.size == 3 and operands[0].immediate? | |
327 | raise unless operands[1].register? | |
328 | raise unless operands[2].register? | |
329 | if operands[0].value == 0 and suffix.empty? | |
330 | unless operands[1] == operands[2] | |
331 | $asm.puts "mov #{operands[2].armOperand}, #{operands[1].armOperand}" | |
332 | end | |
333 | else | |
334 | $asm.puts "adds #{operands[2].armOperand}, #{operands[1].armOperand}, #{operands[0].armOperand}" | |
335 | end | |
336 | elsif operands.size == 3 and operands[0].immediate? | |
337 | raise unless operands[1].register? | |
338 | raise unless operands[2].register? | |
339 | $asm.puts "adds #{armFlippedOperands(operands)}" | |
340 | else | |
341 | if operands[0].immediate? | |
342 | unless Immediate.new(nil, 0) == operands[0] | |
343 | $asm.puts "adds #{armFlippedOperands(operands)}" | |
344 | end | |
345 | else | |
346 | $asm.puts "add#{suffix} #{armFlippedOperands(operands)}" | |
347 | end | |
348 | end | |
349 | when "andi", "andp" | |
350 | emitArmCompact("ands", "and", operands) | |
351 | when "ori", "orp" | |
352 | emitArmCompact("orrs", "orr", operands) | |
353 | when "oris" | |
354 | emitArmCompact("orrs", "orrs", operands) | |
355 | when "xori", "xorp" | |
356 | emitArmCompact("eors", "eor", operands) | |
357 | when "lshifti", "lshiftp" | |
358 | emitArmCompact("lsls", "lsls", operands) | |
359 | when "rshifti", "rshiftp" | |
360 | emitArmCompact("asrs", "asrs", operands) | |
361 | when "urshifti", "urshiftp" | |
362 | emitArmCompact("lsrs", "lsrs", operands) | |
363 | when "muli", "mulp" | |
364 | emitArm("mul", operands) | |
365 | when "subi", "subp", "subis" | |
366 | emitArmCompact("subs", "subs", operands) | |
367 | when "negi", "negp" | |
368 | $asm.puts "rsbs #{operands[0].armOperand}, #{operands[0].armOperand}, \#0" | |
369 | when "noti" | |
370 | $asm.puts "mvns #{operands[0].armOperand}, #{operands[0].armOperand}" | |
371 | when "loadi", "loadis", "loadp" | |
372 | $asm.puts "ldr #{armFlippedOperands(operands)}" | |
373 | when "storei", "storep" | |
374 | $asm.puts "str #{armOperands(operands)}" | |
375 | when "loadb" | |
376 | $asm.puts "ldrb #{armFlippedOperands(operands)}" | |
377 | when "loadbs" | |
378 | $asm.puts "ldrsb.w #{armFlippedOperands(operands)}" | |
379 | when "storeb" | |
380 | $asm.puts "strb #{armOperands(operands)}" | |
381 | when "loadh" | |
382 | $asm.puts "ldrh #{armFlippedOperands(operands)}" | |
383 | when "loadhs" | |
384 | $asm.puts "ldrsh.w #{armFlippedOperands(operands)}" | |
385 | when "storeh" | |
386 | $asm.puts "strh #{armOperands(operands)}" | |
387 | when "loadd" | |
388 | $asm.puts "vldr.64 #{armFlippedOperands(operands)}" | |
389 | when "stored" | |
390 | $asm.puts "vstr.64 #{armOperands(operands)}" | |
391 | when "addd" | |
392 | emitArm("vadd.f64", operands) | |
393 | when "divd" | |
394 | emitArm("vdiv.f64", operands) | |
395 | when "subd" | |
396 | emitArm("vsub.f64", operands) | |
397 | when "muld" | |
398 | emitArm("vmul.f64", operands) | |
399 | when "sqrtd" | |
400 | $asm.puts "vsqrt.f64 #{armFlippedOperands(operands)}" | |
401 | when "ci2d" | |
402 | $asm.puts "vmov #{operands[1].armSingle}, #{operands[0].armOperand}" | |
403 | $asm.puts "vcvt.f64.s32 #{operands[1].armOperand}, #{operands[1].armSingle}" | |
404 | when "bdeq" | |
405 | emitArmDoubleBranch("beq", operands) | |
406 | when "bdneq" | |
407 | $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}" | |
408 | $asm.puts "vmrs apsr_nzcv, fpscr" | |
409 | isUnordered = LocalLabel.unique("bdneq") | |
410 | $asm.puts "bvs #{LocalLabelReference.new(codeOrigin, isUnordered).asmLabel}" | |
411 | $asm.puts "bne #{operands[2].asmLabel}" | |
412 | isUnordered.lower("ARM") | |
413 | when "bdgt" | |
414 | emitArmDoubleBranch("bgt", operands) | |
415 | when "bdgteq" | |
416 | emitArmDoubleBranch("bge", operands) | |
417 | when "bdlt" | |
418 | emitArmDoubleBranch("bmi", operands) | |
419 | when "bdlteq" | |
420 | emitArmDoubleBranch("bls", operands) | |
421 | when "bdequn" | |
422 | $asm.puts "vcmpe.f64 #{armOperands(operands[0..1])}" | |
423 | $asm.puts "vmrs apsr_nzcv, fpscr" | |
424 | $asm.puts "bvs #{operands[2].asmLabel}" | |
425 | $asm.puts "beq #{operands[2].asmLabel}" | |
426 | when "bdnequn" | |
427 | emitArmDoubleBranch("bne", operands) | |
428 | when "bdgtun" | |
429 | emitArmDoubleBranch("bhi", operands) | |
430 | when "bdgtequn" | |
431 | emitArmDoubleBranch("bpl", operands) | |
432 | when "bdltun" | |
433 | emitArmDoubleBranch("blt", operands) | |
434 | when "bdltequn" | |
435 | emitArmDoubleBranch("ble", operands) | |
436 | when "btd2i" | |
437 | # FIXME: may be a good idea to just get rid of this instruction, since the interpreter | |
438 | # currently does not use it. | |
439 | raise "ARM does not support this opcode yet, #{codeOrigin}" | |
440 | when "td2i" | |
441 | $asm.puts "vcvt.s32.f64 #{ARM_SCRATCH_FPR.armSingle}, #{operands[0].armOperand}" | |
442 | $asm.puts "vmov #{operands[1].armOperand}, #{ARM_SCRATCH_FPR.armSingle}" | |
443 | when "bcd2i" | |
444 | $asm.puts "vcvt.s32.f64 #{ARM_SCRATCH_FPR.armSingle}, #{operands[0].armOperand}" | |
445 | $asm.puts "vmov #{operands[1].armOperand}, #{ARM_SCRATCH_FPR.armSingle}" | |
446 | $asm.puts "vcvt.f64.s32 #{ARM_SCRATCH_FPR.armOperand}, #{ARM_SCRATCH_FPR.armSingle}" | |
447 | emitArmDoubleBranch("bne", [ARM_SCRATCH_FPR, operands[0], operands[2]]) | |
448 | $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}" | |
449 | $asm.puts "beq #{operands[2].asmLabel}" | |
450 | when "movdz" | |
451 | # FIXME: either support this or remove it. | |
452 | raise "ARM does not support this opcode yet, #{codeOrigin}" | |
453 | when "pop" | |
454 | $asm.puts "pop #{operands[0].armOperand}" | |
455 | when "push" | |
456 | $asm.puts "push #{operands[0].armOperand}" | |
457 | when "move" | |
458 | if operands[0].immediate? | |
459 | armMoveImmediate(operands[0].value, operands[1]) | |
460 | else | |
461 | $asm.puts "mov #{armFlippedOperands(operands)}" | |
462 | end | |
463 | when "nop" | |
464 | $asm.puts "nop" | |
465 | when "bieq", "bpeq", "bbeq" | |
466 | if Immediate.new(nil, 0) == operands[0] | |
467 | $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}" | |
468 | elsif Immediate.new(nil, 0) == operands[1] | |
469 | $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}" | |
470 | else | |
471 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
472 | end | |
473 | $asm.puts "beq #{operands[2].asmLabel}" | |
474 | when "bineq", "bpneq", "bbneq" | |
475 | if Immediate.new(nil, 0) == operands[0] | |
476 | $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}" | |
477 | elsif Immediate.new(nil, 0) == operands[1] | |
478 | $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}" | |
479 | else | |
480 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
481 | end | |
482 | $asm.puts "bne #{operands[2].asmLabel}" | |
483 | when "bia", "bpa", "bba" | |
484 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
485 | $asm.puts "bhi #{operands[2].asmLabel}" | |
486 | when "biaeq", "bpaeq", "bbaeq" | |
487 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
488 | $asm.puts "bhs #{operands[2].asmLabel}" | |
489 | when "bib", "bpb", "bbb" | |
490 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
491 | $asm.puts "blo #{operands[2].asmLabel}" | |
492 | when "bibeq", "bpbeq", "bbbeq" | |
493 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
494 | $asm.puts "bls #{operands[2].asmLabel}" | |
495 | when "bigt", "bpgt", "bbgt" | |
496 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
497 | $asm.puts "bgt #{operands[2].asmLabel}" | |
498 | when "bigteq", "bpgteq", "bbgteq" | |
499 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
500 | $asm.puts "bge #{operands[2].asmLabel}" | |
501 | when "bilt", "bplt", "bblt" | |
502 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
503 | $asm.puts "blt #{operands[2].asmLabel}" | |
504 | when "bilteq", "bplteq", "bblteq" | |
505 | $asm.puts "cmp #{armOperands(operands[0..1])}" | |
506 | $asm.puts "ble #{operands[2].asmLabel}" | |
507 | when "btiz", "btpz", "btbz" | |
508 | emitArmTest(operands) | |
509 | $asm.puts "beq #{operands[-1].asmLabel}" | |
510 | when "btinz", "btpnz", "btbnz" | |
511 | emitArmTest(operands) | |
512 | $asm.puts "bne #{operands[-1].asmLabel}" | |
513 | when "btis", "btps", "btbs" | |
514 | emitArmTest(operands) | |
515 | $asm.puts "bmi #{operands[-1].asmLabel}" | |
516 | when "jmp" | |
517 | if operands[0].label? | |
518 | $asm.puts "b #{operands[0].asmLabel}" | |
519 | else | |
520 | $asm.puts "mov pc, #{operands[0].armOperand}" | |
521 | end | |
522 | if not isARMv7 and not isARMv7Traditional | |
523 | $asm.puts ".ltorg" | |
524 | end | |
525 | when "call" | |
526 | if operands[0].label? | |
527 | $asm.puts "blx #{operands[0].asmLabel}" | |
528 | else | |
529 | $asm.puts "blx #{operands[0].armOperand}" | |
530 | end | |
531 | when "break" | |
532 | $asm.puts "bkpt #0" | |
533 | when "ret" | |
534 | $asm.puts "bx lr" | |
535 | when "cieq", "cpeq", "cbeq" | |
536 | emitArmCompare(operands, "eq") | |
537 | when "cineq", "cpneq", "cbneq" | |
538 | emitArmCompare(operands, "ne") | |
539 | when "cia", "cpa", "cba" | |
540 | emitArmCompare(operands, "hi") | |
541 | when "ciaeq", "cpaeq", "cbaeq" | |
542 | emitArmCompare(operands, "hs") | |
543 | when "cib", "cpb", "cbb" | |
544 | emitArmCompare(operands, "lo") | |
545 | when "cibeq", "cpbeq", "cbbeq" | |
546 | emitArmCompare(operands, "ls") | |
547 | when "cigt", "cpgt", "cbgt" | |
548 | emitArmCompare(operands, "gt") | |
549 | when "cigteq", "cpgteq", "cbgteq" | |
550 | emitArmCompare(operands, "ge") | |
551 | when "cilt", "cplt", "cblt" | |
552 | emitArmCompare(operands, "lt") | |
553 | when "cilteq", "cplteq", "cblteq" | |
554 | emitArmCompare(operands, "le") | |
555 | when "tis", "tbs", "tps" | |
556 | emitArmTestSet(operands, "mi") | |
557 | when "tiz", "tbz", "tpz" | |
558 | emitArmTestSet(operands, "eq") | |
559 | when "tinz", "tbnz", "tpnz" | |
560 | emitArmTestSet(operands, "ne") | |
561 | when "peek" | |
562 | $asm.puts "ldr #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]" | |
563 | when "poke" | |
564 | $asm.puts "str #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]" | |
565 | when "fii2d" | |
566 | $asm.puts "vmov #{operands[2].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}" | |
567 | when "fd2ii" | |
568 | $asm.puts "vmov #{operands[1].armOperand}, #{operands[2].armOperand}, #{operands[0].armOperand}" | |
569 | when "bo" | |
570 | $asm.puts "bvs #{operands[0].asmLabel}" | |
571 | when "bs" | |
572 | $asm.puts "bmi #{operands[0].asmLabel}" | |
573 | when "bz" | |
574 | $asm.puts "beq #{operands[0].asmLabel}" | |
575 | when "bnz" | |
576 | $asm.puts "bne #{operands[0].asmLabel}" | |
577 | when "leai", "leap" | |
578 | operands[0].armEmitLea(operands[1]) | |
579 | when "smulli" | |
580 | raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4 | |
581 | $asm.puts "smull #{operands[2].armOperand}, #{operands[3].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}" | |
582 | else | |
583 | lowerDefault | |
584 | end | |
585 | end | |
586 | end | |
587 |