moved more code into common_code_generator
[voodoo-lang.git] / lib / voodoo / generators / arm_gas_generator.rb
blob4a7fa725302caa53c1012b179f6fd0226c279ac0
1 require 'voodoo/generators/common_code_generator'
2 require 'set'
4 module Voodoo
5   # = ARM GNU Assembler Code Generator
6   #
7   # The ARM code generator generates assembly code for use with
8   # the GNU assembler.
9   #
10   # == Calling Convention
11   #
12   # The first four arguments are passed in the registers r0 through r3.
13   # Any additional arguments are passed on the stack, starting at
14   # r13. r13 will always be a multiple of 8.
15   #
16   # The return address for the called function is passed in r14.
17   #
18   # The called function will store its return value in r0.
19   #
20   # The called function is required to preserve the values of registers
21   # r4 through r11 and register r13.
22   #
23   # This calling convention is compatible with the Procedure Call
24   # Standard for the ARM Architecture (AAPCS).
25   #
26   # == Call Frames
27   #
28   # Call frames have the following layout:
29   #
30   # When a function is called, it receives a stack frame that looks like
31   # the following:
32   #
33   #   :
34   #   old frame
35   #   padding
36   #   argn
37   #   :
38   #   arg4        <-- r13 points here
39   #
40   # The function prologue of functions generated by this code generator
41   # creates activation frames that look as follows:
42   #
43   #   :
44   #   old frame
45   #   padding
46   #   argn
47   #   :
48   #   arg4       <-- r11 points here
49   #   saved r14
50   #   saved r11
51   #   :
52   #   saved r4   <-- r13 points here
53   #
54   # == Register Usage
55   #
56   # Inside a function, registers r4..r8 and r10 are used for local variables
57   # and function arguments, whereas r11 is used as a frame pointer.
58   #
59   # r12 is used as a temporary, and r3 is used when another temporary
60   # is needed.
61   #
62   class ARMGasGenerator < CommonCodeGenerator
63     def initialize params
64       @WORDSIZE_BITS = 2
65       @WORDSIZE = 1 << @WORDSIZE_BITS
66       @CODE_ALIGNMENT = 4
67       @DATA_ALIGNMENT = @WORDSIZE
68       @FUNCTION_ALIGNMENT = @WORDSIZE
69       @STACK_ALIGNMENT_BITS = 3
70       @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
71       # Registers used for storing local variables.
72       @LOCAL_REGISTERS = [:r4, :r5, :r6, :r7, :r8, :r10]
73       # Set of registers used for storing local variables.
74       @LOCAL_REGISTERS_SET = Set.new @LOCAL_REGISTERS
75       # Hash from register names to offsets in saved frame.
76       @SAVED_FRAME_LAYOUT = { :r4 => 0, :r5 => 1, :r6 => 2, :r7 => 3, :r8 => 4,
77         :r9 => 5, :r10 => 6, :r11 => 7, :r13 => 8, :r14 => 9 }
78       @SAVE_FRAME_REGISTERS = @SAVED_FRAME_LAYOUT.keys
79       @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
80       @NREGISTER_ARGS = 4
81       @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
82       @FP = :r11
83       @RETURN = :r0
84       @TEMPORARIES = [:r12, :r3, :r2, :r1]
85       @constants = []
86       @frame_offset = 0
87       @frame_size = 0
88       @function_end_label = nil
89       @imports = {}
90       @if_labels = []
91       @saved_registers = []       # registers we've saved in the current frame
92       super params
93       @output_file_suffix = '.s'
94       @features.merge! \
95         :'bits-per-word' => '32',
96         :'byte-order' => 'little-endian',
97         :'bytes-per-word' => 4
98     end
100     # Create an entry in the constants table,
101     # returning the label that will refer to the constant.
102     # The value may be an integer or a label.
103     def add_constant value
104       label = gensym
105       @constants << [label, value]
106       label
107     end
109     # Returns the fp-relative offset for the nth (0-based) argument.
110     def arg_offset n
111       (n - @NREGISTER_ARGS) * @WORDSIZE
112     end
113     
114     # Returns an fp-relative reference for the nth (0-based) argument.
115     def arg_reference n
116       offset_reference arg_offset(n)
117     end
119     # Return the register in which the nth (0-based) argument is stored, or
120     # nil if not stored in a register
121     def arg_register n
122       if n < @NREGISTER_ARGS
123         # We copied the argument to one of the local registers.
124         @LOCAL_REGISTERS[n]
125       else
126         nil
127       end
128     end
130     def auto_bytes value, register
131       if value.kind_of? Integer
132         grow_frame value
133       else
134         temporary = register == :sp ? @TEMPORARIES[0] : register
135         load_value_into_register value, temporary
136         auto_bytes_register temporary
137       end
138       emit "cpy #{register}, sp\n" unless register == :sp
139     end
140     
141     # auto-bytes where the value is supplied in a register and the return
142     # value will be in sp. register must not be sp.
143     def auto_bytes_register register
144       temporary = register == @TEMPORARIES[0] ? :r3 : @TEMPORARIES[0]
145       emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
146       emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
147       emit "and #{register}, #{register}, #{temporary}\n"
148       emit "sub sp, #{register}\n"
149     end
150     
151     def auto_words value, register
152       if value.kind_of? Integer
153         auto_bytes(value * @WORDSIZE, register)
154       else
155         raise "Can't use :sp as a register for auto_words" if register == :sp
156         load_value_into_register value, register
157         emit "lsl #{register}, #{register}, \##{@WORDSIZE_BITS}\n"
158         auto_bytes_register register
159         emit "cpy #{register}, sp\n"
160       end
161     end
162     
163     # Begins a new block.
164     def begin_block *code
165       # If we are starting a block at top level, create a frame
166       if @environment == @top_level
167         nlocals = count_locals code
168         create_frame nlocals, false
169       end
170       @environment = Environment.new @environment
171     end
173     # Emit function prologue and declare _formals_ as function arguments
174     def begin_function formals, nlocals
175       if @environment != @top_level
176         raise "Can only begin a function at top level"
177       end
179       @function_end_label = gensym
180       environment = Environment.new @environment
181       formals.each_with_index do |formal, i|
182         if i < @NREGISTER_ARGS
183           environment.add_arg formal, arg_register(i)
184         else
185           environment.add_arg formal, arg_offset(i)
186         end
187       end
188       @environment = environment
189       emit_function_prologue formals, nlocals
190     end
192     # Define a byte with the given value
193     def byte value
194       emit ".byte #{value}\n"
195     end
197     # Call a function.
198     def call func, *args
199       # Calculate how many arguments need to be pushed on
200       # the stack, and allocate space for them.
201       nstack_args = number_of_stack_arguments args.length
202       old_frame_offset = @frame_offset
203       old_frame_size = @frame_size
204       grow_frame nstack_args if nstack_args > 0
206       # Put stack arguments on the stack
207       (@NREGISTER_ARGS...args.length).each do |n|
208         with_temporary do |temporary|
209           load_value_into_register args[n], temporary
210           emit "str #{temporary}, " +
211             "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
212         end
213       end
215       # Put register arguments in the right registers
216       nregister_args = number_of_register_arguments args.length
217       nregister_args.times do |n|
218           load_value_into_register args[n], :"r#{n}"        
219       end
221       # Call function
222       if global? func
223         emit "bl #{func}\n"
224       else
225         with_temporary do |temporary|
226           func_reg = load_value func, temporary
227           emit "blx #{func_reg}\n"
228         end
229       end
231       # Restore original stack frame
232       if old_frame_size != @frame_size
233         emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
234         @frame_offset = old_frame_offset
235         @frame_size = old_frame_size
236       end
237     end
239     # Creates a stack frame for the given number of arguments
240     # and local variables.
241     def create_frame nvars, save_lr = true
242       # Calculate how many variables we will store in registers,
243       # and how many on the stack.
244       nregister_vars = [nvars, @NREGISTER_LOCALS].min
245       nstack_vars = nvars - nregister_vars
247       # Save the registers we will clobber to the stack.
248       clobbered = []
249       nregister_vars.times do |i|
250         clobbered << @LOCAL_REGISTERS[i]
251       end
252       clobbered << @FP
253       clobbered << :lr if save_lr
254       @saved_registers = clobbered
255       emit "stmfd sp!, {#{clobbered.join ', '}}\n"
256       emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
258       # Calculate frame size so that the stack pointer will
259       # be properly aligned at the end of emit_function_prologue.
260       @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
261       extra_space = @frame_size - clobbered.length * @WORDSIZE
262       if extra_space > 0
263         emit "sub sp, sp, \##{extra_space}\n"
264       end
265       @frame_offset = 0
266     end
268     # Emits a comment.
269     def comment text
270       emit "# #{text}\n"
271     end
273     # Start a conditional using the specified branch instruction
274     # after the comparison.
275     def common_if comp, x, y = nil
276       with_temporary do |temporary|
277         xreg = load_value x, temporary
278         yreg = load_value y, :a4
280         falselabel = @environment.gensym
281         @if_labels.push falselabel
283         emit "cmp #{xreg}, #{yreg}\n"
284         lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
285           :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
286         emit "#{lut[comp]} #{falselabel}\n"
287       end
288     end
290     # Destroys the current stack frame.
291     # If ret is true, loads the saved value of lr into pc.
292     def destroy_frame ret = false
293       # Set sp back to where saved registers were stored
294       saved = @saved_registers
295       emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
297       if ret
298         index = saved.index :lr
299         if index
300           saved[index] = :pc
301         else
302           raise "Request to load saved lr into pc, but lr has not been saved"
303         end
304       end
305       emit "ldmfd sp!, {#{saved.join ', '}}\n"
306       
307       emit_constants if ret
308     end
310     # Aligns on the next multiple of +n+ bytes.
311     def emit_align n
312       emit ".align #{n}\n"
313     end
315     # Writes any constants that need to be written to the instruction
316     # stream, and clears the list of constants that need to be written.
317     def emit_constants
318       @constants.each do |x|
319         label x[0]
320         word x[1]
321       end
322       @constants = []
323     end
325     # Emit function prologue.
326     def emit_function_prologue formals = [], nlocals = 0
327       # Calculate the number of arguments we were passed in
328       # registers, the total number of values we need to save
329       # on the stack, then create a stack frame and save
330       # the registers we will be using.
331       nregister_args = [formals.length, @NREGISTER_ARGS].min
332       nvars = nregister_args + nlocals
333       create_frame nvars, true
335       # Move arguments that were passed in registers into
336       # callee-save registers.
337       nregister_args.times do |i|
338         emit "cpy #{@LOCAL_REGISTERS[i]}, r#{i}\n"
339       end
340     end
342     # Loads a word into a register.
343     def emit_load_word register, base, offset
344       if offset == 0
345         emit "ldr #{register}, [#{base}]\n"
346       else
347         emit "ldr #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
348       end
349     end
351     # Stores the value of a register in memory.
352     def emit_store_word register, base, offset
353       if offset == 0
354         emit "str #{register}, [#{base}]\n"
355       else
356         emit "str #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
357       end
358     end
360     # Ends the current block.
361     def end_block
362       # If we are returning to top level, restore stack pointer
363       # and saved registers.
364       if @environment.parent == @top_level
365         offset = @frame_size - @saved_registers.length * @WORDSIZE
366         if offset > 0
367           emit "add sp, sp, \##{offset}\n"
368         end
369         emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
370         @frame_size = 0
371         @frame_offset = 0
372         @saved_registers = []
374         # If we need to emit constants, do so now
375         unless @constants.empty?
376           lbl = gensym
377           goto lbl
378           label lbl
379         end
380       end
382       # Restore old value of @environment
383       @environment = @environment.parent
384     end
386     # Ends a function body.
387     def end_function
388       if @environment == @top_level
389         raise "Cannot end function when not in a function"
390       end
392       label @function_end_label
394       destroy_frame true
395       @frame_size = 0
396       @frame_offset = 0
397       @saved_registers = []
398       @environment = @top_level
399     end
401     # Ends a conditional.
402     def end_if
403       label @if_labels.pop
404     end
406     # Evaluate the binary operation expr and store the result in register
407     def eval_binop expr, register
408       op = expr[0]
410       # Emulation for div and mod, which ARM does not have instructions for
411       case op
412       when :div
413         func = :"__aeabi_idiv"
414         import func unless @imports.has_key? func
415         call func, expr[1], expr[2]
416         emit "cpy #{register}, r0\n" if register != :r0
417         return
418       when :mod
419         func = :"__aeabi_idivmod"
420         import func unless @imports.has_key? func
421         call func, expr[1], expr[2]
422         emit "cpy #{register}, r1\n" if register != :r1
423         return
424       end
426       with_temporaries(2) do |t1,t2|
427         x = load_value expr[1], t1
429         case op
430         when :mul
431           # Operand must be in a register for these ops.
432           y = load_value expr[2], t2
433         else
434           y = value_ref expr[2], t2
435         end
437         case op
438         when :bsr
439           emit "lsr #{register}, #{x}, #{y}\n"
440         when :or
441             emit "orr #{register}, #{x}, #{y}\n"
442         when :mul
443           # Can't store result in same register as first operand.
444           if register == x
445             if x == y
446               # All using the same register. Move x to a different
447               # register to make this work.
448               temp = (x == t1) ? t2 : t1
449               emit "cpy #{temp}, #{x}\n"
450               emit "mul #{register}, #{temp}, #{y}\n"
451             else
452               # Multiplication is commutative. Just swap x and y.
453               emit "mul #{register}, #{y}, #{x}\n"
454             end
455           else
456             # Common case, register and x are different.
457             emit "mul #{register}, #{x}, #{y}\n"
458           end
459         when :rol
460           if integer? expr[2]
461             y = "\##{32 - expr[2]}"
462           else
463             emit "rsb #{y}, #{y}, #32\n"
464           end
465           emit "ror #{register}, #{x}, #{y}\n"
466         when :shl
467           emit "lsl #{register}, #{x}, #{y}\n"
468         when :shr
469           emit "lsr #{register}, #{x}, #{y}\n"
470         when :xor
471           emit "eor #{register}, #{x}, #{y}\n"
472         else
473           emit "#{expr[0]} #{register}, #{x}, #{y}\n"
474         end
475       end
476     end
478     # Evaluates the expression +expr+ and stores the result in +register+.
479     def eval_expr expr, register
480       if expr.length == 1
481         # Load value
482         load_value_into_register expr[0], register
483       else
484         # Evaluate expression
485         op = expr[0]
486         case op
487         when :'auto-bytes'
488           auto_bytes expr[1], register
489         when :'auto-words'
490           auto_words expr[1], register
491         when :call
492           call *expr[1..-1]
493           emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
494         when :'get-byte'
495           get_byte expr[1], expr[2], register
496         when :'get-word'
497           get_word expr[1], expr[2], register
498         when :not
499           load_value_into_register expr[1], register
500           with_temporary do |temporary|
501             emit "mvn #{temporary}, #0\n"
502             emit "eor #{register}, #{register}, #{temporary}\n"
503           end
504         else
505           if binop? op
506             eval_binop expr, register
507           else
508             raise "Not a magic word: #{op}"
509           end
510         end
511       end
512     end
514     # Export symbols from the current section
515     def export *symbols
516       symbols.each { |sym| emit ".globl #{sym}\n" }
517     end
519     # Load byte from _base_ + _offset_ into _register_
520     def get_byte base, offset, register
521       # If base is an integer, but offset isn't, swap them
522       if !integer?(offset) && integer?(base)
523         base, offset = [offset, base]
524       end
526       if integer? offset
527         with_temporary do |temporary|
528           base_reg = load_value base, temporary
529           if offset == 0
530             emit "ldrb #{register}, [#{base_reg}]\n"
531           else
532             emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
533           end
534         end
535       else
536         with_temporaries(2) do |t1,t2|
537           base_reg = load_value base, t1
538           offset_reg = load_value offset, t2
539           emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
540         end
541       end
542     end
544     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
545     def get_word base, offset, register
546       if integer? offset
547         with_temporary do |temporary|
548           base_reg = load_value base, temporary
549           if offset == 0
550             emit "ldr #{register}, [#{base_reg}]\n"
551           else
552             emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
553           end
554         end
555       else
556         with_temporaries(2) do |t1,t2|
557           base_reg = load_value base, t1
558           offset_reg = load_value offset, t2
559           emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
560         end
561       end
562     end
564     # Jump to a label.
565     def goto label
566       if global? label
567         emit "b #{label}\n"
568       else
569         with_temporary do |temporary|
570           register = load_value label, temporary
571           emit "cpy pc, #{register}\n"
572         end
573       end
575       # If we have constants that need to be emitted, do so now
576       emit_constants
577     end
579     # Grows the current frame by n words, plus padding to
580     # respect alignment rules.
581     def grow_frame nwords
582       increment = stack_align(nwords * @WORDSIZE)
583       emit "sub sp, sp, \##{increment}\n"
584       @frame_size = @frame_size + increment
585       @frame_offset = @frame_offset + increment
586     end
588     # Start the false path of a conditional.
589     def ifelse
590       newlabel = @environment.gensym
591       goto newlabel
592       lbl = @if_labels.pop
593       label lbl
594       @if_labels.push newlabel
595     end
597     # Test if x is equal to y
598     def ifeq x, y
599       common_if :ifeq, x, y
600     end
602     # Test if x is greater than or equal to y
603     def ifge x, y
604       common_if :ifge, x, y
605     end
607     # Test if x is strictly greater than y
608     def ifgt x, y
609       common_if :ifgt, x, y
610     end
612     # Test if x is less than or equal to y
613     def ifle x, y
614       common_if :ifle, x, y
615     end
617     # Test if x is strictly less than y
618     def iflt x, y
619       common_if :iflt, x, y
620     end
622     # Test if x different from y
623     def ifne x, y
624       common_if :ifne, x, y
625     end
627     # Import labels into the current section
628     def import *symbols
629       # Record imported labels in @imports
630       symbols.each { |sym| @imports[sym] = sym }
631     end
633     # Emit a label
634     def label name
635       emit "#{name}:\n"
636     end
638     # Introduce a new local variable
639     def let symbol, *expr
640       n = @environment.locals
641       register = local_register n
643       if register
644         # We will use a register to store the value
645         @environment.add_local symbol, register
646         eval_expr expr, register
647       else
648         # We will use the stack to store the value
649         offset = local_offset n
650         @environment.add_local symbol, offset
651         with_temporary do |temporary|
652           eval_expr expr, temporary
653           emit "str #{temporary}, #{offset_reference offset}\n"
654         end
655       end
656     end
658     # Loads the value at the given address.
659     def load_at address, register
660       load_value_into_register address, register
661       emit "ldr #{register}, [#{register}]\n"
662       register
663     end
665     # Loads a value into some register.
666     # If the value is already in a register, does nothing.
667     # Else, loads the value into the register given as the
668     # second argument.
669     # Returns the name of the register the value is in.
670     def load_value x, register
671       ref = value_ref x, register
672       if register? ref
673         ref
674       else
675         emit "mov #{register}, #{ref}\n"
676         register
677       end
678     end
680     # Loads a value into a specific register.
681     def load_value_into_register x, register
682       ref = value_ref x, register
683       if ref != register
684         if register? ref
685           emit "cpy #{register}, #{ref}\n"
686         else
687           emit "mov #{register}, #{ref}\n"
688         end
689       end
690       register
691     end
693     # Returns the fp-relative reference for the nth (0-based) local.
694     def local_offset n
695       -@INITIAL_FRAME_SIZE - ((n + number_of_register_arguments) * @WORDSIZE)
696     end
697     
698     # Given an offset, returns an fp-relative reference.
699     def offset_reference offset
700       "[#{@FP}, \##{offset}]"
701     end
703     # Returns true if the nth (0-based) local is stored in a register
704     def register_local? n
705       (n + number_of_register_arguments) < @NREGISTER_LOCALS
706     end
708     # Returns from a function.
709     # 
710     # _words_ may contain an expression to be evaluated. The result
711     # of the evaluation is returned from the function.
712     def ret *words
713       # Compute return value and store it in @RETURN
714       eval_expr(words, @RETURN) unless words.empty?
715       # Go to epilogue
716       goto @function_end_label
717     end
719     # Set a variable to the result of evaluating an expression
720     def set symbol, *expr
721       if at_expr? symbol
722         with_temporaries(2) do |t1,t2|
723           eval_expr expr, t1
724           register = load_value symbol[1], t2
725           emit "str #{t1}, [#{register}]\n"
726         end
727       else
728         x = @environment[symbol]
729         if x == nil
730           raise "Cannot change value of constant #{symbol}"
731         elsif x.kind_of? Symbol
732           eval_expr expr, x
733         else
734           with_temporary do |temporary|
735             eval_expr expr, temporary
736             emit "str #{temporary}, #{offset_reference x}\n"
737           end
738         end
739       end
740     end
742     # Set the byte at _base_ + _offset_ to _value_
743     def set_byte base, offset, value
744       # If base is an integer, but offset isn't, swap them
745       if !integer?(offset) && integer?(base)
746         base, offset = [offset, base]
747       end
749       if integer? offset
750         base_reg = load_value base, :a4
751         with_temporary do |temporary|
752           load_value_into_register value, temporary
753           if offset == 0
754             emit "strb #{temporary}, [#{base_reg}]\n"
755           else
756             emit "strb #{temporary}, [#{base_reg}, \##{offset}]\n"
757           end
758         end
759       else
760         eval_binop [:add, base, offset], :a4
761         with_temporary do |temporary|
762           load_value_into_register value, temporary
763           emit "strb #{temporary}, [a4]\n"
764         end
765       end
766     end
768     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
769     def set_word base, offset, value
770       # If base is an integer, but offset isn't, swap them
771       if !integer?(offset) && integer?(base)
772         base, offset = [offset, base]
773       end
775       if integer? offset
776         base_reg = load_value base, :a4
777         with_temporary do |temporary|
778           load_value_into_register value, temporary
779           if offset == 0
780             emit "str #{temporary}, [#{base_reg}]\n"
781           else
782             emit "str #{temporary}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
783           end
784         end
785       else
786         load_value_into_register base, :a4
787         with_temporary do |temporary|
788           load_value_into_register offset, temporary
789           emit "add a4, a4, #{temporary}, LSL #2\n"
790           load_value_into_register value, temporary
791           emit "str #{temporary}, [a4]\n"
792         end
793       end
794     end
796     # Define a string with the given value
797     def string value
798       code = ''
799       value.each_byte do |b|
800         if b == 92
801           code << "\\\\"
802         elsif b >= 32 && b < 127 && b != 34
803           code << b.chr
804         else
805           code << sprintf("\\%03o", b)
806         end
807       end
808       emit ".ascii \"#{code}\"\n"
809     end
811     # Call a function, re-using the current call frame if possible.
812     def tail_call func, *args
813       # Compute number of stack arguments
814       nstackargs = number_of_stack_arguments args.length
815       # If we need more stack arguments than we have now,
816       # perform a normal call and return
817       if nstackargs > number_of_stack_arguments(@environment.args)
818         emit "# Not enough space for proper tail call; using regular call\n"
819         ret :call, func, *args
820       end
822       # We will assign arguments from left to right.
823       # Find places that we will overwrite before we read them,
824       # and store their values in some newly allocated stack space.
825       old_frame_offset = @frame_offset
826       old_frame_size = @frame_size
827       overwritten = {}
828       (@NREGISTER_ARGS...args.length).each do |i|
829         arg = args[i]
830         arg = arg[1] if at_expr? arg
831         if symbol?(arg)
832           binding = @environment[arg]
833           if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
834               binding[1] < i
835             # Argument i is a stack argument, but the value we will assign
836             # it is a stack argument that comes before it, so we will
837             # have overwritten it by the time we get to it.
838             overwritten[arg] = nil
839           end
840         end
841       end
842       
843       unless overwritten.empty?
844         # Allocate space for arguments to be saved
845         grow_frame overwritten.length
846         # Save values
847         offset = 0
848         overwritten.each_key do |key|
849           reg = load_value key
850           emit "str #{reg}, [sp, \##{offset}]\n"
851           overwritten[key] = offset
852           offset = offset + @WORDSIZE
853         end
854       end
856       # Assign arguments
857       args.each_index do |i|
858         arg = args[i]
859         if register_arg? i
860           load_value_into_register arg, "a#{i + 1}"
861         else
862           # Test if this is a value we saved
863           sym = at_expr?(arg) ? arg[1] : arg
864           saved = overwritten[sym]
865           if saved
866             # Saved value, load from stack
867             with_temporary do |temporary|
868               emit "ldr #{temporary}, [sp, \##{saved}]\n"
869               emit "str #{temporary}, #{arg_reference i}\n"
870             end
871           else
872             # Regular value, use load_value
873             with_temporary do |temporary|
874               reg = load_value arg, temporary
875               emit "str #{reg}, #{arg_reference i}\n"
876             end
877           end
878         end
879       end
881       with_temporary do |temporary|
882         # Load address of function to be called
883         load_value_into_register func, temporary
885         # Destroy current activation frame and enter func
886         destroy_frame false
887         emit "bx #{temporary}\n"
888       end
889       emit_constants
890     end
892     # Returns a reference to a value.
893     # For immediate values that fit in 8 bits, this returns the
894     # value itself (in ARM syntax).
895     # For all other values, loads the value into a register and
896     # returns the name of the register. If the value is already
897     # in a register, the name of that register is returned. Else,
898     # the value is loaded into the register specified as the
899     # second argument.
900     def value_ref x, register
901       if substitution? x
902         x = substitute_number x[1]
903       end
904         
905       if integer? x
906         if x >= 0 && x <= 255
907           return "\##{x}"
908         elsif x >= -255 && x < 0
909           emit "mvn #{register}, \##{-(x + 1)}\n"
910           return register
911         else
912           lbl = add_constant x
913           emit "ldr #{register}, #{lbl}\n"
914           return register
915         end
916       elsif symbol? x
917         binding = @environment[x]
918         if binding.kind_of? Symbol
919           # Value is already in a register. Return register name.
920           return binding
921         elsif binding.kind_of? Integer
922           # Value is on the stack. Load from the stack.
923           emit "ldr #{register}, #{offset_reference binding}\n"
924           return register
925         else
926           # Assume global
927           lbl = add_constant x
928           emit "ldr #{register}, #{lbl}\n"
929           return register
930         end
931       elsif at_expr? x
932         load_at x[1], register
933       else
934         raise "Don't know how to load #{x.inspect}"
935       end
936     end
938     # Define a word with the given value
939     def word value
940       emit ".int #{value}\n"
941     end
943   end
945   # Register class for little endian ARM
946   Voodoo::CodeGenerator.register_generator ARMGasGenerator,
947                                            :architecture => :arm,
948                                            :format => :gas