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