]> git.saurik.com Git - apple/javascriptcore.git/blob - offlineasm/arm.rb
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / offlineasm / arm.rb
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("r6"), SpecialRegister.new("r10"), SpecialRegister.new("r12")]
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.is_a? String
73 $asm.puts "mov #{register.armOperand}, (#{value})"
74 elsif value >= 0 && value < 256
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"
102 "r8"
103 when "t5"
104 "r9"
105 when "cfr"
106 isARMv7 ? "r7" : "r11"
107 when "lr"
108 "lr"
109 when "sp"
110 "sp"
111 when "pc"
112 "pc"
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
342 elsif operands.size == 3 and operands[0].register?
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"
460 operands.each {
461 | op |
462 $asm.puts "pop { #{op.armOperand} }"
463 }
464 when "push"
465 operands.each {
466 | op |
467 $asm.puts "push { #{op.armOperand} }"
468 }
469 when "popCalleeSaves"
470 if isARMv7
471 $asm.puts "pop {r4-r6, r8-r11}"
472 else
473 $asm.puts "pop {r4-r10}"
474 end
475 when "pushCalleeSaves"
476 if isARMv7
477 $asm.puts "push {r4-r6, r8-r11}"
478 else
479 $asm.puts "push {r4-r10}"
480 end
481 when "move"
482 if operands[0].immediate?
483 armMoveImmediate(operands[0].value, operands[1])
484 else
485 $asm.puts "mov #{armFlippedOperands(operands)}"
486 end
487 when "mvlbl"
488 $asm.puts "movw #{operands[1].armOperand}, \#:lower16:#{operands[0].value}"
489 $asm.puts "movt #{operands[1].armOperand}, \#:upper16:#{operands[0].value}"
490 when "nop"
491 $asm.puts "nop"
492 when "bieq", "bpeq", "bbeq"
493 if Immediate.new(nil, 0) == operands[0]
494 $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}"
495 elsif Immediate.new(nil, 0) == operands[1]
496 $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}"
497 else
498 $asm.puts "cmp #{armOperands(operands[0..1])}"
499 end
500 $asm.puts "beq #{operands[2].asmLabel}"
501 when "bineq", "bpneq", "bbneq"
502 if Immediate.new(nil, 0) == operands[0]
503 $asm.puts "tst #{operands[1].armOperand}, #{operands[1].armOperand}"
504 elsif Immediate.new(nil, 0) == operands[1]
505 $asm.puts "tst #{operands[0].armOperand}, #{operands[0].armOperand}"
506 else
507 $asm.puts "cmp #{armOperands(operands[0..1])}"
508 end
509 $asm.puts "bne #{operands[2].asmLabel}"
510 when "bia", "bpa", "bba"
511 $asm.puts "cmp #{armOperands(operands[0..1])}"
512 $asm.puts "bhi #{operands[2].asmLabel}"
513 when "biaeq", "bpaeq", "bbaeq"
514 $asm.puts "cmp #{armOperands(operands[0..1])}"
515 $asm.puts "bhs #{operands[2].asmLabel}"
516 when "bib", "bpb", "bbb"
517 $asm.puts "cmp #{armOperands(operands[0..1])}"
518 $asm.puts "blo #{operands[2].asmLabel}"
519 when "bibeq", "bpbeq", "bbbeq"
520 $asm.puts "cmp #{armOperands(operands[0..1])}"
521 $asm.puts "bls #{operands[2].asmLabel}"
522 when "bigt", "bpgt", "bbgt"
523 $asm.puts "cmp #{armOperands(operands[0..1])}"
524 $asm.puts "bgt #{operands[2].asmLabel}"
525 when "bigteq", "bpgteq", "bbgteq"
526 $asm.puts "cmp #{armOperands(operands[0..1])}"
527 $asm.puts "bge #{operands[2].asmLabel}"
528 when "bilt", "bplt", "bblt"
529 $asm.puts "cmp #{armOperands(operands[0..1])}"
530 $asm.puts "blt #{operands[2].asmLabel}"
531 when "bilteq", "bplteq", "bblteq"
532 $asm.puts "cmp #{armOperands(operands[0..1])}"
533 $asm.puts "ble #{operands[2].asmLabel}"
534 when "btiz", "btpz", "btbz"
535 emitArmTest(operands)
536 $asm.puts "beq #{operands[-1].asmLabel}"
537 when "btinz", "btpnz", "btbnz"
538 emitArmTest(operands)
539 $asm.puts "bne #{operands[-1].asmLabel}"
540 when "btis", "btps", "btbs"
541 emitArmTest(operands)
542 $asm.puts "bmi #{operands[-1].asmLabel}"
543 when "jmp"
544 if operands[0].label?
545 $asm.puts "b #{operands[0].asmLabel}"
546 else
547 $asm.puts "mov pc, #{operands[0].armOperand}"
548 end
549 if not isARMv7 and not isARMv7Traditional
550 $asm.puts ".ltorg"
551 end
552 when "call"
553 if operands[0].label?
554 $asm.puts "blx #{operands[0].asmLabel}"
555 else
556 $asm.puts "blx #{operands[0].armOperand}"
557 end
558 when "break"
559 $asm.puts "bkpt #0"
560 when "ret"
561 $asm.puts "bx lr"
562 when "cieq", "cpeq", "cbeq"
563 emitArmCompare(operands, "eq")
564 when "cineq", "cpneq", "cbneq"
565 emitArmCompare(operands, "ne")
566 when "cia", "cpa", "cba"
567 emitArmCompare(operands, "hi")
568 when "ciaeq", "cpaeq", "cbaeq"
569 emitArmCompare(operands, "hs")
570 when "cib", "cpb", "cbb"
571 emitArmCompare(operands, "lo")
572 when "cibeq", "cpbeq", "cbbeq"
573 emitArmCompare(operands, "ls")
574 when "cigt", "cpgt", "cbgt"
575 emitArmCompare(operands, "gt")
576 when "cigteq", "cpgteq", "cbgteq"
577 emitArmCompare(operands, "ge")
578 when "cilt", "cplt", "cblt"
579 emitArmCompare(operands, "lt")
580 when "cilteq", "cplteq", "cblteq"
581 emitArmCompare(operands, "le")
582 when "tis", "tbs", "tps"
583 emitArmTestSet(operands, "mi")
584 when "tiz", "tbz", "tpz"
585 emitArmTestSet(operands, "eq")
586 when "tinz", "tbnz", "tpnz"
587 emitArmTestSet(operands, "ne")
588 when "peek"
589 $asm.puts "ldr #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]"
590 when "poke"
591 $asm.puts "str #{operands[1].armOperand}, [sp, \##{operands[0].value * 4}]"
592 when "fii2d"
593 $asm.puts "vmov #{operands[2].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}"
594 when "fd2ii"
595 $asm.puts "vmov #{operands[1].armOperand}, #{operands[2].armOperand}, #{operands[0].armOperand}"
596 when "bo"
597 $asm.puts "bvs #{operands[0].asmLabel}"
598 when "bs"
599 $asm.puts "bmi #{operands[0].asmLabel}"
600 when "bz"
601 $asm.puts "beq #{operands[0].asmLabel}"
602 when "bnz"
603 $asm.puts "bne #{operands[0].asmLabel}"
604 when "leai", "leap"
605 operands[0].armEmitLea(operands[1])
606 when "smulli"
607 raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
608 $asm.puts "smull #{operands[2].armOperand}, #{operands[3].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}"
609 when "memfence"
610 $asm.puts "dmb sy"
611 when "clrbp"
612 $asm.puts "bic #{operands[2].armOperand}, #{operands[0].armOperand}, #{operands[1].armOperand}"
613 else
614 lowerDefault
615 end
616 end
617 end
618