Made auto-bytes and auto-words work with variable arguments on ARM
[voodoo-lang.git] / lib / voodoo / generators / arm_gas_generator.rb
bloba8d5598a7f3248fe2e58aa3ad2d2257dc7c25d5f
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     # Test if op is a binary operation
142     def assymetric_binop? op
143       [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op)
144     end
146     # Test if a value is an at-expression
147     def at_expr? value
148       value.respond_to?(:[]) && value[0] == :'@'
149     end
151     def auto_bytes value, register
152       if value.kind_of? Integer
153         grow_frame value
154       else
155         temporary = register == :sp ? @TEMPORARY : register
156         load_value_into_register value, temporary
157         auto_bytes_register temporary
158       end
159       emit "cpy #{register}, sp\n" unless register == :sp
160     end
161     
162     # auto-bytes where the value is supplied in a register and the return
163     # value will be in sp. register must not be sp.
164     def auto_bytes_register register
165       temporary = register == @TEMPORARY ? :r3 : @TEMPORARY
166       emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
167       emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
168       emit "and #{register}, #{register}, #{temporary}\n"
169       emit "sub sp, #{register}\n"
170     end
171     
172     def auto_words value, register
173       if value.kind_of? Integer
174         auto_bytes(value * @WORDSIZE, register)
175       else
176         temporary = register == :sp ? @TEMPORARY : register
177         load_value_into_register value, temporary
178         emit "lsl #{temporary}, #{temporary}, \##{@WORDSIZE_BITS}\n"
179         auto_bytes_register temporary
180         emit "cpy #{register}, sp\n" unless register == :sp
181       end
182     end
183     
184     # Begins a new block.
185     def begin_block *code
186       emit "# begin block\n"
187       # If we are starting a block at top level, create a frame
188       if @environment == @top_level
189         nlocals = count_locals code
190         create_frame nlocals, false
191       end
192       @environment = Environment.new @environment
193     end
195     # Emit function prologue and declare _formals_ as function arguments
196     def begin_function formals, nlocals
197       if @environment != @top_level
198         raise "Can only begin a function at top level"
199       end
201       @function_end_label = gensym
202       emit "# function #{formals.join ' '}\n"
203       environment = Environment.new @environment
204       formals.each_with_index do |formal, i|
205         if i < @NREGISTER_ARGS
206           environment.add_arg formal, arg_register(i)
207         else
208           environment.add_arg formal, arg_offset(i)
209         end
210       end
211       @environment = environment
212       emit_function_prologue formals, nlocals
213     end
215     # Test if op is a binary operation
216     def binop? op
217       assymetric_binop?(op) || symmetric_binop?(op)
218     end
220     # Define a byte with the given value
221     def byte value
222       emit ".byte #{value}\n"
223     end
225     # Call a function.
226     def call func, *args
227       emit "# call #{func} #{args.join ' '}\n"
229       # Calculate how many arguments need to be pushed on
230       # the stack, and allocate space for them.
231       nstack_args = number_of_stack_arguments args.length
232       old_frame_offset = @frame_offset
233       old_frame_size = @frame_size
234       grow_frame nstack_args if nstack_args > 0
236       # Put stack arguments on the stack
237       (@NREGISTER_ARGS...args.length).each do |n|
238         load_value_into_register args[n], @TEMPORARY
239         emit "str #{@TEMPORARY}, " +
240           "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
241       end
243       # Put register arguments in the right registers
244       nregister_args = number_of_register_arguments args.length
245       nregister_args.times do |n|
246           load_value_into_register args[n], :"a#{n + 1}"        
247       end
249       # Call function
250       if global? func
251         emit "bl #{func}\n"
252       else
253         func_reg = load_value func
254         emit "blx #{func_reg}\n"
255       end
257       # Restore original stack frame
258       if old_frame_size != @frame_size
259         emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
260         @frame_offset = old_frame_offset
261         @frame_size = old_frame_size
262       end
263     end
265     # Creates a stack frame for the given number of arguments
266     # and local variables.
267     def create_frame nvars, save_lr = true
268       # Calculate how many variables we will store in registers,
269       # and how many on the stack.
270       nregister_vars = [nvars, @NREGISTER_LOCALS].min
271       nstack_vars = nvars - nregister_vars
273       # Save the registers we will clobber to the stack.
274       clobbered = []
275       nregister_vars.times do |i|
276         clobbered << :"v#{i < 5 ? i + 1 : i + 2}"
277       end
278       clobbered << @FP
279       clobbered << :lr if save_lr
280       @saved_registers = clobbered
281       emit "stmfd sp!, {#{clobbered.join ', '}}\n"
282       emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
284       # Calculate frame size so that the stack pointer will
285       # be properly aligned at the end of emit_function_prologue.
286       @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
287       extra_space = @frame_size - clobbered.length * @WORDSIZE
288       if extra_space > 0
289         emit "sub sp, sp, \##{extra_space}\n"
290       end
291       @frame_offset = 0
292     end
294     # Start a conditional using the specified branch instruction
295     # after the comparison.
296     def common_if comp, x, y = nil
297       emit "# #{comp} #{x} #{y}\n"
299       xreg = load_value x, @TEMPORARY
300       yreg = load_value y, :a4
302       falselabel = @environment.gensym
303       @if_labels.push falselabel
305       emit "cmp #{xreg}, #{yreg}\n"
307       lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
308         :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
309       emit "#{lut[comp]} #{falselabel}\n"
310     end
312     # Counts the number of local variables created in
313     # a sequence of statements.
314     def count_locals statements
315        count = 0
316        each_statement(statements) do |statement|
317          if statement[0] == :let
318            # let introduces a single local
319            count = count + 1
320          end
321        end
322        count
323     end
325     # Destroys the current stack frame.
326     # If ret is true, loads the saved value of lr into pc.
327     def destroy_frame ret = false
328       # Set sp back to where saved registers were stored
329       saved = @saved_registers
330       emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
332       if ret
333         index = saved.index :lr
334         if index
335           saved[index] = :pc
336         else
337           raise "Request to load saved lr into pc, but lr has not been saved"
338         end
339       end
340       emit "ldmfd sp!, {#{saved.join ', '}}\n"
341       
342       emit_constants if ret
343     end
345     # Writes any constants that need to be written to the instruction
346     # stream, and clears the list of constants that need to be written.
347     def emit_constants
348       @constants.each do |x|
349         label x[0]
350         word x[1]
351       end
352       @constants = []
353     end
355     # Emit function prologue.
356     def emit_function_prologue formals = [], nlocals = 0
357       # Calculate the number of arguments we were passed in
358       # registers, the total number of values we need to save
359       # on the stack, then create a stack frame and save
360       # the v registers we will be using.
361       nregister_args = [formals.length, @NREGISTER_ARGS].min
362       nvars = nregister_args + nlocals
363       create_frame nvars, true
365       # Move arguments that were passed in registers into
366       # callee-save registers.
367       nregister_args.times do |i|
368         emit "cpy v#{i + 1}, a#{i + 1}\n"
369       end
370     end
372     # Ends the current block.
373     def end_block
374       emit "# end block\n"
376       # If we are returning to top level, restore stack pointer
377       # and saved registers.
378       if @environment.parent == @top_level
379         offset = @frame_size - @saved_registers.length * @WORDSIZE
380         if offset > 0
381           emit "add sp, sp, \##{offset}\n"
382         end
383         emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
384         @frame_size = 0
385         @frame_offset = 0
386         @saved_registers = []
388         # If we need to emit constants, do so now
389         unless @constants.empty?
390           lbl = gensym
391           goto lbl
392           label lbl
393         end
394       end
396       # Restore old value of @environment
397       @environment = @environment.parent
398     end
400     # Ends a function body.
401     def end_function
402       if @environment == @top_level
403         raise "Cannot end function when not in a function"
404       end
406       emit "# function epilogue\n"
407       label @function_end_label
409       destroy_frame true
410       @frame_size = 0
411       @frame_offset = 0
412       @saved_registers = []
413       emit "# end function\n\n"
414       @environment = @top_level
415     end
417     # Ends a conditional.
418     def end_if
419       label @if_labels.pop
420     end
422     # Evaluate the binary operation expr and store the result in register
423     def eval_binop expr, register
424       op = expr[0]
426       # Emulation for div and mod, which ARM does not have instructions for
427       case op
428       when :div
429         func = :"__aeabi_idiv"
430         import func unless @imports.has_key? func
431         call func, expr[1], expr[2]
432         emit "cpy #{register}, r0\n" if register != :r0
433         return
434       when :mod
435         func = :"__aeabi_idivmod"
436         import func unless @imports.has_key? func
437         call func, expr[1], expr[2]
438         emit "cpy #{register}, r1\n" if register != :r1
439         return
440       end
442       x = load_value expr[1], :a4
443       y = load_value expr[2], @TEMPORARY
445       case op
446       when :bsr
447         emit "lsr #{register}, #{x}, #{y}\n"
448       when :or
449         emit "orr #{register}, #{x}, #{y}\n"
450       when :rol
451         emit "rsb #{y}, #{y}, #32\n"
452         emit "ror #{register}, #{x}, #{y}\n"
453       when :shl
454         emit "lsl #{register}, #{x}, #{y}\n"
455       when :shr
456         emit "lsr #{register}, #{x}, #{y}\n"
457       when :xor
458         emit "eor #{register}, #{x}, #{y}\n"
459       else
460         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
461       end
462     end
464     # Evaluates the expression +expr+ and stores the result in +register+.
465     def eval_expr expr, register
466       if expr.length == 1
467         # Load value
468         load_value_into_register expr[0], register
469       else
470         # Evaluate expression
471         op = expr[0]
472         case op
473         when :'auto-bytes'
474           auto_bytes expr[1], register
475         when :'auto-words'
476           auto_words expr[1], register
477         when :call
478           call *expr[1..-1]
479           emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
480         when :'get-byte'
481           get_byte expr[1], expr[2], register
482         when :'get-word'
483           get_word expr[1], expr[2], register
484         when :not
485           load_value_into_register expr[1], register
486           emit "mvn #{@TEMPORARY}, #0\n"
487           emit "eor #{register}, #{register}, #{@TEMPORARY}\n"
488         else
489           if binop? op
490             eval_binop expr, register
491           else
492             raise "Not a magic word: #{op}"
493           end
494         end
495       end
496     end
498     # Export symbols from the current section
499     def export *symbols
500       symbols.each { |sym| emit ".globl #{sym}\n" }
501     end
503     # Add a function to the current section
504     def function formals, *code
505       nlocals = count_locals code
506       begin_function formals, nlocals
507       code.each { |action| add section, action }
508       end_function
509     end
511     # Load byte from _base_ + _offset_ into _register_
512     def get_byte base, offset, register
513       # If base is an integer, but offset isn't, swap them
514       if !integer?(offset) && integer?(base)
515         base, offset = [offset, base]
516       end
518       if integer? offset
519         base_reg = load_value base
520         if offset == 0
521           emit "ldrb #{register}, [#{base_reg}]\n"
522         else
523           emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
524         end
525       else
526         base_reg = load_value base
527         offset_reg = load_value offset, :a4
528         emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
529       end
530     end
532     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
533     def get_word base, offset, register
534       if integer? offset
535         base_reg = load_value base
536         if offset == 0
537           emit "ldr #{register}, [#{base_reg}]\n"
538         else
539           emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
540         end
541       else
542         base_reg = load_value base
543         offset_reg = load_value offset, :a4
544         emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
545       end
546     end
548     # Test if a symbol refers to a global
549     def global? symbol
550       symbol?(symbol) && @environment[symbol] == nil
551     end
553     # Jump to a label.
554     def goto label
555       emit "b #{label}\n"
557       # If we have constants that need to be emitted, do so now
558       emit_constants
559     end
561     # Grows the current frame by n words, plus padding to
562     # respect alignment rules.
563     def grow_frame nwords
564       increment = stack_align(nwords * @WORDSIZE)
565       emit "sub sp, sp, \##{increment}\n"
566       @frame_size = @frame_size + increment
567       @frame_offset = @frame_offset + increment
568     end
570     # Start the false path of a conditional.
571     def ifelse
572       emit "# else\n"
573       newlabel = @environment.gensym
574       goto newlabel
575       lbl = @if_labels.pop
576       label lbl
577       @if_labels.push newlabel
578     end
580     # Test if x is equal to y
581     def ifeq x, y
582       common_if :ifeq, x, y
583     end
585     # Test if x is greater than or equal to y
586     def ifge x, y
587       common_if :ifge, x, y
588     end
590     # Test if x is strictly greater than y
591     def ifgt x, y
592       common_if :ifgt, x, y
593     end
595     # Test if x is less than or equal to y
596     def ifle x, y
597       common_if :ifle, x, y
598     end
600     # Test if x is strictly less than y
601     def iflt x, y
602       common_if :iflt, x, y
603     end
605     # Test if x different from y
606     def ifne x, y
607       common_if :ifne, x, y
608     end
610     # Import labels into the current section
611     def import *symbols
612       # Record imported labels in @imports
613       symbols.each { |sym| @imports[sym] = sym }
614     end
616     # Test if a value is an integer
617     def integer? value
618       value.kind_of? Integer
619     end
621     # Emit a label
622     def label name
623       emit "#{name}:\n"
624     end
626     # Introduce a new local variable
627     def let symbol, *expr
628       n = @environment.locals
629       register = local_register n
631       if register
632         # We will use a register to store the value
633         @environment.add_local symbol, register
634         eval_expr expr, register
635       else
636         # We will use the stack to store the value
637         offset = local_offset n
638         @environment.add_local symbol, offset
639         eval_expr expr, @TEMPORARY
640         emit "str #{@TEMPORARY}, #{offset_reference offset}\n"
641       end
642     end
644     # Load the value at the given address.
645     def load_at address, register = @TEMPORARY
646       load_value_into_register address, register
647       emit "ldr #{register}, [#{register}]\n"
648       register
649     end
651     # Load a value into a register.
652     # Returns the name of the register.
653     # If the value was already in a register, the name of that
654     # register is returned.
655     # Else, the value is loaded into a register and the name of
656     # that register is returned. The register to use in that case
657     # may be specified using the optional second argument.
658     def load_value x, register = @TEMPORARY
659       if integer? x
660         if x >= 0 && x <= 255
661           emit "mov #{register}, \##{x}\n"
662           return register
663         elsif x >= -255 && x < 0
664           emit "mvn #{register}, \##{-(x + 1)}\n"
665           return register
666         else
667           lbl = add_constant x
668           emit "ldr #{register}, #{lbl}\n"
669           return register
670         end
671       elsif symbol? x
672         binding = @environment[x]
673         if binding.kind_of? String
674           # Value is already in a register. Return register name.
675           return binding
676         elsif binding.kind_of? Integer
677           # Value is on the stack. Load from the stack.
678           emit "ldr #{register}, #{offset_reference binding}\n"
679           return register
680         else
681           # Assume global
682           lbl = add_constant x
683           emit "ldr #{register}, #{lbl}\n"
684           return register
685         end
686       elsif at_expr? x
687         load_at x[1], register
688       else
689         raise "Don't know how to load #{x.inspect}"
690       end
691     end
693     # Load a value into a specific register
694     def load_value_into_register x, register
695       reg = load_value x, register
696       if reg != register
697         emit "cpy #{register}, #{reg}\n"
698       end
699     end
701     # Returns the fp-relative reference for the nth (0-based) local.
702     def local_offset n
703       -@INITIAL_FRAME_SIZE - (n * @WORDSIZE)
704     end
705     
706     # Return the register in which the nth local (0-based) is stored, or
707     # nil if not stored in a register
708     def local_register n
709       if register_local? n
710         n = n + number_of_register_arguments
711         if n < 5
712           "v#{n + 1}"
713         else
714           "v#{n + 2}"
715         end
716       else
717         nil
718       end
719     end
721     # Calculate the number of register arguments,
722     # given the total number of arguments.
723     def number_of_register_arguments n = @environment.args
724       [n, @NREGISTER_ARGS].min
725     end
727     # Calculate the number of stack arguments,
728     # given the total number of arguments.
729     def number_of_stack_arguments n = @environment.args
730       [0, n - @NREGISTER_ARGS].max
731     end
733     # Given an offset, returns an fp-relative reference.
734     def offset_reference offset
735       "[#{@FP}, \##{offset}]"
736     end
738     # Returns true if the nth (0-based) argument is stored in a register
739     def register_arg? n
740       n < @NREGISTER_ARGS
741     end
743     # Returns true if the nth (0-based) local is stored in a register
744     def register_local? n
745       (n + number_of_register_arguments) < @NREGISTER_LOCALS
746     end
748     # Returns from a function.
749     # 
750     # _words_ may contain an expression to be evaluated. The result
751     # of the evaluation is returned from the function.
752     def ret *words
753       emit "# return #{words.join ' '}\n"
754       # Compute return value and store it in @RETURN
755       eval_expr(words, @RETURN) unless words.empty?
756       # Go to epilogue
757       goto @function_end_label
758     end
759     
760     # Set a variable to the result of evaluating an expression
761     def set symbol, *expr
762       if at_expr? symbol
763         eval_expr expr, :r3
764         register = load_value symbol[1]
765         emit "str r3, [#{register}]\n"
766       else
767         x = @environment[symbol]
768         if x == nil
769           raise "Cannot change value of constant #{symbol}"
770         elsif x.kind_of? String
771           eval_expr expr, x
772         else
773           eval_expr expr, @TEMPORARY
774           emit "str #{@TEMPORARY}, #{offset_reference x}\n"
775         end
776       end
777     end
779     # Set the byte at _base_ + _offset_ to _value_
780     def set_byte base, offset, value
781       emit "# set-byte #{base} #{offset} #{value}\n"
782       # If base is an integer, but offset isn't, swap them
783       if !integer?(offset) && integer?(base)
784         base, offset = [offset, base]
785       end
787       if integer? offset
788         base_reg = load_value base, :a4
789         load_value_into_register value, @TEMPORARY
790         if offset == 0
791           emit "strb #{@TEMPORARY}, [#{base_reg}]\n"
792         else
793           emit "strb #{@TEMPORARY}, [#{base_reg}, \##{offset}]\n"
794         end
795       else
796         eval_binop [:add, base, offset], :a4
797         load_value_into_register value, @TEMPORARY
798         emit "strb #{@TEMPORARY}, [a4]\n"
799       end
800     end
802     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
803     def set_word base, offset, value
804       emit "# set-word #{base} #{offset} #{value}\n"
805       # If base is an integer, but offset isn't, swap them
806       if !integer?(offset) && integer?(base)
807         base, offset = [offset, base]
808       end
810       if integer? offset
811         base_reg = load_value base, :a4
812         load_value_into_register value, @TEMPORARY
813         if offset == 0
814           emit "str #{@TEMPORARY}, [#{base_reg}]\n"
815         else
816           emit "str #{@TEMPORARY}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
817         end
818       else
819         load_value_into_register base, :a4
820         load_value_into_register offset, @TEMPORARY
821         emit "add a4, a4, #{@TEMPORARY}, LSL #2\n"
822         load_value_into_register value, @TEMPORARY
823         emit "str #{@TEMPORARY}, [a4]\n"
824       end
825     end
827     # Given n, returns the nearest multiple of @STACK_ALIGNMENT
828     # that is >= n.
829     def stack_align n
830       (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
831     end
832     
833     # Define a string with the given value
834     def string value
835       code = ''
836       value.each_byte do |b|
837         if b == 92
838           code << "\\\\"
839         elsif b >= 32 && b < 127 && b != 34
840           code << b.chr
841         else
842           code << sprintf("\\%03o", b)
843         end
844       end
845       emit ".ascii \"#{code}\"\n"
846     end
848     # Test if a value is a symbol
849     def symbol? value
850       value.kind_of? Symbol
851     end
853     # Test if op is a symmetric binary operation (i.e. it will yield the
854     # same result if the order of its source operands is changed).
855     def symmetric_binop? op
856       [:add, :and, :mul, :or, :xor].member? op
857     end
859     # Call a function, re-using the current call frame if possible.
860     def tail_call func, *args
861       emit "# tail-call #{func} #{args.join ' '}\n"      
863       # Compute number of stack arguments
864       nstackargs = number_of_stack_arguments args.length
865       # If we need more stack arguments than we have now,
866       # perform a normal call and return
867       if nstackargs > number_of_stack_arguments(@environment.args)
868         emit "# Not enough space for proper tail call; using regular call\n"
869         ret :call, func, *args
870       end
872       # We will assign arguments from left to right.
873       # Find places that we will overwrite before we read them,
874       # and store their values in some newly allocated stack space.
875       old_frame_offset = @frame_offset
876       old_frame_size = @frame_size
877       overwritten = {}
878       (@NREGISTER_ARGS...args.length).each do |i|
879         arg = args[i]
880         arg = arg[1] if at_expr? arg
881         if symbol?(arg)
882           binding = @environment[arg]
883           if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
884               binding[1] < i
885             # Argument i is a stack argument, but the value we will assign
886             # it is a stack argument that comes before it, so we will
887             # have overwritten it by the time we get to it.
888             overwritten[arg] = nil
889           end
890         end
891       end
892       
893       unless overwritten.empty?
894         # Allocate space for arguments to be saved
895         grow_frame overwritten.length
896         # Save values
897         offset = 0
898         overwritten.each_key do |key|
899           reg = load_value key
900           emit "str #{reg}, [sp, \##{offset}]\n"
901           overwritten[key] = offset
902           offset = offset + @WORDSIZE
903         end
904       end
906       # Assign arguments
907       args.each_index do |i|
908         arg = args[i]
909         if register_arg? i
910           load_value_into_register arg, "a#{i + 1}"
911         else
912           # Test if this is a value we saved
913           sym = at_expr?(arg) ? arg[1] : arg
914           saved = overwritten[sym]
915           if saved
916             # Saved value, load from stack
917             reg = @TEMPORARY
918             emit "ldr #{reg}, [sp, \##{saved}]\n"
919           else
920             # Regular value, use load_value
921             reg = load_value arg
922           end
923           emit "str #{reg}, #{arg_reference i}\n"
924         end
925       end
927       # Load address of function to be called into @TEMPORARY
928       load_value_into_register func, @TEMPORARY
930       # Destroy current activation frame and enter func
931       destroy_frame false
932       emit "bx #{@TEMPORARY}\n"
933       emit_constants
934     end
936     # Define a word with the given value
937     def word value
938       emit ".int #{value}\n"
939     end
941     # Write generated code to the given IO object.
942     def write io
943       @sections.each do |section,code|
944         unless code.empty?
945           io.puts ".section #{section.to_s}"
946           io.puts code
947           io.puts
948         end
949       end
950     end
951   end
953   # Register class for little endian ARM
954   Voodoo::CodeGenerator.register_generator ARMGasGenerator,
955                                            :architecture => :arm,
956                                            :format => :gas