Use immediate values for small integers on ARM
[voodoo-lang.git] / lib / voodoo / generators / arm_gas_generator.rb
blobb8da37bedf80ad84318f807d319ea3a573f2d1a3
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}".to_sym
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       xreg = load_value x, @TEMPORARY
285       yreg = load_value y, :a4
287       falselabel = @environment.gensym
288       @if_labels.push falselabel
290       emit "cmp #{xreg}, #{yreg}\n"
292       lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
293         :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
294       emit "#{lut[comp]} #{falselabel}\n"
295     end
297     # Destroys the current stack frame.
298     # If ret is true, loads the saved value of lr into pc.
299     def destroy_frame ret = false
300       # Set sp back to where saved registers were stored
301       saved = @saved_registers
302       emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
304       if ret
305         index = saved.index :lr
306         if index
307           saved[index] = :pc
308         else
309           raise "Request to load saved lr into pc, but lr has not been saved"
310         end
311       end
312       emit "ldmfd sp!, {#{saved.join ', '}}\n"
313       
314       emit_constants if ret
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 v 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 v#{i + 1}, a#{i + 1}\n"
341       end
342     end
344     # Ends the current block.
345     def end_block
346       # If we are returning to top level, restore stack pointer
347       # and saved registers.
348       if @environment.parent == @top_level
349         offset = @frame_size - @saved_registers.length * @WORDSIZE
350         if offset > 0
351           emit "add sp, sp, \##{offset}\n"
352         end
353         emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
354         @frame_size = 0
355         @frame_offset = 0
356         @saved_registers = []
358         # If we need to emit constants, do so now
359         unless @constants.empty?
360           lbl = gensym
361           goto lbl
362           label lbl
363         end
364       end
366       # Restore old value of @environment
367       @environment = @environment.parent
368     end
370     # Ends a function body.
371     def end_function
372       if @environment == @top_level
373         raise "Cannot end function when not in a function"
374       end
376       label @function_end_label
378       destroy_frame true
379       @frame_size = 0
380       @frame_offset = 0
381       @saved_registers = []
382       @environment = @top_level
383     end
385     # Ends a conditional.
386     def end_if
387       label @if_labels.pop
388     end
390     # Evaluate the binary operation expr and store the result in register
391     def eval_binop expr, register
392       op = expr[0]
394       # Emulation for div and mod, which ARM does not have instructions for
395       case op
396       when :div
397         func = :"__aeabi_idiv"
398         import func unless @imports.has_key? func
399         call func, expr[1], expr[2]
400         emit "cpy #{register}, r0\n" if register != :r0
401         return
402       when :mod
403         func = :"__aeabi_idivmod"
404         import func unless @imports.has_key? func
405         call func, expr[1], expr[2]
406         emit "cpy #{register}, r1\n" if register != :r1
407         return
408       end
410       # First operand must be in a register.
411       x = load_value expr[1], @TEMPORARY
413       case op
414       when :mul
415         # Operand must be in a register for these ops.
416         y = load_value expr[2], :a4
417       else
418         y = value_ref expr[2], :a4
419       end
421       case op
422       when :bsr
423         emit "lsr #{register}, #{x}, #{y}\n"
424       when :or
425         emit "orr #{register}, #{x}, #{y}\n"
426       when :mul
427         # Can't store result in same register as first operand.
428         if register == x
429           if x == y
430             # All using the same register. Move x to a different
431             # register to make this work.
432             temp = (x == @TEMPORARY) ? :a4 : @TEMPORARY
433             emit "cpy #{temp}, #{x}\n"
434             emit "mul #{register}, #{temp}, #{y}\n"
435           else
436             # Multiplication is commutative. Just swap x and y.
437             emit "mul #{register}, #{y}, #{x}\n"
438           end
439         else
440           # Common case, register and x are different.
441           emit "mul #{register}, #{x}, #{y}\n"
442         end
443       when :rol
444         if integer? expr[2]
445           y = "\##{32 - expr[2]}"
446         else
447           emit "rsb #{y}, #{y}, #32\n"
448         end
449         emit "ror #{register}, #{x}, #{y}\n"
450       when :shl
451         emit "lsl #{register}, #{x}, #{y}\n"
452       when :shr
453         emit "lsr #{register}, #{x}, #{y}\n"
454       when :xor
455         emit "eor #{register}, #{x}, #{y}\n"
456       else
457         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
458       end
459     end
461     # Evaluates the expression +expr+ and stores the result in +register+.
462     def eval_expr expr, register
463       if expr.length == 1
464         # Load value
465         load_value_into_register expr[0], register
466       else
467         # Evaluate expression
468         op = expr[0]
469         case op
470         when :'auto-bytes'
471           auto_bytes expr[1], register
472         when :'auto-words'
473           auto_words expr[1], register
474         when :call
475           call *expr[1..-1]
476           emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
477         when :'get-byte'
478           get_byte expr[1], expr[2], register
479         when :'get-word'
480           get_word expr[1], expr[2], register
481         when :not
482           load_value_into_register expr[1], register
483           emit "mvn #{@TEMPORARY}, #0\n"
484           emit "eor #{register}, #{register}, #{@TEMPORARY}\n"
485         else
486           if binop? op
487             eval_binop expr, register
488           else
489             raise "Not a magic word: #{op}"
490           end
491         end
492       end
493     end
495     # Export symbols from the current section
496     def export *symbols
497       symbols.each { |sym| emit ".globl #{sym}\n" }
498     end
500     # Load byte from _base_ + _offset_ into _register_
501     def get_byte base, offset, register
502       # If base is an integer, but offset isn't, swap them
503       if !integer?(offset) && integer?(base)
504         base, offset = [offset, base]
505       end
507       if integer? offset
508         base_reg = load_value base
509         if offset == 0
510           emit "ldrb #{register}, [#{base_reg}]\n"
511         else
512           emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
513         end
514       else
515         base_reg = load_value base
516         offset_reg = load_value offset, :a4
517         emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
518       end
519     end
521     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
522     def get_word base, offset, register
523       if integer? offset
524         base_reg = load_value base
525         if offset == 0
526           emit "ldr #{register}, [#{base_reg}]\n"
527         else
528           emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
529         end
530       else
531         base_reg = load_value base
532         offset_reg = load_value offset, :a4
533         emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
534       end
535     end
537     # Jump to a label.
538     def goto label
539       if global? label
540         emit "b #{label}\n"
541       else
542         register = load_value label
543         emit "cpy pc, #{register}\n"
544       end
546       # If we have constants that need to be emitted, do so now
547       emit_constants
548     end
550     # Grows the current frame by n words, plus padding to
551     # respect alignment rules.
552     def grow_frame nwords
553       increment = stack_align(nwords * @WORDSIZE)
554       emit "sub sp, sp, \##{increment}\n"
555       @frame_size = @frame_size + increment
556       @frame_offset = @frame_offset + increment
557     end
559     # Start the false path of a conditional.
560     def ifelse
561       newlabel = @environment.gensym
562       goto newlabel
563       lbl = @if_labels.pop
564       label lbl
565       @if_labels.push newlabel
566     end
568     # Test if x is equal to y
569     def ifeq x, y
570       common_if :ifeq, x, y
571     end
573     # Test if x is greater than or equal to y
574     def ifge x, y
575       common_if :ifge, x, y
576     end
578     # Test if x is strictly greater than y
579     def ifgt x, y
580       common_if :ifgt, x, y
581     end
583     # Test if x is less than or equal to y
584     def ifle x, y
585       common_if :ifle, x, y
586     end
588     # Test if x is strictly less than y
589     def iflt x, y
590       common_if :iflt, x, y
591     end
593     # Test if x different from y
594     def ifne x, y
595       common_if :ifne, x, y
596     end
598     # Import labels into the current section
599     def import *symbols
600       # Record imported labels in @imports
601       symbols.each { |sym| @imports[sym] = sym }
602     end
604     # Emit a label
605     def label name
606       emit "#{name}:\n"
607     end
609     # Introduce a new local variable
610     def let symbol, *expr
611       n = @environment.locals
612       register = local_register n
614       if register
615         # We will use a register to store the value
616         @environment.add_local symbol, register
617         eval_expr expr, register
618       else
619         # We will use the stack to store the value
620         offset = local_offset n
621         @environment.add_local symbol, offset
622         eval_expr expr, @TEMPORARY
623         emit "str #{@TEMPORARY}, #{offset_reference offset}\n"
624       end
625     end
627     # Loads the value at the given address.
628     def load_at address, register = @TEMPORARY
629       load_value_into_register address, register
630       emit "ldr #{register}, [#{register}]\n"
631       register
632     end
634     # Loads a value into some register.
635     # If the value is already in a register, does nothing.
636     # Else, loads the value into the register given as the
637     # second argument.
638     # Returns the name of the register the value is in.
639     def load_value x, register = @TEMPORARY
640       ref = value_ref x, register
641       if register? ref
642         ref
643       else
644         emit "mov #{register}, #{ref}\n"
645         register
646       end
647     end
649     # Loads a value into a specific register.
650     def load_value_into_register x, register
651       ref = value_ref x, register
652       if ref != register
653         if register? ref
654           emit "cpy #{register}, #{ref}\n"
655         else
656           emit "mov #{register}, #{ref}\n"
657         end
658       end
659       register
660     end
662     # Returns the fp-relative reference for the nth (0-based) local.
663     def local_offset n
664       -@INITIAL_FRAME_SIZE - (n * @WORDSIZE)
665     end
666     
667     # Return the register in which the nth local (0-based) is stored, or
668     # nil if not stored in a register
669     def local_register n
670       if register_local? n
671         n = n + number_of_register_arguments
672         if n < 5
673           "v#{n + 1}".to_sym
674         else
675           "v#{n + 2}".to_sym
676         end
677       else
678         nil
679       end
680     end
682     # Calculate the number of register arguments,
683     # given the total number of arguments.
684     def number_of_register_arguments n = @environment.args
685       [n, @NREGISTER_ARGS].min
686     end
688     # Calculate the number of stack arguments,
689     # given the total number of arguments.
690     def number_of_stack_arguments n = @environment.args
691       [0, n - @NREGISTER_ARGS].max
692     end
694     # Given an offset, returns an fp-relative reference.
695     def offset_reference offset
696       "[#{@FP}, \##{offset}]"
697     end
699     # Returns true if operand is a register, false otherwise.
700     def register? x
701       x.kind_of? Symbol
702     end
704     # Returns true if the nth (0-based) argument is stored in a register
705     def register_arg? n
706       n < @NREGISTER_ARGS
707     end
709     # Returns true if the nth (0-based) local is stored in a register
710     def register_local? n
711       (n + number_of_register_arguments) < @NREGISTER_LOCALS
712     end
714     # Restores the frame saved at the given location.
715     def restore_frame location
716       load_value_into_register location, @TEMPORARY
717       @SAVE_FRAME_REGISTERS.each_with_index do |register,i|
718         emit "ldr #{register}, [#{@TEMPORARY}, \##{i * @WORDSIZE}]\n"
719       end
720     end
721     
722     # Returns from a function.
723     # 
724     # _words_ may contain an expression to be evaluated. The result
725     # of the evaluation is returned from the function.
726     def ret *words
727       # Compute return value and store it in @RETURN
728       eval_expr(words, @RETURN) unless words.empty?
729       # Go to epilogue
730       goto @function_end_label
731     end
733     # Saves the current frame to the given location.
734     def save_frame location
735       load_value_into_register location, @TEMPORARY
736       @SAVE_FRAME_REGISTERS.each_with_index do |register,i|
737         emit "str #{register}, [#{@TEMPORARY}, \##{i * @WORDSIZE}]\n"
738       end
739     end
740     
741     # Returns the number of bytes necessary to save the current frame.
742     def saved_frame_size
743       @SAVE_FRAME_REGISTERS.length * @WORDSIZE
744     end
745     
746     # Set a variable to the result of evaluating an expression
747     def set symbol, *expr
748       if at_expr? symbol
749         eval_expr expr, :r3
750         register = load_value symbol[1]
751         emit "str r3, [#{register}]\n"
752       else
753         x = @environment[symbol]
754         if x == nil
755           raise "Cannot change value of constant #{symbol}"
756         elsif x.kind_of? Symbol
757           eval_expr expr, x
758         else
759           eval_expr expr, @TEMPORARY
760           emit "str #{@TEMPORARY}, #{offset_reference x}\n"
761         end
762       end
763     end
765     # Set the byte at _base_ + _offset_ to _value_
766     def set_byte base, offset, value
767       # If base is an integer, but offset isn't, swap them
768       if !integer?(offset) && integer?(base)
769         base, offset = [offset, base]
770       end
772       if integer? offset
773         base_reg = load_value base, :a4
774         load_value_into_register value, @TEMPORARY
775         if offset == 0
776           emit "strb #{@TEMPORARY}, [#{base_reg}]\n"
777         else
778           emit "strb #{@TEMPORARY}, [#{base_reg}, \##{offset}]\n"
779         end
780       else
781         eval_binop [:add, base, offset], :a4
782         load_value_into_register value, @TEMPORARY
783         emit "strb #{@TEMPORARY}, [a4]\n"
784       end
785     end
787     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
788     def set_word base, offset, value
789       # If base is an integer, but offset isn't, swap them
790       if !integer?(offset) && integer?(base)
791         base, offset = [offset, base]
792       end
794       if integer? offset
795         base_reg = load_value base, :a4
796         load_value_into_register value, @TEMPORARY
797         if offset == 0
798           emit "str #{@TEMPORARY}, [#{base_reg}]\n"
799         else
800           emit "str #{@TEMPORARY}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
801         end
802       else
803         load_value_into_register base, :a4
804         load_value_into_register offset, @TEMPORARY
805         emit "add a4, a4, #{@TEMPORARY}, LSL #2\n"
806         load_value_into_register value, @TEMPORARY
807         emit "str #{@TEMPORARY}, [a4]\n"
808       end
809     end
811     # Given n, returns the nearest multiple of @STACK_ALIGNMENT
812     # that is >= n.
813     def stack_align n
814       (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
815     end
816     
817     # Define a string with the given value
818     def string value
819       code = ''
820       value.each_byte do |b|
821         if b == 92
822           code << "\\\\"
823         elsif b >= 32 && b < 127 && b != 34
824           code << b.chr
825         else
826           code << sprintf("\\%03o", b)
827         end
828       end
829       emit ".ascii \"#{code}\"\n"
830     end
832     # Call a function, re-using the current call frame if possible.
833     def tail_call func, *args
834       # Compute number of stack arguments
835       nstackargs = number_of_stack_arguments args.length
836       # If we need more stack arguments than we have now,
837       # perform a normal call and return
838       if nstackargs > number_of_stack_arguments(@environment.args)
839         emit "# Not enough space for proper tail call; using regular call\n"
840         ret :call, func, *args
841       end
843       # We will assign arguments from left to right.
844       # Find places that we will overwrite before we read them,
845       # and store their values in some newly allocated stack space.
846       old_frame_offset = @frame_offset
847       old_frame_size = @frame_size
848       overwritten = {}
849       (@NREGISTER_ARGS...args.length).each do |i|
850         arg = args[i]
851         arg = arg[1] if at_expr? arg
852         if symbol?(arg)
853           binding = @environment[arg]
854           if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
855               binding[1] < i
856             # Argument i is a stack argument, but the value we will assign
857             # it is a stack argument that comes before it, so we will
858             # have overwritten it by the time we get to it.
859             overwritten[arg] = nil
860           end
861         end
862       end
863       
864       unless overwritten.empty?
865         # Allocate space for arguments to be saved
866         grow_frame overwritten.length
867         # Save values
868         offset = 0
869         overwritten.each_key do |key|
870           reg = load_value key
871           emit "str #{reg}, [sp, \##{offset}]\n"
872           overwritten[key] = offset
873           offset = offset + @WORDSIZE
874         end
875       end
877       # Assign arguments
878       args.each_index do |i|
879         arg = args[i]
880         if register_arg? i
881           load_value_into_register arg, "a#{i + 1}"
882         else
883           # Test if this is a value we saved
884           sym = at_expr?(arg) ? arg[1] : arg
885           saved = overwritten[sym]
886           if saved
887             # Saved value, load from stack
888             reg = @TEMPORARY
889             emit "ldr #{reg}, [sp, \##{saved}]\n"
890           else
891             # Regular value, use load_value
892             reg = load_value arg
893           end
894           emit "str #{reg}, #{arg_reference i}\n"
895         end
896       end
898       # Load address of function to be called into @TEMPORARY
899       load_value_into_register func, @TEMPORARY
901       # Destroy current activation frame and enter func
902       destroy_frame false
903       emit "bx #{@TEMPORARY}\n"
904       emit_constants
905     end
907     # Returns a reference to a value.
908     # For immediate values that fit in 8 bits, this returns the
909     # value itself (in ARM syntax).
910     # For all other values, loads the value into a register and
911     # returns the name of the register. If the value is already
912     # in a register, the name of that register is returned. Else,
913     # the value is loaded into the register specified as the
914     # second argument.
915     def value_ref x, register = @TEMPORARY
916       if substitution? x
917         x = substitute_number x[1]
918       end
919         
920       if integer? x
921         if x >= 0 && x <= 255
922           return "\##{x}"
923         elsif x >= -255 && x < 0
924           emit "mvn #{register}, \##{-(x + 1)}\n"
925           return register
926         else
927           lbl = add_constant x
928           emit "ldr #{register}, #{lbl}\n"
929           return register
930         end
931       elsif symbol? x
932         binding = @environment[x]
933         if binding.kind_of? Symbol
934           # Value is already in a register. Return register name.
935           return binding
936         elsif binding.kind_of? Integer
937           # Value is on the stack. Load from the stack.
938           emit "ldr #{register}, #{offset_reference binding}\n"
939           return register
940         else
941           # Assume global
942           lbl = add_constant x
943           emit "ldr #{register}, #{lbl}\n"
944           return register
945         end
946       elsif at_expr? x
947         load_at x[1], register
948       else
949         raise "Don't know how to load #{x.inspect}"
950       end
951     end
953     # Define a word with the given value
954     def word value
955       emit ".int #{value}\n"
956     end
958   end
960   # Register class for little endian ARM
961   Voodoo::CodeGenerator.register_generator ARMGasGenerator,
962                                            :architecture => :arm,
963                                            :format => :gas