On ARM, don't generate mul with dest equal to first source
[voodoo-lang.git] / lib / voodoo / generators / arm_gas_generator.rb
blob9b64a4bd8230b61cb971d29ee2ba8824c7e91437
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       @SAVE_FRAME_REGISTERS = [:r4, :r5, :r6, :r7, :r8, :r9,
71                                :r10, :r11, :r13, :r14]
72       @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
73       @NREGISTER_ARGS = 4
74       @NREGISTER_LOCALS = 6
75       @FP = :r11
76       @RETURN = :r0
77       @TEMPORARY = :r12
78       @constants = []
79       @frame_offset = 0
80       @frame_size = 0
81       @function_end_label = nil
82       @imports = {}
83       @if_labels = []
84       @saved_registers = []       # registers we've saved in the current frame
85       super params
86       @output_file_suffix = '.s'
87       @features.merge! \
88         :'bits-per-word' => '32',
89         :'byte-order' => 'little-endian',
90         :'bytes-per-word' => 4
91     end
93     # Create an entry in the constants table,
94     # returning the label that will refer to the constant.
95     # The value may be an integer or a label.
96     def add_constant value
97       label = gensym
98       @constants << [label, value]
99       label
100     end
102     def align alignment = nil
103       unless alignment
104         # Get default alignment
105         case @section
106         when :code
107           alignment = @CODE_ALIGNMENT
108         when :data
109           alignment = @DATA_ALIGNMENT
110         when :function
111           alignment = @FUNCTION_ALIGNMENT
112         else
113           # Use data alignment as default
114           alignment = @DATA_ALIGNMENT
115         end
116       end
117       emit ".align #{alignment}\n" unless alignment == 0
118     end
120     # Returns the fp-relative offset for the nth (0-based) argument.
121     def arg_offset n
122       (n - @NREGISTER_ARGS) * @WORDSIZE
123     end
124     
125     # Returns an fp-relative reference for the nth (0-based) argument.
126     def arg_reference n
127       offset_reference arg_offset(n)
128     end
130     # Return the register in which the nth (0-based) argument is stored, or
131     # nil if not stored in a register
132     def arg_register n
133       # The first @NREGISTER_ARGS arguments are in the v registers,
134       # the rest are on the stack.
135       if register_arg? n
136         "v#{n + 1}"
137       else
138         nil
139       end
140     end
142     def auto_bytes value, register
143       if value.kind_of? Integer
144         grow_frame value
145       else
146         temporary = register == :sp ? @TEMPORARY : register
147         load_value_into_register value, temporary
148         auto_bytes_register temporary
149       end
150       emit "cpy #{register}, sp\n" unless register == :sp
151     end
152     
153     # auto-bytes where the value is supplied in a register and the return
154     # value will be in sp. register must not be sp.
155     def auto_bytes_register register
156       temporary = register == @TEMPORARY ? :r3 : @TEMPORARY
157       emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
158       emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
159       emit "and #{register}, #{register}, #{temporary}\n"
160       emit "sub sp, #{register}\n"
161     end
162     
163     def auto_words value, register
164       if value.kind_of? Integer
165         auto_bytes(value * @WORDSIZE, register)
166       else
167         temporary = register == :sp ? @TEMPORARY : register
168         load_value_into_register value, temporary
169         emit "lsl #{temporary}, #{temporary}, \##{@WORDSIZE_BITS}\n"
170         auto_bytes_register temporary
171         emit "cpy #{register}, sp\n" unless register == :sp
172       end
173     end
174     
175     # Begins a new block.
176     def begin_block *code
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       environment = Environment.new @environment
193       formals.each_with_index do |formal, i|
194         if i < @NREGISTER_ARGS
195           environment.add_arg formal, arg_register(i)
196         else
197           environment.add_arg formal, arg_offset(i)
198         end
199       end
200       @environment = environment
201       emit_function_prologue formals, nlocals
202     end
204     # Define a byte with the given value
205     def byte value
206       emit ".byte #{value}\n"
207     end
209     # Call a function.
210     def call func, *args
211       # Calculate how many arguments need to be pushed on
212       # the stack, and allocate space for them.
213       nstack_args = number_of_stack_arguments args.length
214       old_frame_offset = @frame_offset
215       old_frame_size = @frame_size
216       grow_frame nstack_args if nstack_args > 0
218       # Put stack arguments on the stack
219       (@NREGISTER_ARGS...args.length).each do |n|
220         load_value_into_register args[n], @TEMPORARY
221         emit "str #{@TEMPORARY}, " +
222           "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
223       end
225       # Put register arguments in the right registers
226       nregister_args = number_of_register_arguments args.length
227       nregister_args.times do |n|
228           load_value_into_register args[n], :"a#{n + 1}"        
229       end
231       # Call function
232       if global? func
233         emit "bl #{func}\n"
234       else
235         func_reg = load_value func
236         emit "blx #{func_reg}\n"
237       end
239       # Restore original stack frame
240       if old_frame_size != @frame_size
241         emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
242         @frame_offset = old_frame_offset
243         @frame_size = old_frame_size
244       end
245     end
247     # Creates a stack frame for the given number of arguments
248     # and local variables.
249     def create_frame nvars, save_lr = true
250       # Calculate how many variables we will store in registers,
251       # and how many on the stack.
252       nregister_vars = [nvars, @NREGISTER_LOCALS].min
253       nstack_vars = nvars - nregister_vars
255       # Save the registers we will clobber to the stack.
256       clobbered = []
257       nregister_vars.times do |i|
258         clobbered << :"v#{i < 5 ? i + 1 : i + 2}"
259       end
260       clobbered << @FP
261       clobbered << :lr if save_lr
262       @saved_registers = clobbered
263       emit "stmfd sp!, {#{clobbered.join ', '}}\n"
264       emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
266       # Calculate frame size so that the stack pointer will
267       # be properly aligned at the end of emit_function_prologue.
268       @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
269       extra_space = @frame_size - clobbered.length * @WORDSIZE
270       if extra_space > 0
271         emit "sub sp, sp, \##{extra_space}\n"
272       end
273       @frame_offset = 0
274     end
276     # Emits a comment.
277     def comment text
278       emit "# #{text}\n"
279     end
281     # Start a conditional using the specified branch instruction
282     # after the comparison.
283     def common_if comp, x, y = nil
284       emit "# #{comp} #{x} #{y}\n"
286       xreg = load_value x, @TEMPORARY
287       yreg = load_value y, :a4
289       falselabel = @environment.gensym
290       @if_labels.push falselabel
292       emit "cmp #{xreg}, #{yreg}\n"
294       lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
295         :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
296       emit "#{lut[comp]} #{falselabel}\n"
297     end
299     # Destroys the current stack frame.
300     # If ret is true, loads the saved value of lr into pc.
301     def destroy_frame ret = false
302       # Set sp back to where saved registers were stored
303       saved = @saved_registers
304       emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
306       if ret
307         index = saved.index :lr
308         if index
309           saved[index] = :pc
310         else
311           raise "Request to load saved lr into pc, but lr has not been saved"
312         end
313       end
314       emit "ldmfd sp!, {#{saved.join ', '}}\n"
315       
316       emit_constants if ret
317     end
319     # Writes any constants that need to be written to the instruction
320     # stream, and clears the list of constants that need to be written.
321     def emit_constants
322       @constants.each do |x|
323         label x[0]
324         word x[1]
325       end
326       @constants = []
327     end
329     # Emit function prologue.
330     def emit_function_prologue formals = [], nlocals = 0
331       # Calculate the number of arguments we were passed in
332       # registers, the total number of values we need to save
333       # on the stack, then create a stack frame and save
334       # the v registers we will be using.
335       nregister_args = [formals.length, @NREGISTER_ARGS].min
336       nvars = nregister_args + nlocals
337       create_frame nvars, true
339       # Move arguments that were passed in registers into
340       # callee-save registers.
341       nregister_args.times do |i|
342         emit "cpy v#{i + 1}, a#{i + 1}\n"
343       end
344     end
346     # Ends the current block.
347     def end_block
348       emit "# end block\n"
350       # If we are returning to top level, restore stack pointer
351       # and saved registers.
352       if @environment.parent == @top_level
353         offset = @frame_size - @saved_registers.length * @WORDSIZE
354         if offset > 0
355           emit "add sp, sp, \##{offset}\n"
356         end
357         emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
358         @frame_size = 0
359         @frame_offset = 0
360         @saved_registers = []
362         # If we need to emit constants, do so now
363         unless @constants.empty?
364           lbl = gensym
365           goto lbl
366           label lbl
367         end
368       end
370       # Restore old value of @environment
371       @environment = @environment.parent
372     end
374     # Ends a function body.
375     def end_function
376       if @environment == @top_level
377         raise "Cannot end function when not in a function"
378       end
380       emit "# function epilogue\n"
381       label @function_end_label
383       destroy_frame true
384       @frame_size = 0
385       @frame_offset = 0
386       @saved_registers = []
387       emit "# end function\n\n"
388       @environment = @top_level
389     end
391     # Ends a conditional.
392     def end_if
393       label @if_labels.pop
394     end
396     # Evaluate the binary operation expr and store the result in register
397     def eval_binop expr, register
398       op = expr[0]
400       # Emulation for div and mod, which ARM does not have instructions for
401       case op
402       when :div
403         func = :"__aeabi_idiv"
404         import func unless @imports.has_key? func
405         call func, expr[1], expr[2]
406         emit "cpy #{register}, r0\n" if register != :r0
407         return
408       when :mod
409         func = :"__aeabi_idivmod"
410         import func unless @imports.has_key? func
411         call func, expr[1], expr[2]
412         emit "cpy #{register}, r1\n" if register != :r1
413         return
414       end
416       x = load_value expr[1], :a4
417       y = load_value expr[2], @TEMPORARY
419       case op
420       when :bsr
421         emit "lsr #{register}, #{x}, #{y}\n"
422       when :or
423         emit "orr #{register}, #{x}, #{y}\n"
424       when :mul
425         # Can't store result in same register as first operand.
426         if register == x
427           if x == y
428             # All using the same register. Move x to a different
429             # register to make this work.
430             temp = (x == @TEMPORARY) ? :a4 : @TEMPORARY
431             emit "cpy #{temp}, #{x}\n"
432             emit "mul #{register}, #{temp}, #{y}\n"
433           else
434             # Multiplication is commutative. Just swap x and y.
435             emit "mul #{register}, #{y}, #{x}\n"
436           end
437         else
438           # Common case, register and x are different.
439           emit "mul #{register}, #{x}, #{y}\n"
440         end
441       when :rol
442         emit "rsb #{y}, #{y}, #32\n"
443         emit "ror #{register}, #{x}, #{y}\n"
444       when :shl
445         emit "lsl #{register}, #{x}, #{y}\n"
446       when :shr
447         emit "lsr #{register}, #{x}, #{y}\n"
448       when :xor
449         emit "eor #{register}, #{x}, #{y}\n"
450       else
451         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
452       end
453     end
455     # Evaluates the expression +expr+ and stores the result in +register+.
456     def eval_expr expr, register
457       if expr.length == 1
458         # Load value
459         load_value_into_register expr[0], register
460       else
461         # Evaluate expression
462         op = expr[0]
463         case op
464         when :'auto-bytes'
465           auto_bytes expr[1], register
466         when :'auto-words'
467           auto_words expr[1], register
468         when :call
469           call *expr[1..-1]
470           emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
471         when :'get-byte'
472           get_byte expr[1], expr[2], register
473         when :'get-word'
474           get_word expr[1], expr[2], register
475         when :not
476           load_value_into_register expr[1], register
477           emit "mvn #{@TEMPORARY}, #0\n"
478           emit "eor #{register}, #{register}, #{@TEMPORARY}\n"
479         else
480           if binop? op
481             eval_binop expr, register
482           else
483             raise "Not a magic word: #{op}"
484           end
485         end
486       end
487     end
489     # Export symbols from the current section
490     def export *symbols
491       symbols.each { |sym| emit ".globl #{sym}\n" }
492     end
494     # Load byte from _base_ + _offset_ into _register_
495     def get_byte base, offset, register
496       # If base is an integer, but offset isn't, swap them
497       if !integer?(offset) && integer?(base)
498         base, offset = [offset, base]
499       end
501       if integer? offset
502         base_reg = load_value base
503         if offset == 0
504           emit "ldrb #{register}, [#{base_reg}]\n"
505         else
506           emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
507         end
508       else
509         base_reg = load_value base
510         offset_reg = load_value offset, :a4
511         emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
512       end
513     end
515     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
516     def get_word base, offset, register
517       if integer? offset
518         base_reg = load_value base
519         if offset == 0
520           emit "ldr #{register}, [#{base_reg}]\n"
521         else
522           emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
523         end
524       else
525         base_reg = load_value base
526         offset_reg = load_value offset, :a4
527         emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
528       end
529     end
531     # Jump to a label.
532     def goto label
533       if global? label
534         emit "b #{label}\n"
535       else
536         register = load_value label
537         emit "cpy pc, #{register}\n"
538       end
540       # If we have constants that need to be emitted, do so now
541       emit_constants
542     end
544     # Grows the current frame by n words, plus padding to
545     # respect alignment rules.
546     def grow_frame nwords
547       increment = stack_align(nwords * @WORDSIZE)
548       emit "sub sp, sp, \##{increment}\n"
549       @frame_size = @frame_size + increment
550       @frame_offset = @frame_offset + increment
551     end
553     # Start the false path of a conditional.
554     def ifelse
555       emit "# else\n"
556       newlabel = @environment.gensym
557       goto newlabel
558       lbl = @if_labels.pop
559       label lbl
560       @if_labels.push newlabel
561     end
563     # Test if x is equal to y
564     def ifeq x, y
565       common_if :ifeq, x, y
566     end
568     # Test if x is greater than or equal to y
569     def ifge x, y
570       common_if :ifge, x, y
571     end
573     # Test if x is strictly greater than y
574     def ifgt x, y
575       common_if :ifgt, x, y
576     end
578     # Test if x is less than or equal to y
579     def ifle x, y
580       common_if :ifle, x, y
581     end
583     # Test if x is strictly less than y
584     def iflt x, y
585       common_if :iflt, x, y
586     end
588     # Test if x different from y
589     def ifne x, y
590       common_if :ifne, x, y
591     end
593     # Import labels into the current section
594     def import *symbols
595       # Record imported labels in @imports
596       symbols.each { |sym| @imports[sym] = sym }
597     end
599     # Emit a label
600     def label name
601       emit "#{name}:\n"
602     end
604     # Introduce a new local variable
605     def let symbol, *expr
606       n = @environment.locals
607       register = local_register n
609       if register
610         # We will use a register to store the value
611         @environment.add_local symbol, register
612         eval_expr expr, register
613       else
614         # We will use the stack to store the value
615         offset = local_offset n
616         @environment.add_local symbol, offset
617         eval_expr expr, @TEMPORARY
618         emit "str #{@TEMPORARY}, #{offset_reference offset}\n"
619       end
620     end
622     # Load the value at the given address.
623     def load_at address, register = @TEMPORARY
624       load_value_into_register address, register
625       emit "ldr #{register}, [#{register}]\n"
626       register
627     end
629     # Load a value into a register.
630     # Returns the name of the register.
631     # If the value was already in a register, the name of that
632     # register is returned.
633     # Else, the value is loaded into a register and the name of
634     # that register is returned. The register to use in that case
635     # may be specified using the optional second argument.
636     def load_value x, register = @TEMPORARY
637       if substitution? x
638         x = substitute_number x[1]
639       end
640         
641       if integer? x
642         if x >= 0 && x <= 255
643           emit "mov #{register}, \##{x}\n"
644           return register
645         elsif x >= -255 && x < 0
646           emit "mvn #{register}, \##{-(x + 1)}\n"
647           return register
648         else
649           lbl = add_constant x
650           emit "ldr #{register}, #{lbl}\n"
651           return register
652         end
653       elsif symbol? x
654         binding = @environment[x]
655         if binding.kind_of? String
656           # Value is already in a register. Return register name.
657           return binding
658         elsif binding.kind_of? Integer
659           # Value is on the stack. Load from the stack.
660           emit "ldr #{register}, #{offset_reference binding}\n"
661           return register
662         else
663           # Assume global
664           lbl = add_constant x
665           emit "ldr #{register}, #{lbl}\n"
666           return register
667         end
668       elsif at_expr? x
669         load_at x[1], register
670       else
671         raise "Don't know how to load #{x.inspect}"
672       end
673     end
675     # Load a value into a specific register
676     def load_value_into_register x, register
677       reg = load_value x, register
678       if reg != register
679         emit "cpy #{register}, #{reg}\n"
680       end
681     end
683     # Returns the fp-relative reference for the nth (0-based) local.
684     def local_offset n
685       -@INITIAL_FRAME_SIZE - (n * @WORDSIZE)
686     end
687     
688     # Return the register in which the nth local (0-based) is stored, or
689     # nil if not stored in a register
690     def local_register n
691       if register_local? n
692         n = n + number_of_register_arguments
693         if n < 5
694           "v#{n + 1}"
695         else
696           "v#{n + 2}"
697         end
698       else
699         nil
700       end
701     end
703     # Calculate the number of register arguments,
704     # given the total number of arguments.
705     def number_of_register_arguments n = @environment.args
706       [n, @NREGISTER_ARGS].min
707     end
709     # Calculate the number of stack arguments,
710     # given the total number of arguments.
711     def number_of_stack_arguments n = @environment.args
712       [0, n - @NREGISTER_ARGS].max
713     end
715     # Given an offset, returns an fp-relative reference.
716     def offset_reference offset
717       "[#{@FP}, \##{offset}]"
718     end
720     # Returns true if the nth (0-based) argument is stored in a register
721     def register_arg? n
722       n < @NREGISTER_ARGS
723     end
725     # Returns true if the nth (0-based) local is stored in a register
726     def register_local? n
727       (n + number_of_register_arguments) < @NREGISTER_LOCALS
728     end
730     # Restores the frame saved at the given location.
731     def restore_frame location
732       load_value_into_register location, @TEMPORARY
733       @SAVE_FRAME_REGISTERS.each_with_index do |register,i|
734         emit "ldr #{register}, [#{@TEMPORARY}, \##{i * @WORDSIZE}]\n"
735       end
736     end
737     
738     # Returns from a function.
739     # 
740     # _words_ may contain an expression to be evaluated. The result
741     # of the evaluation is returned from the function.
742     def ret *words
743       # Compute return value and store it in @RETURN
744       eval_expr(words, @RETURN) unless words.empty?
745       # Go to epilogue
746       goto @function_end_label
747     end
749     # Saves the current frame to the given location.
750     def save_frame location
751       load_value_into_register location, @TEMPORARY
752       @SAVE_FRAME_REGISTERS.each_with_index do |register,i|
753         emit "str #{register}, [#{@TEMPORARY}, \##{i * @WORDSIZE}]\n"
754       end
755     end
756     
757     # Returns the number of bytes necessary to save the current frame.
758     def saved_frame_size
759       @SAVE_FRAME_REGISTERS.length * @WORDSIZE
760     end
761     
762     # Set a variable to the result of evaluating an expression
763     def set symbol, *expr
764       if at_expr? symbol
765         eval_expr expr, :r3
766         register = load_value symbol[1]
767         emit "str r3, [#{register}]\n"
768       else
769         x = @environment[symbol]
770         if x == nil
771           raise "Cannot change value of constant #{symbol}"
772         elsif x.kind_of? String
773           eval_expr expr, x
774         else
775           eval_expr expr, @TEMPORARY
776           emit "str #{@TEMPORARY}, #{offset_reference x}\n"
777         end
778       end
779     end
781     # Set the byte at _base_ + _offset_ to _value_
782     def set_byte base, offset, value
783       emit "# set-byte #{base} #{offset} #{value}\n"
784       # If base is an integer, but offset isn't, swap them
785       if !integer?(offset) && integer?(base)
786         base, offset = [offset, base]
787       end
789       if integer? offset
790         base_reg = load_value base, :a4
791         load_value_into_register value, @TEMPORARY
792         if offset == 0
793           emit "strb #{@TEMPORARY}, [#{base_reg}]\n"
794         else
795           emit "strb #{@TEMPORARY}, [#{base_reg}, \##{offset}]\n"
796         end
797       else
798         eval_binop [:add, base, offset], :a4
799         load_value_into_register value, @TEMPORARY
800         emit "strb #{@TEMPORARY}, [a4]\n"
801       end
802     end
804     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
805     def set_word base, offset, value
806       # If base is an integer, but offset isn't, swap them
807       if !integer?(offset) && integer?(base)
808         base, offset = [offset, base]
809       end
811       if integer? offset
812         base_reg = load_value base, :a4
813         load_value_into_register value, @TEMPORARY
814         if offset == 0
815           emit "str #{@TEMPORARY}, [#{base_reg}]\n"
816         else
817           emit "str #{@TEMPORARY}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
818         end
819       else
820         load_value_into_register base, :a4
821         load_value_into_register offset, @TEMPORARY
822         emit "add a4, a4, #{@TEMPORARY}, LSL #2\n"
823         load_value_into_register value, @TEMPORARY
824         emit "str #{@TEMPORARY}, [a4]\n"
825       end
826     end
828     # Given n, returns the nearest multiple of @STACK_ALIGNMENT
829     # that is >= n.
830     def stack_align n
831       (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
832     end
833     
834     # Define a string with the given value
835     def string value
836       code = ''
837       value.each_byte do |b|
838         if b == 92
839           code << "\\\\"
840         elsif b >= 32 && b < 127 && b != 34
841           code << b.chr
842         else
843           code << sprintf("\\%03o", b)
844         end
845       end
846       emit ".ascii \"#{code}\"\n"
847     end
849     # Call a function, re-using the current call frame if possible.
850     def tail_call func, *args
851       emit "# tail-call #{func} #{args.join ' '}\n"      
853       # Compute number of stack arguments
854       nstackargs = number_of_stack_arguments args.length
855       # If we need more stack arguments than we have now,
856       # perform a normal call and return
857       if nstackargs > number_of_stack_arguments(@environment.args)
858         emit "# Not enough space for proper tail call; using regular call\n"
859         ret :call, func, *args
860       end
862       # We will assign arguments from left to right.
863       # Find places that we will overwrite before we read them,
864       # and store their values in some newly allocated stack space.
865       old_frame_offset = @frame_offset
866       old_frame_size = @frame_size
867       overwritten = {}
868       (@NREGISTER_ARGS...args.length).each do |i|
869         arg = args[i]
870         arg = arg[1] if at_expr? arg
871         if symbol?(arg)
872           binding = @environment[arg]
873           if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
874               binding[1] < i
875             # Argument i is a stack argument, but the value we will assign
876             # it is a stack argument that comes before it, so we will
877             # have overwritten it by the time we get to it.
878             overwritten[arg] = nil
879           end
880         end
881       end
882       
883       unless overwritten.empty?
884         # Allocate space for arguments to be saved
885         grow_frame overwritten.length
886         # Save values
887         offset = 0
888         overwritten.each_key do |key|
889           reg = load_value key
890           emit "str #{reg}, [sp, \##{offset}]\n"
891           overwritten[key] = offset
892           offset = offset + @WORDSIZE
893         end
894       end
896       # Assign arguments
897       args.each_index do |i|
898         arg = args[i]
899         if register_arg? i
900           load_value_into_register arg, "a#{i + 1}"
901         else
902           # Test if this is a value we saved
903           sym = at_expr?(arg) ? arg[1] : arg
904           saved = overwritten[sym]
905           if saved
906             # Saved value, load from stack
907             reg = @TEMPORARY
908             emit "ldr #{reg}, [sp, \##{saved}]\n"
909           else
910             # Regular value, use load_value
911             reg = load_value arg
912           end
913           emit "str #{reg}, #{arg_reference i}\n"
914         end
915       end
917       # Load address of function to be called into @TEMPORARY
918       load_value_into_register func, @TEMPORARY
920       # Destroy current activation frame and enter func
921       destroy_frame false
922       emit "bx #{@TEMPORARY}\n"
923       emit_constants
924     end
926     # Define a word with the given value
927     def word value
928       emit ".int #{value}\n"
929     end
931   end
933   # Register class for little endian ARM
934   Voodoo::CodeGenerator.register_generator ARMGasGenerator,
935                                            :architecture => :arm,
936                                            :format => :gas