1 require 'voodoo/generators/common_code_generator'
5 # = ARM GNU Assembler Code Generator
7 # The ARM code generator generates assembly code for use with
10 # == Calling Convention
12 # The first four arguments are passed in the registers r0 through r3.
13 # Any additional arguments are passed on the stack, starting at
14 # r13. r13 will always be a multiple of 8.
16 # The return address for the called function is passed in r14.
18 # The called function will store its return value in r0.
20 # The called function is required to preserve the values of registers
21 # r4 through r11 and register r13.
23 # This calling convention is compatible with the Procedure Call
24 # Standard for the ARM Architecture (AAPCS).
28 # Call frames have the following layout:
30 # When a function is called, it receives a stack frame that looks like
38 # arg4 <-- r13 points here
40 # The function prologue of functions generated by this code generator
41 # creates activation frames that look as follows:
48 # arg4 <-- r11 points here
55 # localn <-- r13 points here
59 # Inside a function, registers r4..r8 and r10 are used for local variables
60 # and function arguments, whereas r11 is used as a frame pointer.
62 # r12 is used as a temporary, and r3, r2 and r1 are used when more
63 # temporaries are needed.
67 # Local variables are used to store both the first 4 function arguments
68 # and any variables declared inside the function (arguments beyond the 4th
69 # are stored on the stack, as per the calling convention). Local variables
70 # beyond the 6th are stored on the stack, starting below the saved registers
73 class ARMGasGenerator < CommonCodeGenerator
76 @WORDSIZE = 1 << @WORDSIZE_BITS
78 @DATA_ALIGNMENT = @WORDSIZE
79 @FUNCTION_ALIGNMENT = @WORDSIZE
80 @STACK_ALIGNMENT_BITS = 3
81 @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
82 # Registers used for storing local variables.
83 @LOCAL_REGISTERS = [:r4, :r5, :r6, :r7, :r8, :r10]
84 # Set of registers used for storing local variables.
85 @LOCAL_REGISTERS_SET = Set.new @LOCAL_REGISTERS
86 # Registers to be saved by save-frame.
87 @SAVE_FRAME_REGISTERS = [:r4, :r5, :r6, :r7, :r8,
88 :r9, :r10, :r11, :r13, :r14]
89 # Hash from register names to offsets in saved frame.
90 @SAVED_FRAME_LAYOUT = {}
91 @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
92 @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
94 @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
97 @TEMPORARIES = [:r12, :r3, :r2, :r1]
101 @function_end_label = nil
104 @saved_registers = [] # registers we've saved in the current frame
105 @saved_size = 0 # bytes dedicated to saved registers
107 @output_file_suffix = '.s'
109 :'bits-per-word' => '32',
110 :'byte-order' => 'little-endian',
111 :'bytes-per-word' => 4
114 # Create an entry in the constants table,
115 # returning the label that will refer to the constant.
116 # The value may be an integer or a label.
117 def add_constant value
119 @constants << [label, value]
123 # Returns the fp-relative offset for the nth (0-based) argument.
125 (n - @NREGISTER_ARGS) * @WORDSIZE
128 # Returns an fp-relative reference for the nth (0-based) argument.
130 offset_reference arg_offset(n)
133 # Return the register in which the nth (0-based) argument is stored, or
134 # nil if not stored in a register
136 if n < @NREGISTER_ARGS
137 # We copied the argument to one of the local registers.
144 def auto_bytes value, register
145 if value.kind_of? Integer
148 temporary = register == :sp ? @TEMPORARIES[0] : register
149 load_value_into_register value, temporary
150 auto_bytes_register temporary
152 emit "cpy #{register}, sp\n" unless register == :sp
155 # auto-bytes where the value is supplied in a register and the return
156 # value will be in sp. register must not be sp.
157 def auto_bytes_register register
158 temporary = register == @TEMPORARIES[0] ? :r3 : @TEMPORARIES[0]
159 emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
160 emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
161 emit "and #{register}, #{register}, #{temporary}\n"
162 emit "sub sp, #{register}\n"
165 def auto_words value, register
166 if value.kind_of? Integer
167 auto_bytes(value * @WORDSIZE, register)
169 raise "Can't use :sp as a register for auto_words" if register == :sp
170 load_value_into_register value, register
171 emit "lsl #{register}, #{register}, \##{@WORDSIZE_BITS}\n"
172 auto_bytes_register register
173 emit "cpy #{register}, sp\n"
177 # Begins a new block.
178 def begin_block *code
179 # If we are starting a block at top level, create a frame
180 if @environment == @top_level
181 nlocals = count_locals code
182 create_frame nlocals, false
184 @environment = Environment.new @environment
187 # Emit function prologue and declare _formals_ as function arguments
188 def begin_function formals, nlocals
189 if @environment != @top_level
190 raise "Can only begin a function at top level"
193 @function_end_label = gensym
194 environment = Environment.new @environment
195 formals.each_with_index do |formal, i|
196 if i < @NREGISTER_ARGS
197 environment.add_arg formal, arg_register(i)
199 environment.add_arg formal, arg_offset(i)
202 @environment = environment
203 emit_function_prologue formals, nlocals
206 # Define a byte with the given value
208 emit ".byte #{value}\n"
213 # Calculate how many arguments need to be pushed on
214 # the stack, and allocate space for them.
215 nstack_args = number_of_stack_arguments args.length
216 old_frame_offset = @frame_offset
217 old_frame_size = @frame_size
218 grow_frame nstack_args if nstack_args > 0
220 # Put stack arguments on the stack
221 (@NREGISTER_ARGS...args.length).each do |n|
222 with_temporary do |temporary|
223 load_value_into_register args[n], temporary
224 emit "str #{temporary}, " +
225 "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
229 # Put register arguments in the right registers
230 nregister_args = number_of_register_arguments args.length
231 nregister_args.times do |n|
232 load_value_into_register args[n], :"r#{n}"
237 @symbol_tracker.use func
240 with_temporary do |temporary|
241 func_reg = load_value func, temporary
242 emit "blx #{func_reg}\n"
246 # Restore original stack frame
247 if old_frame_size != @frame_size
248 emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
249 @frame_offset = old_frame_offset
250 @frame_size = old_frame_size
254 # Creates a stack frame for the given number of arguments
255 # and local variables.
256 def create_frame nvars, save_lr = true
257 # Calculate how many variables we will store in registers,
258 # and how many on the stack.
259 nregister_vars = [nvars, @NREGISTER_LOCALS].min
260 nstack_vars = nvars - nregister_vars
262 # Save the registers we will clobber to the stack.
264 nregister_vars.times do |i|
265 clobbered << @LOCAL_REGISTERS[i]
268 clobbered << :lr if save_lr
269 @saved_registers = clobbered
270 @saved_size = @saved_registers.length * @WORDSIZE
271 emit "stmfd sp!, {#{clobbered.join ', '}}\n"
272 emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
274 # Calculate frame size so that the stack pointer will
275 # be properly aligned at the end of emit_function_prologue.
276 @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
277 extra_space = @frame_size - clobbered.length * @WORDSIZE
279 emit "sub sp, sp, \##{extra_space}\n"
289 # Start a conditional using the specified branch instruction
290 # after the comparison.
291 def common_if comp, x, y = nil
292 with_temporary do |temporary|
293 xreg = load_value x, temporary
294 yreg = load_value y, :a4
296 falselabel = @environment.gensym
297 @if_labels.push falselabel
299 emit "cmp #{xreg}, #{yreg}\n"
300 lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
301 :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
302 emit "#{lut[comp]} #{falselabel}\n"
306 # Destroys the current stack frame.
307 # If ret is true, loads the saved value of lr into pc.
308 def destroy_frame ret = false
309 # Set sp back to where saved registers were stored
310 saved = @saved_registers
311 emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
314 index = saved.index :lr
318 raise "Request to load saved lr into pc, but lr has not been saved"
321 emit "ldmfd sp!, {#{saved.join ', '}}\n"
323 emit_constants if ret
326 # Aligns on the next multiple of +n+ bytes.
331 # Writes any constants that need to be written to the instruction
332 # stream, and clears the list of constants that need to be written.
334 @constants.each do |x|
341 # Emit function prologue.
342 def emit_function_prologue formals = [], nlocals = 0
343 # Calculate the number of arguments we were passed in
344 # registers, the total number of values we need to save
345 # on the stack, then create a stack frame and save
346 # the registers we will be using.
347 nregister_args = [formals.length, @NREGISTER_ARGS].min
348 nvars = nregister_args + nlocals
349 create_frame nvars, true
351 # Move arguments that were passed in registers into
352 # callee-save registers.
353 nregister_args.times do |i|
354 emit "cpy #{@LOCAL_REGISTERS[i]}, r#{i}\n"
358 # Emits a label type annotation.
359 def emit_label_type name, type
361 :code => "%function",
364 emit ".type #{name}, #{type_map[type]}\n"
367 # Emits a label size annotation.
368 def emit_label_size name
369 emit ".size #{name}, .-#{name}\n"
372 # Loads a word into a register.
373 def emit_load_word register, base, offset
375 emit "ldr #{register}, [#{base}]\n"
377 emit "ldr #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
381 # Stores the value of a register in memory.
382 def emit_store_word register, base, offset
384 emit "str #{register}, [#{base}]\n"
386 emit "str #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
390 # Ends the current block.
392 # If we are returning to top level, restore stack pointer
393 # and saved registers.
394 if @environment.parent == @top_level
395 offset = @frame_size - @saved_size
397 emit "add sp, sp, \##{offset}\n"
399 emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
402 @saved_registers = []
405 # If we need to emit constants, do so now
406 unless @constants.empty?
413 # Restore old value of @environment
414 @environment = @environment.parent
417 # Ends a function body.
419 if @environment == @top_level
420 raise "Cannot end function when not in a function"
423 label @function_end_label
428 @saved_registers = []
430 @environment = @top_level
433 # Ends a conditional.
438 # Evaluate the binary operation expr and store the result in register
439 def eval_binop expr, register
442 # Emulation for div and mod, which ARM does not have instructions for
445 func = :"__aeabi_idiv"
446 import func unless @imports.member? func
447 call func, expr[1], expr[2]
448 emit "cpy #{register}, r0\n" if register != :r0
451 func = :"__aeabi_idivmod"
452 import func unless @imports.member? func
453 call func, expr[1], expr[2]
454 emit "cpy #{register}, r1\n" if register != :r1
458 with_temporaries(2) do |t1,t2|
459 x = load_value expr[1], t1
463 # Operand must be in a register for these ops.
464 y = load_value expr[2], t2
466 y = value_ref expr[2], t2
471 emit "lsr #{register}, #{x}, #{y}\n"
473 emit "orr #{register}, #{x}, #{y}\n"
475 # Can't store result in same register as first operand.
478 # All using the same register. Move x to a different
479 # register to make this work.
480 temp = (x == t1) ? t2 : t1
481 emit "cpy #{temp}, #{x}\n"
482 emit "mul #{register}, #{temp}, #{y}\n"
484 # Multiplication is commutative. Just swap x and y.
485 emit "mul #{register}, #{y}, #{x}\n"
488 # Common case, register and x are different.
489 emit "mul #{register}, #{x}, #{y}\n"
493 y = "\##{32 - expr[2]}"
495 emit "rsb #{y}, #{y}, #32\n"
497 emit "ror #{register}, #{x}, #{y}\n"
499 emit "lsl #{register}, #{x}, #{y}\n"
501 emit "lsr #{register}, #{x}, #{y}\n"
503 emit "eor #{register}, #{x}, #{y}\n"
505 emit "#{expr[0]} #{register}, #{x}, #{y}\n"
510 # Evaluates the expression +expr+ and stores the result in +register+.
511 def eval_expr expr, register
514 load_value_into_register expr[0], register
516 # Evaluate expression
520 auto_bytes expr[1], register
522 auto_words expr[1], register
525 emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
527 get_byte expr[1], expr[2], register
529 get_word expr[1], expr[2], register
531 load_value_into_register expr[1], register
532 with_temporary do |temporary|
533 emit "mvn #{temporary}, #0\n"
534 emit "eor #{register}, #{register}, #{temporary}\n"
538 eval_binop expr, register
540 raise "Not a magic word: #{op}"
546 # Export symbols from the current section
548 symbols.each { |sym| emit ".globl #{sym}\n" }
551 # Load byte from _base_ + _offset_ into _register_
552 def get_byte base, offset, register
553 # If base is an integer, but offset isn't, swap them
554 if !integer?(offset) && integer?(base)
555 base, offset = [offset, base]
559 with_temporary do |temporary|
560 base_reg = load_value base, temporary
562 emit "ldrb #{register}, [#{base_reg}]\n"
564 emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
568 with_temporaries(2) do |t1,t2|
569 base_reg = load_value base, t1
570 offset_reg = load_value offset, t2
571 emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
576 # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
577 def get_word base, offset, register
579 with_temporary do |temporary|
580 base_reg = load_value base, temporary
582 emit "ldr #{register}, [#{base_reg}]\n"
584 emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
588 with_temporaries(2) do |t1,t2|
589 base_reg = load_value base, t1
590 offset_reg = load_value offset, t2
591 emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
601 with_temporary do |temporary|
602 register = load_value label, temporary
603 emit "cpy pc, #{register}\n"
607 # If we have constants that need to be emitted, do so now
611 # Grows the current frame by n words, plus padding to
612 # respect alignment rules.
613 def grow_frame nwords
614 increment = stack_align(nwords * @WORDSIZE)
615 emit "sub sp, sp, \##{increment}\n"
616 @frame_size = @frame_size + increment
617 @frame_offset = @frame_offset + increment
620 # Start the false path of a conditional.
622 newlabel = @environment.gensym
626 @if_labels.push newlabel
629 # Test if x is equal to y
631 common_if :ifeq, x, y
634 # Test if x is greater than or equal to y
636 common_if :ifge, x, y
639 # Test if x is strictly greater than y
641 common_if :ifgt, x, y
644 # Test if x is less than or equal to y
646 common_if :ifle, x, y
649 # Test if x is strictly less than y
651 common_if :iflt, x, y
654 # Test if x different from y
656 common_if :ifne, x, y
659 # Import labels into the current section
661 # Record imported labels in @imports and @symbol_tracker
662 @imports.merge symbols
663 @symbol_tracker.define *symbols
666 # Introduce a new local variable
667 def let symbol, *expr
668 n = @environment.locals
669 register = local_register n
672 # We will use a register to store the value
673 @environment.add_local symbol, register
674 eval_expr expr, register
676 # We will use the stack to store the value
677 offset = local_offset n
678 @environment.add_local symbol, offset
679 with_temporary do |temporary|
680 eval_expr expr, temporary
681 emit "str #{temporary}, #{offset_reference offset}\n"
686 # Loads the value at the given address.
687 def load_at address, register
688 load_value_into_register address, register
689 emit "ldr #{register}, [#{register}]\n"
693 # Loads a value into some register.
694 # If the value is already in a register, does nothing.
695 # Else, loads the value into the register given as the
697 # Returns the name of the register the value is in.
698 def load_value x, register
699 ref = value_ref x, register
703 emit "mov #{register}, #{ref}\n"
708 # Loads a value into a specific register.
709 def load_value_into_register x, register
710 ref = value_ref x, register
713 emit "cpy #{register}, #{ref}\n"
715 emit "mov #{register}, #{ref}\n"
721 # Returns the fp-relative reference for the nth (0-based) local.
723 nstack_locals = n + number_of_register_arguments - @NREGISTER_LOCALS
724 -(nstack_locals + 1) * @WORDSIZE - @saved_size
727 # Given an offset, returns an fp-relative reference.
728 def offset_reference offset
729 "[#{@FP}, \##{offset}]"
732 # Returns true if the nth (0-based) local is stored in a register
733 def register_local? n
734 (n + number_of_register_arguments) < @NREGISTER_LOCALS
737 # Returns from a function.
739 # _words_ may contain an expression to be evaluated. The result
740 # of the evaluation is returned from the function.
742 # Compute return value and store it in @RETURN
743 eval_expr(words, @RETURN) unless words.empty?
745 goto @function_end_label
748 # Set a variable to the result of evaluating an expression
749 def set symbol, *expr
751 with_temporaries(2) do |t1,t2|
753 register = load_value symbol[1], t2
754 emit "str #{t1}, [#{register}]\n"
757 x = @environment[symbol]
759 raise "Cannot change value of constant #{symbol}"
760 elsif x.kind_of? Symbol
763 with_temporary do |temporary|
764 eval_expr expr, temporary
765 emit "str #{temporary}, #{offset_reference x}\n"
771 # Set the byte at _base_ + _offset_ to _value_
772 def set_byte base, offset, value
773 # If base is an integer, but offset isn't, swap them
774 if !integer?(offset) && integer?(base)
775 base, offset = [offset, base]
779 base_reg = load_value base, :a4
780 with_temporary do |temporary|
781 load_value_into_register value, temporary
783 emit "strb #{temporary}, [#{base_reg}]\n"
785 emit "strb #{temporary}, [#{base_reg}, \##{offset}]\n"
789 eval_binop [:add, base, offset], :a4
790 with_temporary do |temporary|
791 load_value_into_register value, temporary
792 emit "strb #{temporary}, [a4]\n"
797 # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
798 def set_word base, offset, value
799 # If base is an integer, but offset isn't, swap them
800 if !integer?(offset) && integer?(base)
801 base, offset = [offset, base]
805 base_reg = load_value base, :a4
806 with_temporary do |temporary|
807 load_value_into_register value, temporary
809 emit "str #{temporary}, [#{base_reg}]\n"
811 emit "str #{temporary}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
815 load_value_into_register base, :a4
816 with_temporary do |temporary|
817 load_value_into_register offset, temporary
818 emit "add a4, a4, #{temporary}, LSL #2\n"
819 load_value_into_register value, temporary
820 emit "str #{temporary}, [a4]\n"
825 # Define a string with the given value
828 value.each_byte do |b|
831 elsif b >= 32 && b < 127 && b != 34
834 code << sprintf("\\%03o", b)
837 emit ".ascii \"#{code}\"\n"
840 # Call a function, re-using the current call frame if possible.
841 def tail_call func, *args
842 # Compute number of stack arguments
843 nstackargs = number_of_stack_arguments args.length
844 # If we need more stack arguments than we have now,
845 # perform a normal call and return
846 if nstackargs > number_of_stack_arguments(@environment.args)
847 emit "# Not enough space for proper tail call; using regular call\n"
848 ret :call, func, *args
851 # We will assign arguments from left to right.
852 # Find places that we will overwrite before we read them,
853 # and store their values in some newly allocated stack space.
854 old_frame_offset = @frame_offset
855 old_frame_size = @frame_size
857 (@NREGISTER_ARGS...args.length).each do |i|
859 arg = arg[1] if at_expr? arg
861 binding = @environment[arg]
862 if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
864 # Argument i is a stack argument, but the value we will assign
865 # it is a stack argument that comes before it, so we will
866 # have overwritten it by the time we get to it.
867 overwritten[arg] = nil
872 unless overwritten.empty?
873 # Allocate space for arguments to be saved
874 grow_frame overwritten.length
877 overwritten.each_key do |key|
879 emit "str #{reg}, [sp, \##{offset}]\n"
880 overwritten[key] = offset
881 offset = offset + @WORDSIZE
886 args.each_index do |i|
889 load_value_into_register arg, "a#{i + 1}"
891 # Test if this is a value we saved
892 sym = at_expr?(arg) ? arg[1] : arg
893 saved = overwritten[sym]
895 # Saved value, load from stack
896 with_temporary do |temporary|
897 emit "ldr #{temporary}, [sp, \##{saved}]\n"
898 emit "str #{temporary}, #{arg_reference i}\n"
901 # Regular value, use load_value
902 with_temporary do |temporary|
903 reg = load_value arg, temporary
904 emit "str #{reg}, #{arg_reference i}\n"
910 with_temporary do |temporary|
911 # Load address of function to be called
912 load_value_into_register func, temporary
914 # Destroy current activation frame and enter func
916 emit "bx #{temporary}\n"
921 # Returns a reference to a value.
922 # For immediate values that fit in 8 bits, this returns the
923 # value itself (in ARM syntax).
924 # For all other values, loads the value into a register and
925 # returns the name of the register. If the value is already
926 # in a register, the name of that register is returned. Else,
927 # the value is loaded into the register specified as the
929 def value_ref x, register
931 x = substitute_number x[1]
935 if x >= 0 && x <= 255
937 elsif x >= -255 && x < 0
938 emit "mvn #{register}, \##{-(x + 1)}\n"
942 emit "ldr #{register}, #{lbl}\n"
946 binding = @environment[x]
947 if binding.kind_of? Symbol
948 # Value is already in a register. Return register name.
950 elsif binding.kind_of? Integer
951 # Value is on the stack. Load from the stack.
952 emit "ldr #{register}, #{offset_reference binding}\n"
956 @symbol_tracker.use x
958 emit "ldr #{register}, #{lbl}\n"
962 load_at x[1], register
964 raise "Don't know how to load #{x.inspect}"
968 # Define a word with the given value
970 emit ".int #{value}\n"
975 # Register class for little endian ARM
976 Voodoo::CodeGenerator.register_generator ARMGasGenerator,
977 :architecture => :arm,