made save-frame only save registers not yet saved in the frame
[voodoo-lang.git] / lib / voodoo / generators / arm_gas_generator.rb
blob4518850409c4be8210f09877b5918b3a2509acee
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       # Registers to be saved by save-frame.
76       @SAVE_FRAME_REGISTERS = [:r4, :r5, :r6, :r7, :r8,
77                                :r9, :r10, :r11, :r13, :r14]
78       # Hash from register names to offsets in saved frame.
79       @SAVED_FRAME_LAYOUT = {}
80       @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
81       @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
82       @NREGISTER_ARGS = 4
83       @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
84       @FP = :r11
85       @RETURN = :r0
86       @TEMPORARIES = [:r12, :r3, :r2, :r1]
87       @constants = []
88       @frame_offset = 0
89       @frame_size = 0
90       @function_end_label = nil
91       @imports = {}
92       @if_labels = []
93       @saved_registers = []       # registers we've saved in the current frame
94       super params
95       @output_file_suffix = '.s'
96       @features.merge! \
97         :'bits-per-word' => '32',
98         :'byte-order' => 'little-endian',
99         :'bytes-per-word' => 4
100     end
102     # Create an entry in the constants table,
103     # returning the label that will refer to the constant.
104     # The value may be an integer or a label.
105     def add_constant value
106       label = gensym
107       @constants << [label, value]
108       label
109     end
111     # Returns the fp-relative offset for the nth (0-based) argument.
112     def arg_offset n
113       (n - @NREGISTER_ARGS) * @WORDSIZE
114     end
115     
116     # Returns an fp-relative reference for the nth (0-based) argument.
117     def arg_reference n
118       offset_reference arg_offset(n)
119     end
121     # Return the register in which the nth (0-based) argument is stored, or
122     # nil if not stored in a register
123     def arg_register n
124       if n < @NREGISTER_ARGS
125         # We copied the argument to one of the local registers.
126         @LOCAL_REGISTERS[n]
127       else
128         nil
129       end
130     end
132     def auto_bytes value, register
133       if value.kind_of? Integer
134         grow_frame value
135       else
136         temporary = register == :sp ? @TEMPORARIES[0] : register
137         load_value_into_register value, temporary
138         auto_bytes_register temporary
139       end
140       emit "cpy #{register}, sp\n" unless register == :sp
141     end
142     
143     # auto-bytes where the value is supplied in a register and the return
144     # value will be in sp. register must not be sp.
145     def auto_bytes_register register
146       temporary = register == @TEMPORARIES[0] ? :r3 : @TEMPORARIES[0]
147       emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
148       emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
149       emit "and #{register}, #{register}, #{temporary}\n"
150       emit "sub sp, #{register}\n"
151     end
152     
153     def auto_words value, register
154       if value.kind_of? Integer
155         auto_bytes(value * @WORDSIZE, register)
156       else
157         raise "Can't use :sp as a register for auto_words" if register == :sp
158         load_value_into_register value, register
159         emit "lsl #{register}, #{register}, \##{@WORDSIZE_BITS}\n"
160         auto_bytes_register register
161         emit "cpy #{register}, sp\n"
162       end
163     end
164     
165     # Begins a new block.
166     def begin_block *code
167       # If we are starting a block at top level, create a frame
168       if @environment == @top_level
169         nlocals = count_locals code
170         create_frame nlocals, false
171       end
172       @environment = Environment.new @environment
173     end
175     # Emit function prologue and declare _formals_ as function arguments
176     def begin_function formals, nlocals
177       if @environment != @top_level
178         raise "Can only begin a function at top level"
179       end
181       @function_end_label = gensym
182       environment = Environment.new @environment
183       formals.each_with_index do |formal, i|
184         if i < @NREGISTER_ARGS
185           environment.add_arg formal, arg_register(i)
186         else
187           environment.add_arg formal, arg_offset(i)
188         end
189       end
190       @environment = environment
191       emit_function_prologue formals, nlocals
192     end
194     # Define a byte with the given value
195     def byte value
196       emit ".byte #{value}\n"
197     end
199     # Call a function.
200     def call func, *args
201       # Calculate how many arguments need to be pushed on
202       # the stack, and allocate space for them.
203       nstack_args = number_of_stack_arguments args.length
204       old_frame_offset = @frame_offset
205       old_frame_size = @frame_size
206       grow_frame nstack_args if nstack_args > 0
208       # Put stack arguments on the stack
209       (@NREGISTER_ARGS...args.length).each do |n|
210         with_temporary do |temporary|
211           load_value_into_register args[n], temporary
212           emit "str #{temporary}, " +
213             "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
214         end
215       end
217       # Put register arguments in the right registers
218       nregister_args = number_of_register_arguments args.length
219       nregister_args.times do |n|
220           load_value_into_register args[n], :"r#{n}"        
221       end
223       # Call function
224       if global? func
225         emit "bl #{func}\n"
226       else
227         with_temporary do |temporary|
228           func_reg = load_value func, temporary
229           emit "blx #{func_reg}\n"
230         end
231       end
233       # Restore original stack frame
234       if old_frame_size != @frame_size
235         emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
236         @frame_offset = old_frame_offset
237         @frame_size = old_frame_size
238       end
239     end
241     # Creates a stack frame for the given number of arguments
242     # and local variables.
243     def create_frame nvars, save_lr = true
244       # Calculate how many variables we will store in registers,
245       # and how many on the stack.
246       nregister_vars = [nvars, @NREGISTER_LOCALS].min
247       nstack_vars = nvars - nregister_vars
249       # Save the registers we will clobber to the stack.
250       clobbered = []
251       nregister_vars.times do |i|
252         clobbered << @LOCAL_REGISTERS[i]
253       end
254       clobbered << @FP
255       clobbered << :lr if save_lr
256       @saved_registers = clobbered
257       emit "stmfd sp!, {#{clobbered.join ', '}}\n"
258       emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
260       # Calculate frame size so that the stack pointer will
261       # be properly aligned at the end of emit_function_prologue.
262       @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
263       extra_space = @frame_size - clobbered.length * @WORDSIZE
264       if extra_space > 0
265         emit "sub sp, sp, \##{extra_space}\n"
266       end
267       @frame_offset = 0
268     end
270     # Emits a comment.
271     def comment text
272       emit "# #{text}\n"
273     end
275     # Start a conditional using the specified branch instruction
276     # after the comparison.
277     def common_if comp, x, y = nil
278       with_temporary do |temporary|
279         xreg = load_value x, temporary
280         yreg = load_value y, :a4
282         falselabel = @environment.gensym
283         @if_labels.push falselabel
285         emit "cmp #{xreg}, #{yreg}\n"
286         lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
287           :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
288         emit "#{lut[comp]} #{falselabel}\n"
289       end
290     end
292     # Destroys the current stack frame.
293     # If ret is true, loads the saved value of lr into pc.
294     def destroy_frame ret = false
295       # Set sp back to where saved registers were stored
296       saved = @saved_registers
297       emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
299       if ret
300         index = saved.index :lr
301         if index
302           saved[index] = :pc
303         else
304           raise "Request to load saved lr into pc, but lr has not been saved"
305         end
306       end
307       emit "ldmfd sp!, {#{saved.join ', '}}\n"
308       
309       emit_constants if ret
310     end
312     # Aligns on the next multiple of +n+ bytes.
313     def emit_align n
314       emit ".align #{n}\n"
315     end
317     # Writes any constants that need to be written to the instruction
318     # stream, and clears the list of constants that need to be written.
319     def emit_constants
320       @constants.each do |x|
321         label x[0]
322         word x[1]
323       end
324       @constants = []
325     end
327     # Emit function prologue.
328     def emit_function_prologue formals = [], nlocals = 0
329       # Calculate the number of arguments we were passed in
330       # registers, the total number of values we need to save
331       # on the stack, then create a stack frame and save
332       # the registers we will be using.
333       nregister_args = [formals.length, @NREGISTER_ARGS].min
334       nvars = nregister_args + nlocals
335       create_frame nvars, true
337       # Move arguments that were passed in registers into
338       # callee-save registers.
339       nregister_args.times do |i|
340         emit "cpy #{@LOCAL_REGISTERS[i]}, r#{i}\n"
341       end
342     end
344     # Loads a word into a register.
345     def emit_load_word register, base, offset
346       if offset == 0
347         emit "ldr #{register}, [#{base}]\n"
348       else
349         emit "ldr #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
350       end
351     end
353     # Stores the value of a register in memory.
354     def emit_store_word register, base, offset
355       if offset == 0
356         emit "str #{register}, [#{base}]\n"
357       else
358         emit "str #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
359       end
360     end
362     # Ends the current block.
363     def end_block
364       # If we are returning to top level, restore stack pointer
365       # and saved registers.
366       if @environment.parent == @top_level
367         offset = @frame_size - @saved_registers.length * @WORDSIZE
368         if offset > 0
369           emit "add sp, sp, \##{offset}\n"
370         end
371         emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
372         @frame_size = 0
373         @frame_offset = 0
374         @saved_registers = []
376         # If we need to emit constants, do so now
377         unless @constants.empty?
378           lbl = gensym
379           goto lbl
380           label lbl
381         end
382       end
384       # Restore old value of @environment
385       @environment = @environment.parent
386     end
388     # Ends a function body.
389     def end_function
390       if @environment == @top_level
391         raise "Cannot end function when not in a function"
392       end
394       label @function_end_label
396       destroy_frame true
397       @frame_size = 0
398       @frame_offset = 0
399       @saved_registers = []
400       @environment = @top_level
401     end
403     # Ends a conditional.
404     def end_if
405       label @if_labels.pop
406     end
408     # Evaluate the binary operation expr and store the result in register
409     def eval_binop expr, register
410       op = expr[0]
412       # Emulation for div and mod, which ARM does not have instructions for
413       case op
414       when :div
415         func = :"__aeabi_idiv"
416         import func unless @imports.has_key? func
417         call func, expr[1], expr[2]
418         emit "cpy #{register}, r0\n" if register != :r0
419         return
420       when :mod
421         func = :"__aeabi_idivmod"
422         import func unless @imports.has_key? func
423         call func, expr[1], expr[2]
424         emit "cpy #{register}, r1\n" if register != :r1
425         return
426       end
428       with_temporaries(2) do |t1,t2|
429         x = load_value expr[1], t1
431         case op
432         when :mul
433           # Operand must be in a register for these ops.
434           y = load_value expr[2], t2
435         else
436           y = value_ref expr[2], t2
437         end
439         case op
440         when :bsr
441           emit "lsr #{register}, #{x}, #{y}\n"
442         when :or
443             emit "orr #{register}, #{x}, #{y}\n"
444         when :mul
445           # Can't store result in same register as first operand.
446           if register == x
447             if x == y
448               # All using the same register. Move x to a different
449               # register to make this work.
450               temp = (x == t1) ? t2 : t1
451               emit "cpy #{temp}, #{x}\n"
452               emit "mul #{register}, #{temp}, #{y}\n"
453             else
454               # Multiplication is commutative. Just swap x and y.
455               emit "mul #{register}, #{y}, #{x}\n"
456             end
457           else
458             # Common case, register and x are different.
459             emit "mul #{register}, #{x}, #{y}\n"
460           end
461         when :rol
462           if integer? expr[2]
463             y = "\##{32 - expr[2]}"
464           else
465             emit "rsb #{y}, #{y}, #32\n"
466           end
467           emit "ror #{register}, #{x}, #{y}\n"
468         when :shl
469           emit "lsl #{register}, #{x}, #{y}\n"
470         when :shr
471           emit "lsr #{register}, #{x}, #{y}\n"
472         when :xor
473           emit "eor #{register}, #{x}, #{y}\n"
474         else
475           emit "#{expr[0]} #{register}, #{x}, #{y}\n"
476         end
477       end
478     end
480     # Evaluates the expression +expr+ and stores the result in +register+.
481     def eval_expr expr, register
482       if expr.length == 1
483         # Load value
484         load_value_into_register expr[0], register
485       else
486         # Evaluate expression
487         op = expr[0]
488         case op
489         when :'auto-bytes'
490           auto_bytes expr[1], register
491         when :'auto-words'
492           auto_words expr[1], register
493         when :call
494           call *expr[1..-1]
495           emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
496         when :'get-byte'
497           get_byte expr[1], expr[2], register
498         when :'get-word'
499           get_word expr[1], expr[2], register
500         when :not
501           load_value_into_register expr[1], register
502           with_temporary do |temporary|
503             emit "mvn #{temporary}, #0\n"
504             emit "eor #{register}, #{register}, #{temporary}\n"
505           end
506         else
507           if binop? op
508             eval_binop expr, register
509           else
510             raise "Not a magic word: #{op}"
511           end
512         end
513       end
514     end
516     # Export symbols from the current section
517     def export *symbols
518       symbols.each { |sym| emit ".globl #{sym}\n" }
519     end
521     # Load byte from _base_ + _offset_ into _register_
522     def get_byte base, offset, register
523       # If base is an integer, but offset isn't, swap them
524       if !integer?(offset) && integer?(base)
525         base, offset = [offset, base]
526       end
528       if integer? offset
529         with_temporary do |temporary|
530           base_reg = load_value base, temporary
531           if offset == 0
532             emit "ldrb #{register}, [#{base_reg}]\n"
533           else
534             emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
535           end
536         end
537       else
538         with_temporaries(2) do |t1,t2|
539           base_reg = load_value base, t1
540           offset_reg = load_value offset, t2
541           emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
542         end
543       end
544     end
546     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
547     def get_word base, offset, register
548       if integer? offset
549         with_temporary do |temporary|
550           base_reg = load_value base, temporary
551           if offset == 0
552             emit "ldr #{register}, [#{base_reg}]\n"
553           else
554             emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
555           end
556         end
557       else
558         with_temporaries(2) do |t1,t2|
559           base_reg = load_value base, t1
560           offset_reg = load_value offset, t2
561           emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
562         end
563       end
564     end
566     # Jump to a label.
567     def goto label
568       if global? label
569         emit "b #{label}\n"
570       else
571         with_temporary do |temporary|
572           register = load_value label, temporary
573           emit "cpy pc, #{register}\n"
574         end
575       end
577       # If we have constants that need to be emitted, do so now
578       emit_constants
579     end
581     # Grows the current frame by n words, plus padding to
582     # respect alignment rules.
583     def grow_frame nwords
584       increment = stack_align(nwords * @WORDSIZE)
585       emit "sub sp, sp, \##{increment}\n"
586       @frame_size = @frame_size + increment
587       @frame_offset = @frame_offset + increment
588     end
590     # Start the false path of a conditional.
591     def ifelse
592       newlabel = @environment.gensym
593       goto newlabel
594       lbl = @if_labels.pop
595       label lbl
596       @if_labels.push newlabel
597     end
599     # Test if x is equal to y
600     def ifeq x, y
601       common_if :ifeq, x, y
602     end
604     # Test if x is greater than or equal to y
605     def ifge x, y
606       common_if :ifge, x, y
607     end
609     # Test if x is strictly greater than y
610     def ifgt x, y
611       common_if :ifgt, x, y
612     end
614     # Test if x is less than or equal to y
615     def ifle x, y
616       common_if :ifle, x, y
617     end
619     # Test if x is strictly less than y
620     def iflt x, y
621       common_if :iflt, x, y
622     end
624     # Test if x different from y
625     def ifne x, y
626       common_if :ifne, x, y
627     end
629     # Import labels into the current section
630     def import *symbols
631       # Record imported labels in @imports
632       symbols.each { |sym| @imports[sym] = sym }
633     end
635     # Emit a label
636     def label name
637       emit "#{name}:\n"
638     end
640     # Introduce a new local variable
641     def let symbol, *expr
642       n = @environment.locals
643       register = local_register n
645       if register
646         # We will use a register to store the value
647         @environment.add_local symbol, register
648         eval_expr expr, register
649       else
650         # We will use the stack to store the value
651         offset = local_offset n
652         @environment.add_local symbol, offset
653         with_temporary do |temporary|
654           eval_expr expr, temporary
655           emit "str #{temporary}, #{offset_reference offset}\n"
656         end
657       end
658     end
660     # Loads the value at the given address.
661     def load_at address, register
662       load_value_into_register address, register
663       emit "ldr #{register}, [#{register}]\n"
664       register
665     end
667     # Loads a value into some register.
668     # If the value is already in a register, does nothing.
669     # Else, loads the value into the register given as the
670     # second argument.
671     # Returns the name of the register the value is in.
672     def load_value x, register
673       ref = value_ref x, register
674       if register? ref
675         ref
676       else
677         emit "mov #{register}, #{ref}\n"
678         register
679       end
680     end
682     # Loads a value into a specific register.
683     def load_value_into_register x, register
684       ref = value_ref x, register
685       if ref != register
686         if register? ref
687           emit "cpy #{register}, #{ref}\n"
688         else
689           emit "mov #{register}, #{ref}\n"
690         end
691       end
692       register
693     end
695     # Returns the fp-relative reference for the nth (0-based) local.
696     def local_offset n
697       -@INITIAL_FRAME_SIZE - ((n + number_of_register_arguments) * @WORDSIZE)
698     end
699     
700     # Given an offset, returns an fp-relative reference.
701     def offset_reference offset
702       "[#{@FP}, \##{offset}]"
703     end
705     # Returns true if the nth (0-based) local is stored in a register
706     def register_local? n
707       (n + number_of_register_arguments) < @NREGISTER_LOCALS
708     end
710     # Returns from a function.
711     # 
712     # _words_ may contain an expression to be evaluated. The result
713     # of the evaluation is returned from the function.
714     def ret *words
715       # Compute return value and store it in @RETURN
716       eval_expr(words, @RETURN) unless words.empty?
717       # Go to epilogue
718       goto @function_end_label
719     end
721     # Set a variable to the result of evaluating an expression
722     def set symbol, *expr
723       if at_expr? symbol
724         with_temporaries(2) do |t1,t2|
725           eval_expr expr, t1
726           register = load_value symbol[1], t2
727           emit "str #{t1}, [#{register}]\n"
728         end
729       else
730         x = @environment[symbol]
731         if x == nil
732           raise "Cannot change value of constant #{symbol}"
733         elsif x.kind_of? Symbol
734           eval_expr expr, x
735         else
736           with_temporary do |temporary|
737             eval_expr expr, temporary
738             emit "str #{temporary}, #{offset_reference x}\n"
739           end
740         end
741       end
742     end
744     # Set the byte at _base_ + _offset_ to _value_
745     def set_byte base, offset, value
746       # If base is an integer, but offset isn't, swap them
747       if !integer?(offset) && integer?(base)
748         base, offset = [offset, base]
749       end
751       if integer? offset
752         base_reg = load_value base, :a4
753         with_temporary do |temporary|
754           load_value_into_register value, temporary
755           if offset == 0
756             emit "strb #{temporary}, [#{base_reg}]\n"
757           else
758             emit "strb #{temporary}, [#{base_reg}, \##{offset}]\n"
759           end
760         end
761       else
762         eval_binop [:add, base, offset], :a4
763         with_temporary do |temporary|
764           load_value_into_register value, temporary
765           emit "strb #{temporary}, [a4]\n"
766         end
767       end
768     end
770     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
771     def set_word base, offset, value
772       # If base is an integer, but offset isn't, swap them
773       if !integer?(offset) && integer?(base)
774         base, offset = [offset, base]
775       end
777       if integer? offset
778         base_reg = load_value base, :a4
779         with_temporary do |temporary|
780           load_value_into_register value, temporary
781           if offset == 0
782             emit "str #{temporary}, [#{base_reg}]\n"
783           else
784             emit "str #{temporary}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
785           end
786         end
787       else
788         load_value_into_register base, :a4
789         with_temporary do |temporary|
790           load_value_into_register offset, temporary
791           emit "add a4, a4, #{temporary}, LSL #2\n"
792           load_value_into_register value, temporary
793           emit "str #{temporary}, [a4]\n"
794         end
795       end
796     end
798     # Define a string with the given value
799     def string value
800       code = ''
801       value.each_byte do |b|
802         if b == 92
803           code << "\\\\"
804         elsif b >= 32 && b < 127 && b != 34
805           code << b.chr
806         else
807           code << sprintf("\\%03o", b)
808         end
809       end
810       emit ".ascii \"#{code}\"\n"
811     end
813     # Call a function, re-using the current call frame if possible.
814     def tail_call func, *args
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             with_temporary do |temporary|
870               emit "ldr #{temporary}, [sp, \##{saved}]\n"
871               emit "str #{temporary}, #{arg_reference i}\n"
872             end
873           else
874             # Regular value, use load_value
875             with_temporary do |temporary|
876               reg = load_value arg, temporary
877               emit "str #{reg}, #{arg_reference i}\n"
878             end
879           end
880         end
881       end
883       with_temporary do |temporary|
884         # Load address of function to be called
885         load_value_into_register func, temporary
887         # Destroy current activation frame and enter func
888         destroy_frame false
889         emit "bx #{temporary}\n"
890       end
891       emit_constants
892     end
894     # Returns a reference to a value.
895     # For immediate values that fit in 8 bits, this returns the
896     # value itself (in ARM syntax).
897     # For all other values, loads the value into a register and
898     # returns the name of the register. If the value is already
899     # in a register, the name of that register is returned. Else,
900     # the value is loaded into the register specified as the
901     # second argument.
902     def value_ref x, register
903       if substitution? x
904         x = substitute_number x[1]
905       end
906         
907       if integer? x
908         if x >= 0 && x <= 255
909           return "\##{x}"
910         elsif x >= -255 && x < 0
911           emit "mvn #{register}, \##{-(x + 1)}\n"
912           return register
913         else
914           lbl = add_constant x
915           emit "ldr #{register}, #{lbl}\n"
916           return register
917         end
918       elsif symbol? x
919         binding = @environment[x]
920         if binding.kind_of? Symbol
921           # Value is already in a register. Return register name.
922           return binding
923         elsif binding.kind_of? Integer
924           # Value is on the stack. Load from the stack.
925           emit "ldr #{register}, #{offset_reference binding}\n"
926           return register
927         else
928           # Assume global
929           lbl = add_constant x
930           emit "ldr #{register}, #{lbl}\n"
931           return register
932         end
933       elsif at_expr? x
934         load_at x[1], register
935       else
936         raise "Don't know how to load #{x.inspect}"
937       end
938     end
940     # Define a word with the given value
941     def word value
942       emit ".int #{value}\n"
943     end
945   end
947   # Register class for little endian ARM
948   Voodoo::CodeGenerator.register_generator ARMGasGenerator,
949                                            :architecture => :arm,
950                                            :format => :gas