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
25require "config"
26require "ast"
27require "opt"
28require "risc"
29
30def 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
39end
40
41def 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
50end
51
52class 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
58end
59
60class SpecialRegister
61    def armOperand
62        @name
63    end
64end
65
66ARM_EXTRA_GPRS = [SpecialRegister.new("r6"), SpecialRegister.new("r10"), SpecialRegister.new("r12")]
67ARM_EXTRA_FPRS = [SpecialRegister.new("d7")]
68ARM_SCRATCH_FPR = SpecialRegister.new("d6")
69
70def 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
86end
87
88class 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
117end
118
119class 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
138end
139
140class Immediate
141    def armOperand
142        raise "Invalid immediate #{value} at #{codeOriginString}" if value < 0 or value > 255
143        "\##{value}"
144    end
145end
146
147class 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
152end
153
154class BaseIndex
155    def armOperand
156        raise "Bad offset at #{codeOriginString}" if offset.value != 0
157        "[#{base.armOperand}, #{index.armOperand}, lsl \##{scaleShift}]"
158    end
159end
160
161class AbsoluteAddress
162    def armOperand
163        raise "Unconverted absolute address at #{codeOriginString}"
164    end
165end
166
167#
168# Lea support.
169#
170
171class 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
179end
180
181class 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
186end
187
188# FIXME: we could support AbsoluteAddress for lea, but we don't.
189
190#
191# Actual lowering code follows.
192#
193
194class 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
234end
235
236def armOperands(operands)
237    operands.map{|v| v.armOperand}.join(", ")
238end
239
240def armFlippedOperands(operands)
241    armOperands([operands[-1]] + operands[0..-2])
242end
243
244def 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
256end
257
258def 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
265end
266
267def 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}"
271end
272
273def 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
289end
290
291def 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"
296end
297
298def 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"
303end
304
305class 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
617end
618
619