1 require 'voodoo/generators/common_code_generator'
4 # = ARM GNU Assembler Code Generator
6 # The ARM code generator generates assembly code for use with
9 # == Calling Convention
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.
15 # The return address for the called function is passed in r14.
17 # The called function will store its return value in r0.
19 # The called function is required to preserve the values of registers
20 # r4 through r11 and register r13.
22 # This calling convention is compatible with the Procedure Call
23 # Standard for the ARM Architecture (AAPCS).
27 # Call frames have the following layout:
29 # When a function is called, it receives a stack frame that looks like
37 # arg4 <-- r13 points here
39 # The function prologue of functions generated by this code generator
40 # creates activation frames that look as follows:
47 # arg4 <-- r11 points here
51 # saved r4 <-- r13 points here
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.
58 # r12 is used as a temporary, and r3 is used when another temporary
61 class ARMGasGenerator < CommonCodeGenerator
64 @WORDSIZE = 1 << @WORDSIZE_BITS
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
81 @function_end_label = nil
84 @saved_registers = [] # registers we've saved in the current frame
86 @output_file_suffix = '.s'
88 :'bits-per-word' => '32',
89 :'byte-order' => 'little-endian',
90 :'bytes-per-word' => 4
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
98 @constants << [label, value]
102 def align alignment = nil
104 # Get default alignment
107 alignment = @CODE_ALIGNMENT
109 alignment = @DATA_ALIGNMENT
111 alignment = @FUNCTION_ALIGNMENT
113 # Use data alignment as default
114 alignment = @DATA_ALIGNMENT
117 emit ".align #{alignment}\n" unless alignment == 0
120 # Returns the fp-relative offset for the nth (0-based) argument.
122 (n - @NREGISTER_ARGS) * @WORDSIZE
125 # Returns an fp-relative reference for the nth (0-based) argument.
127 offset_reference arg_offset(n)
130 # Return the register in which the nth (0-based) argument is stored, or
131 # nil if not stored in a register
133 # The first @NREGISTER_ARGS arguments are in the v registers,
134 # the rest are on the stack.
142 def auto_bytes value, register
143 if value.kind_of? Integer
146 temporary = register == :sp ? @TEMPORARY : register
147 load_value_into_register value, temporary
148 auto_bytes_register temporary
150 emit "cpy #{register}, sp\n" unless register == :sp
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"
163 def auto_words value, register
164 if value.kind_of? Integer
165 auto_bytes(value * @WORDSIZE, register)
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
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
182 @environment = Environment.new @environment
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"
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)
197 environment.add_arg formal, arg_offset(i)
200 @environment = environment
201 emit_function_prologue formals, nlocals
204 # Define a byte with the given value
206 emit ".byte #{value}\n"
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"
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}"
235 func_reg = load_value func
236 emit "blx #{func_reg}\n"
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
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.
257 nregister_vars.times do |i|
258 clobbered << :"v#{i < 5 ? i + 1 : i + 2}"
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
271 emit "sub sp, sp, \##{extra_space}\n"
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"
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"
305 index = saved.index :lr
309 raise "Request to load saved lr into pc, but lr has not been saved"
312 emit "ldmfd sp!, {#{saved.join ', '}}\n"
314 emit_constants if ret
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.
320 @constants.each do |x|
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"
344 # Ends the current 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
351 emit "add sp, sp, \##{offset}\n"
353 emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
356 @saved_registers = []
358 # If we need to emit constants, do so now
359 unless @constants.empty?
366 # Restore old value of @environment
367 @environment = @environment.parent
370 # Ends a function body.
372 if @environment == @top_level
373 raise "Cannot end function when not in a function"
376 label @function_end_label
381 @saved_registers = []
382 @environment = @top_level
385 # Ends a conditional.
390 # Evaluate the binary operation expr and store the result in register
391 def eval_binop expr, register
394 # Emulation for div and mod, which ARM does not have instructions for
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
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
410 # First operand must be in a register.
411 x = load_value expr[1], @TEMPORARY
415 # Operand must be in a register for these ops.
416 y = load_value expr[2], :a4
418 y = value_ref expr[2], :a4
423 emit "lsr #{register}, #{x}, #{y}\n"
425 emit "orr #{register}, #{x}, #{y}\n"
427 # Can't store result in same register as first operand.
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"
436 # Multiplication is commutative. Just swap x and y.
437 emit "mul #{register}, #{y}, #{x}\n"
440 # Common case, register and x are different.
441 emit "mul #{register}, #{x}, #{y}\n"
445 y = "\##{32 - expr[2]}"
447 emit "rsb #{y}, #{y}, #32\n"
449 emit "ror #{register}, #{x}, #{y}\n"
451 emit "lsl #{register}, #{x}, #{y}\n"
453 emit "lsr #{register}, #{x}, #{y}\n"
455 emit "eor #{register}, #{x}, #{y}\n"
457 emit "#{expr[0]} #{register}, #{x}, #{y}\n"
461 # Evaluates the expression +expr+ and stores the result in +register+.
462 def eval_expr expr, register
465 load_value_into_register expr[0], register
467 # Evaluate expression
471 auto_bytes expr[1], register
473 auto_words expr[1], register
476 emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
478 get_byte expr[1], expr[2], register
480 get_word expr[1], expr[2], register
482 load_value_into_register expr[1], register
483 emit "mvn #{@TEMPORARY}, #0\n"
484 emit "eor #{register}, #{register}, #{@TEMPORARY}\n"
487 eval_binop expr, register
489 raise "Not a magic word: #{op}"
495 # Export symbols from the current section
497 symbols.each { |sym| emit ".globl #{sym}\n" }
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]
508 base_reg = load_value base
510 emit "ldrb #{register}, [#{base_reg}]\n"
512 emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
515 base_reg = load_value base
516 offset_reg = load_value offset, :a4
517 emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
521 # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
522 def get_word base, offset, register
524 base_reg = load_value base
526 emit "ldr #{register}, [#{base_reg}]\n"
528 emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
531 base_reg = load_value base
532 offset_reg = load_value offset, :a4
533 emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
542 register = load_value label
543 emit "cpy pc, #{register}\n"
546 # If we have constants that need to be emitted, do so now
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
559 # Start the false path of a conditional.
561 newlabel = @environment.gensym
565 @if_labels.push newlabel
568 # Test if x is equal to y
570 common_if :ifeq, x, y
573 # Test if x is greater than or equal to y
575 common_if :ifge, x, y
578 # Test if x is strictly greater than y
580 common_if :ifgt, x, y
583 # Test if x is less than or equal to y
585 common_if :ifle, x, y
588 # Test if x is strictly less than y
590 common_if :iflt, x, y
593 # Test if x different from y
595 common_if :ifne, x, y
598 # Import labels into the current section
600 # Record imported labels in @imports
601 symbols.each { |sym| @imports[sym] = sym }
609 # Introduce a new local variable
610 def let symbol, *expr
611 n = @environment.locals
612 register = local_register n
615 # We will use a register to store the value
616 @environment.add_local symbol, register
617 eval_expr expr, register
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"
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"
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
638 # Returns the name of the register the value is in.
639 def load_value x, register = @TEMPORARY
640 ref = value_ref x, register
644 emit "mov #{register}, #{ref}\n"
649 # Loads a value into a specific register.
650 def load_value_into_register x, register
651 ref = value_ref x, register
654 emit "cpy #{register}, #{ref}\n"
656 emit "mov #{register}, #{ref}\n"
662 # Returns the fp-relative reference for the nth (0-based) local.
664 -@INITIAL_FRAME_SIZE - (n * @WORDSIZE)
667 # Return the register in which the nth local (0-based) is stored, or
668 # nil if not stored in a register
671 n = n + number_of_register_arguments
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
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
694 # Given an offset, returns an fp-relative reference.
695 def offset_reference offset
696 "[#{@FP}, \##{offset}]"
699 # Returns true if operand is a register, false otherwise.
704 # Returns true if the nth (0-based) argument is stored in a register
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
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"
722 # Returns from a function.
724 # _words_ may contain an expression to be evaluated. The result
725 # of the evaluation is returned from the function.
727 # Compute return value and store it in @RETURN
728 eval_expr(words, @RETURN) unless words.empty?
730 goto @function_end_label
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"
741 # Returns the number of bytes necessary to save the current frame.
743 @SAVE_FRAME_REGISTERS.length * @WORDSIZE
746 # Set a variable to the result of evaluating an expression
747 def set symbol, *expr
750 register = load_value symbol[1]
751 emit "str r3, [#{register}]\n"
753 x = @environment[symbol]
755 raise "Cannot change value of constant #{symbol}"
756 elsif x.kind_of? Symbol
759 eval_expr expr, @TEMPORARY
760 emit "str #{@TEMPORARY}, #{offset_reference x}\n"
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]
773 base_reg = load_value base, :a4
774 load_value_into_register value, @TEMPORARY
776 emit "strb #{@TEMPORARY}, [#{base_reg}]\n"
778 emit "strb #{@TEMPORARY}, [#{base_reg}, \##{offset}]\n"
781 eval_binop [:add, base, offset], :a4
782 load_value_into_register value, @TEMPORARY
783 emit "strb #{@TEMPORARY}, [a4]\n"
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]
795 base_reg = load_value base, :a4
796 load_value_into_register value, @TEMPORARY
798 emit "str #{@TEMPORARY}, [#{base_reg}]\n"
800 emit "str #{@TEMPORARY}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
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"
811 # Given n, returns the nearest multiple of @STACK_ALIGNMENT
814 (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
817 # Define a string with the given value
820 value.each_byte do |b|
823 elsif b >= 32 && b < 127 && b != 34
826 code << sprintf("\\%03o", b)
829 emit ".ascii \"#{code}\"\n"
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
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
849 (@NREGISTER_ARGS...args.length).each do |i|
851 arg = arg[1] if at_expr? arg
853 binding = @environment[arg]
854 if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
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
864 unless overwritten.empty?
865 # Allocate space for arguments to be saved
866 grow_frame overwritten.length
869 overwritten.each_key do |key|
871 emit "str #{reg}, [sp, \##{offset}]\n"
872 overwritten[key] = offset
873 offset = offset + @WORDSIZE
878 args.each_index do |i|
881 load_value_into_register arg, "a#{i + 1}"
883 # Test if this is a value we saved
884 sym = at_expr?(arg) ? arg[1] : arg
885 saved = overwritten[sym]
887 # Saved value, load from stack
889 emit "ldr #{reg}, [sp, \##{saved}]\n"
891 # Regular value, use load_value
894 emit "str #{reg}, #{arg_reference i}\n"
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
903 emit "bx #{@TEMPORARY}\n"
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
915 def value_ref x, register = @TEMPORARY
917 x = substitute_number x[1]
921 if x >= 0 && x <= 255
923 elsif x >= -255 && x < 0
924 emit "mvn #{register}, \##{-(x + 1)}\n"
928 emit "ldr #{register}, #{lbl}\n"
932 binding = @environment[x]
933 if binding.kind_of? Symbol
934 # Value is already in a register. Return register name.
936 elsif binding.kind_of? Integer
937 # Value is on the stack. Load from the stack.
938 emit "ldr #{register}, #{offset_reference binding}\n"
943 emit "ldr #{register}, #{lbl}\n"
947 load_at x[1], register
949 raise "Don't know how to load #{x.inspect}"
953 # Define a word with the given value
955 emit ".int #{value}\n"
960 # Register class for little endian ARM
961 Voodoo::CodeGenerator.register_generator ARMGasGenerator,
962 :architecture => :arm,