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