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
52 # saved r4 <-- r13 points here
56 # Inside a function, registers r4..r8 and r10 are used for local variables
57 # and function arguments, whereas r11 is used as a frame pointer.
59 # r12 is used as a temporary, and r3 is used when another temporary
62 class ARMGasGenerator < CommonCodeGenerator
65 @WORDSIZE = 1 << @WORDSIZE_BITS
67 @DATA_ALIGNMENT = @WORDSIZE
68 @FUNCTION_ALIGNMENT = @WORDSIZE
69 @STACK_ALIGNMENT_BITS = 3
70 @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
71 # Registers used for storing local variables.
72 @LOCAL_REGISTERS = [:r4, :r5, :r6, :r7, :r8, :r10]
73 # Set of registers used for storing local variables.
74 @LOCAL_REGISTERS_SET = Set.new @LOCAL_REGISTERS
75 # Registers to be saved by save-frame.
76 @SAVE_FRAME_REGISTERS = [:r4, :r5, :r6, :r7, :r8,
77 :r9, :r10, :r11, :r13, :r14]
78 # Hash from register names to offsets in saved frame.
79 @SAVED_FRAME_LAYOUT = {}
80 @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
81 @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
83 @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
86 @TEMPORARIES = [:r12, :r3, :r2, :r1]
90 @function_end_label = nil
93 @saved_registers = [] # registers we've saved in the current frame
95 @output_file_suffix = '.s'
97 :'bits-per-word' => '32',
98 :'byte-order' => 'little-endian',
99 :'bytes-per-word' => 4
102 # Create an entry in the constants table,
103 # returning the label that will refer to the constant.
104 # The value may be an integer or a label.
105 def add_constant value
107 @constants << [label, value]
111 # Returns the fp-relative offset for the nth (0-based) argument.
113 (n - @NREGISTER_ARGS) * @WORDSIZE
116 # Returns an fp-relative reference for the nth (0-based) argument.
118 offset_reference arg_offset(n)
121 # Return the register in which the nth (0-based) argument is stored, or
122 # nil if not stored in a register
124 if n < @NREGISTER_ARGS
125 # We copied the argument to one of the local registers.
132 def auto_bytes value, register
133 if value.kind_of? Integer
136 temporary = register == :sp ? @TEMPORARIES[0] : register
137 load_value_into_register value, temporary
138 auto_bytes_register temporary
140 emit "cpy #{register}, sp\n" unless register == :sp
143 # auto-bytes where the value is supplied in a register and the return
144 # value will be in sp. register must not be sp.
145 def auto_bytes_register register
146 temporary = register == @TEMPORARIES[0] ? :r3 : @TEMPORARIES[0]
147 emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
148 emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
149 emit "and #{register}, #{register}, #{temporary}\n"
150 emit "sub sp, #{register}\n"
153 def auto_words value, register
154 if value.kind_of? Integer
155 auto_bytes(value * @WORDSIZE, register)
157 raise "Can't use :sp as a register for auto_words" if register == :sp
158 load_value_into_register value, register
159 emit "lsl #{register}, #{register}, \##{@WORDSIZE_BITS}\n"
160 auto_bytes_register register
161 emit "cpy #{register}, sp\n"
165 # Begins a new block.
166 def begin_block *code
167 # If we are starting a block at top level, create a frame
168 if @environment == @top_level
169 nlocals = count_locals code
170 create_frame nlocals, false
172 @environment = Environment.new @environment
175 # Emit function prologue and declare _formals_ as function arguments
176 def begin_function formals, nlocals
177 if @environment != @top_level
178 raise "Can only begin a function at top level"
181 @function_end_label = gensym
182 environment = Environment.new @environment
183 formals.each_with_index do |formal, i|
184 if i < @NREGISTER_ARGS
185 environment.add_arg formal, arg_register(i)
187 environment.add_arg formal, arg_offset(i)
190 @environment = environment
191 emit_function_prologue formals, nlocals
194 # Define a byte with the given value
196 emit ".byte #{value}\n"
201 # Calculate how many arguments need to be pushed on
202 # the stack, and allocate space for them.
203 nstack_args = number_of_stack_arguments args.length
204 old_frame_offset = @frame_offset
205 old_frame_size = @frame_size
206 grow_frame nstack_args if nstack_args > 0
208 # Put stack arguments on the stack
209 (@NREGISTER_ARGS...args.length).each do |n|
210 with_temporary do |temporary|
211 load_value_into_register args[n], temporary
212 emit "str #{temporary}, " +
213 "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
217 # Put register arguments in the right registers
218 nregister_args = number_of_register_arguments args.length
219 nregister_args.times do |n|
220 load_value_into_register args[n], :"r#{n}"
227 with_temporary do |temporary|
228 func_reg = load_value func, temporary
229 emit "blx #{func_reg}\n"
233 # Restore original stack frame
234 if old_frame_size != @frame_size
235 emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
236 @frame_offset = old_frame_offset
237 @frame_size = old_frame_size
241 # Creates a stack frame for the given number of arguments
242 # and local variables.
243 def create_frame nvars, save_lr = true
244 # Calculate how many variables we will store in registers,
245 # and how many on the stack.
246 nregister_vars = [nvars, @NREGISTER_LOCALS].min
247 nstack_vars = nvars - nregister_vars
249 # Save the registers we will clobber to the stack.
251 nregister_vars.times do |i|
252 clobbered << @LOCAL_REGISTERS[i]
255 clobbered << :lr if save_lr
256 @saved_registers = clobbered
257 emit "stmfd sp!, {#{clobbered.join ', '}}\n"
258 emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
260 # Calculate frame size so that the stack pointer will
261 # be properly aligned at the end of emit_function_prologue.
262 @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
263 extra_space = @frame_size - clobbered.length * @WORDSIZE
265 emit "sub sp, sp, \##{extra_space}\n"
275 # Start a conditional using the specified branch instruction
276 # after the comparison.
277 def common_if comp, x, y = nil
278 with_temporary do |temporary|
279 xreg = load_value x, temporary
280 yreg = load_value y, :a4
282 falselabel = @environment.gensym
283 @if_labels.push falselabel
285 emit "cmp #{xreg}, #{yreg}\n"
286 lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
287 :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
288 emit "#{lut[comp]} #{falselabel}\n"
292 # Destroys the current stack frame.
293 # If ret is true, loads the saved value of lr into pc.
294 def destroy_frame ret = false
295 # Set sp back to where saved registers were stored
296 saved = @saved_registers
297 emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
300 index = saved.index :lr
304 raise "Request to load saved lr into pc, but lr has not been saved"
307 emit "ldmfd sp!, {#{saved.join ', '}}\n"
309 emit_constants if ret
312 # Aligns on the next multiple of +n+ bytes.
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 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 #{@LOCAL_REGISTERS[i]}, r#{i}\n"
344 # Loads a word into a register.
345 def emit_load_word register, base, offset
347 emit "ldr #{register}, [#{base}]\n"
349 emit "ldr #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
353 # Stores the value of a register in memory.
354 def emit_store_word register, base, offset
356 emit "str #{register}, [#{base}]\n"
358 emit "str #{register}, [#{base}, \##{offset * @WORDSIZE}]\n"
362 # Ends the current block.
364 # If we are returning to top level, restore stack pointer
365 # and saved registers.
366 if @environment.parent == @top_level
367 offset = @frame_size - @saved_registers.length * @WORDSIZE
369 emit "add sp, sp, \##{offset}\n"
371 emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
374 @saved_registers = []
376 # If we need to emit constants, do so now
377 unless @constants.empty?
384 # Restore old value of @environment
385 @environment = @environment.parent
388 # Ends a function body.
390 if @environment == @top_level
391 raise "Cannot end function when not in a function"
394 label @function_end_label
399 @saved_registers = []
400 @environment = @top_level
403 # Ends a conditional.
408 # Evaluate the binary operation expr and store the result in register
409 def eval_binop expr, register
412 # Emulation for div and mod, which ARM does not have instructions for
415 func = :"__aeabi_idiv"
416 import func unless @imports.has_key? func
417 call func, expr[1], expr[2]
418 emit "cpy #{register}, r0\n" if register != :r0
421 func = :"__aeabi_idivmod"
422 import func unless @imports.has_key? func
423 call func, expr[1], expr[2]
424 emit "cpy #{register}, r1\n" if register != :r1
428 with_temporaries(2) do |t1,t2|
429 x = load_value expr[1], t1
433 # Operand must be in a register for these ops.
434 y = load_value expr[2], t2
436 y = value_ref expr[2], t2
441 emit "lsr #{register}, #{x}, #{y}\n"
443 emit "orr #{register}, #{x}, #{y}\n"
445 # Can't store result in same register as first operand.
448 # All using the same register. Move x to a different
449 # register to make this work.
450 temp = (x == t1) ? t2 : t1
451 emit "cpy #{temp}, #{x}\n"
452 emit "mul #{register}, #{temp}, #{y}\n"
454 # Multiplication is commutative. Just swap x and y.
455 emit "mul #{register}, #{y}, #{x}\n"
458 # Common case, register and x are different.
459 emit "mul #{register}, #{x}, #{y}\n"
463 y = "\##{32 - expr[2]}"
465 emit "rsb #{y}, #{y}, #32\n"
467 emit "ror #{register}, #{x}, #{y}\n"
469 emit "lsl #{register}, #{x}, #{y}\n"
471 emit "lsr #{register}, #{x}, #{y}\n"
473 emit "eor #{register}, #{x}, #{y}\n"
475 emit "#{expr[0]} #{register}, #{x}, #{y}\n"
480 # Evaluates the expression +expr+ and stores the result in +register+.
481 def eval_expr expr, register
484 load_value_into_register expr[0], register
486 # Evaluate expression
490 auto_bytes expr[1], register
492 auto_words expr[1], register
495 emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
497 get_byte expr[1], expr[2], register
499 get_word expr[1], expr[2], register
501 load_value_into_register expr[1], register
502 with_temporary do |temporary|
503 emit "mvn #{temporary}, #0\n"
504 emit "eor #{register}, #{register}, #{temporary}\n"
508 eval_binop expr, register
510 raise "Not a magic word: #{op}"
516 # Export symbols from the current section
518 symbols.each { |sym| emit ".globl #{sym}\n" }
521 # Load byte from _base_ + _offset_ into _register_
522 def get_byte base, offset, register
523 # If base is an integer, but offset isn't, swap them
524 if !integer?(offset) && integer?(base)
525 base, offset = [offset, base]
529 with_temporary do |temporary|
530 base_reg = load_value base, temporary
532 emit "ldrb #{register}, [#{base_reg}]\n"
534 emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
538 with_temporaries(2) do |t1,t2|
539 base_reg = load_value base, t1
540 offset_reg = load_value offset, t2
541 emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
546 # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
547 def get_word base, offset, register
549 with_temporary do |temporary|
550 base_reg = load_value base, temporary
552 emit "ldr #{register}, [#{base_reg}]\n"
554 emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
558 with_temporaries(2) do |t1,t2|
559 base_reg = load_value base, t1
560 offset_reg = load_value offset, t2
561 emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
571 with_temporary do |temporary|
572 register = load_value label, temporary
573 emit "cpy pc, #{register}\n"
577 # If we have constants that need to be emitted, do so now
581 # Grows the current frame by n words, plus padding to
582 # respect alignment rules.
583 def grow_frame nwords
584 increment = stack_align(nwords * @WORDSIZE)
585 emit "sub sp, sp, \##{increment}\n"
586 @frame_size = @frame_size + increment
587 @frame_offset = @frame_offset + increment
590 # Start the false path of a conditional.
592 newlabel = @environment.gensym
596 @if_labels.push newlabel
599 # Test if x is equal to y
601 common_if :ifeq, x, y
604 # Test if x is greater than or equal to y
606 common_if :ifge, x, y
609 # Test if x is strictly greater than y
611 common_if :ifgt, x, y
614 # Test if x is less than or equal to y
616 common_if :ifle, x, y
619 # Test if x is strictly less than y
621 common_if :iflt, x, y
624 # Test if x different from y
626 common_if :ifne, x, y
629 # Import labels into the current section
631 # Record imported labels in @imports
632 symbols.each { |sym| @imports[sym] = sym }
640 # Introduce a new local variable
641 def let symbol, *expr
642 n = @environment.locals
643 register = local_register n
646 # We will use a register to store the value
647 @environment.add_local symbol, register
648 eval_expr expr, register
650 # We will use the stack to store the value
651 offset = local_offset n
652 @environment.add_local symbol, offset
653 with_temporary do |temporary|
654 eval_expr expr, temporary
655 emit "str #{temporary}, #{offset_reference offset}\n"
660 # Loads the value at the given address.
661 def load_at address, register
662 load_value_into_register address, register
663 emit "ldr #{register}, [#{register}]\n"
667 # Loads a value into some register.
668 # If the value is already in a register, does nothing.
669 # Else, loads the value into the register given as the
671 # Returns the name of the register the value is in.
672 def load_value x, register
673 ref = value_ref x, register
677 emit "mov #{register}, #{ref}\n"
682 # Loads a value into a specific register.
683 def load_value_into_register x, register
684 ref = value_ref x, register
687 emit "cpy #{register}, #{ref}\n"
689 emit "mov #{register}, #{ref}\n"
695 # Returns the fp-relative reference for the nth (0-based) local.
697 -@INITIAL_FRAME_SIZE - ((n + number_of_register_arguments) * @WORDSIZE)
700 # Given an offset, returns an fp-relative reference.
701 def offset_reference offset
702 "[#{@FP}, \##{offset}]"
705 # Returns true if the nth (0-based) local is stored in a register
706 def register_local? n
707 (n + number_of_register_arguments) < @NREGISTER_LOCALS
710 # Returns from a function.
712 # _words_ may contain an expression to be evaluated. The result
713 # of the evaluation is returned from the function.
715 # Compute return value and store it in @RETURN
716 eval_expr(words, @RETURN) unless words.empty?
718 goto @function_end_label
721 # Set a variable to the result of evaluating an expression
722 def set symbol, *expr
724 with_temporaries(2) do |t1,t2|
726 register = load_value symbol[1], t2
727 emit "str #{t1}, [#{register}]\n"
730 x = @environment[symbol]
732 raise "Cannot change value of constant #{symbol}"
733 elsif x.kind_of? Symbol
736 with_temporary do |temporary|
737 eval_expr expr, temporary
738 emit "str #{temporary}, #{offset_reference x}\n"
744 # Set the byte at _base_ + _offset_ to _value_
745 def set_byte base, offset, value
746 # If base is an integer, but offset isn't, swap them
747 if !integer?(offset) && integer?(base)
748 base, offset = [offset, base]
752 base_reg = load_value base, :a4
753 with_temporary do |temporary|
754 load_value_into_register value, temporary
756 emit "strb #{temporary}, [#{base_reg}]\n"
758 emit "strb #{temporary}, [#{base_reg}, \##{offset}]\n"
762 eval_binop [:add, base, offset], :a4
763 with_temporary do |temporary|
764 load_value_into_register value, temporary
765 emit "strb #{temporary}, [a4]\n"
770 # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
771 def set_word base, offset, value
772 # If base is an integer, but offset isn't, swap them
773 if !integer?(offset) && integer?(base)
774 base, offset = [offset, base]
778 base_reg = load_value base, :a4
779 with_temporary do |temporary|
780 load_value_into_register value, temporary
782 emit "str #{temporary}, [#{base_reg}]\n"
784 emit "str #{temporary}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
788 load_value_into_register base, :a4
789 with_temporary do |temporary|
790 load_value_into_register offset, temporary
791 emit "add a4, a4, #{temporary}, LSL #2\n"
792 load_value_into_register value, temporary
793 emit "str #{temporary}, [a4]\n"
798 # Define a string with the given value
801 value.each_byte do |b|
804 elsif b >= 32 && b < 127 && b != 34
807 code << sprintf("\\%03o", b)
810 emit ".ascii \"#{code}\"\n"
813 # Call a function, re-using the current call frame if possible.
814 def tail_call func, *args
815 # Compute number of stack arguments
816 nstackargs = number_of_stack_arguments args.length
817 # If we need more stack arguments than we have now,
818 # perform a normal call and return
819 if nstackargs > number_of_stack_arguments(@environment.args)
820 emit "# Not enough space for proper tail call; using regular call\n"
821 ret :call, func, *args
824 # We will assign arguments from left to right.
825 # Find places that we will overwrite before we read them,
826 # and store their values in some newly allocated stack space.
827 old_frame_offset = @frame_offset
828 old_frame_size = @frame_size
830 (@NREGISTER_ARGS...args.length).each do |i|
832 arg = arg[1] if at_expr? arg
834 binding = @environment[arg]
835 if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
837 # Argument i is a stack argument, but the value we will assign
838 # it is a stack argument that comes before it, so we will
839 # have overwritten it by the time we get to it.
840 overwritten[arg] = nil
845 unless overwritten.empty?
846 # Allocate space for arguments to be saved
847 grow_frame overwritten.length
850 overwritten.each_key do |key|
852 emit "str #{reg}, [sp, \##{offset}]\n"
853 overwritten[key] = offset
854 offset = offset + @WORDSIZE
859 args.each_index do |i|
862 load_value_into_register arg, "a#{i + 1}"
864 # Test if this is a value we saved
865 sym = at_expr?(arg) ? arg[1] : arg
866 saved = overwritten[sym]
868 # Saved value, load from stack
869 with_temporary do |temporary|
870 emit "ldr #{temporary}, [sp, \##{saved}]\n"
871 emit "str #{temporary}, #{arg_reference i}\n"
874 # Regular value, use load_value
875 with_temporary do |temporary|
876 reg = load_value arg, temporary
877 emit "str #{reg}, #{arg_reference i}\n"
883 with_temporary do |temporary|
884 # Load address of function to be called
885 load_value_into_register func, temporary
887 # Destroy current activation frame and enter func
889 emit "bx #{temporary}\n"
894 # Returns a reference to a value.
895 # For immediate values that fit in 8 bits, this returns the
896 # value itself (in ARM syntax).
897 # For all other values, loads the value into a register and
898 # returns the name of the register. If the value is already
899 # in a register, the name of that register is returned. Else,
900 # the value is loaded into the register specified as the
902 def value_ref x, register
904 x = substitute_number x[1]
908 if x >= 0 && x <= 255
910 elsif x >= -255 && x < 0
911 emit "mvn #{register}, \##{-(x + 1)}\n"
915 emit "ldr #{register}, #{lbl}\n"
919 binding = @environment[x]
920 if binding.kind_of? Symbol
921 # Value is already in a register. Return register name.
923 elsif binding.kind_of? Integer
924 # Value is on the stack. Load from the stack.
925 emit "ldr #{register}, #{offset_reference binding}\n"
930 emit "ldr #{register}, #{lbl}\n"
934 load_at x[1], register
936 raise "Don't know how to load #{x.inspect}"
940 # Define a word with the given value
942 emit ".int #{value}\n"
947 # Register class for little endian ARM
948 Voodoo::CodeGenerator.register_generator ARMGasGenerator,
949 :architecture => :arm,