Implemented blocks for MIPS.
[voodoo-lang.git] / lib / voodoo / generators / mips_gas_generator.rb
blob561f3e8244cf2cdab7b79a92ee90abede6430159
1 require 'voodoo/generators/common_code_generator'
3 module Voodoo
4   # = MIPS GNU Assembler Code Generator
5   #
6   # The MIPS code generator generates i386 assembly code for use with
7   # the GNU assembler.
8   #
9   # == Calling Convention
10   #
11   # The first four arguments are passed in the registers $4 through $7.
12   # Any additional arguments are passed on the stack, starting at
13   # $sp + 16. Words $sp through $sp + 12 will be available for the called
14   # function to use. $sp will always be a multiple of 8.
15   #
16   # The return address for the called function is passed in $31.
17   #
18   # When performing a position-independent call, the address of the called
19   # function is passed in $25.
20   #
21   # The called function will store its return value in $2.
22   #
23   # The called function is required to preserve the values of registers
24   # $16 through $23 and register $30.
25   #
26   # This calling convention is compatible with the System V ELF ABI.
27   #
28   # == Call Frames
29   #
30   # Call frames have the following layout:
31   #
32   # When a function is called, it receives a stack frame that looks like
33   # the following:
34   #
35   #   :
36   #   old frame
37   #   argn
38   #   :
39   #   arg4
40   #   empty3
41   #   empty2
42   #   empty1
43   #   empty0    <-- $sp points here
44   #
45   # The function prologue of functions generated by this code generator
46   # creates activiation frames that look as follows:
47   #
48   # :
49   # old frame
50   # argn
51   # :
52   # arg4
53   # arg3
54   # arg2
55   # arg1
56   # arg0
57   # return address
58   # pointer to Global Offset Table
59   # local0
60   # :
61   # local7
62   # local8
63   # :
64   # localn
65   # padding    <-- $sp points here
66   #
67   # In words:
68   #
69   # The four empty slots provided by the caller are used to store
70   # arguments 0 through 3 (originally passed in $4 through $7),
71   # if necessary.
72   #
73   # The stack frame created below the four slots provided by the caller
74   # contains the following data, in order:
75   #
76   # - Saved return address (originally passed in $31), if necessary.
77   #
78   # - Saved pointer to global offset table (computed from $25), if necessary.
79   #
80   # - Saved values of caller's locals 0 through 7
81   #   (originally in $16 through $23), if necessary.
82   #
83   # - Values of our locals > 8, if necessary.
84   #
85   # - Padding to align $sp on a multiple of 8, if necessary.
86   #
87   #
88   # In accordance with the System V ELF ABI for MIPS, the pointer to
89   # the global offset table is calculated as follows:
90   #
91   # $gp = _gp_disp + $25
92   #
93   # where $gp is the register to store the pointer, $25 is the register
94   # holding the address of the called function, and _gp_disp is the
95   # offset between the beginning of the function and the global offset table.
96   #
97   class MIPSGasGenerator < CommonCodeGenerator
98     def initialize params
99       @WORDSIZE = 4
100       @CODE_ALIGNMENT = 0
101       @DATA_ALIGNMENT = @WORDSIZE
102       @FUNCTION_ALIGNMENT = @WORDSIZE
104       @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
105       @REGISTER_ARG_BASE = 4
106       @NREGISTER_ARGS = 4
107       @REGISTER_LOCAL_BASE = 16
108       @NREGISTER_LOCALS = 8
109       @RETURN = :'$2'
110       @TEMPORARY = :'$1'
111       @FUNCTION = :'$25'
112       @GOT = :'$28'
113       @TEMPORARIES = [:'$8', :'$9', :'$10', :'$11',
114                       :'$12', :'$13', :'$14', :'$15']
115       @function_end_label = nil
116       @imports = {}
117       @if_labels = []
118       super params
119       @output_file_suffix = '.s'
120     end
122     def align alignment = nil
123       unless alignment
124         # Get default alignment
125         case @section
126         when :code
127           alignment = @CODE_ALIGNMENT
128         when :data
129           alignment = @DATA_ALIGNMENT
130         when :function
131           alignment = @FUNCTION_ALIGNMENT
132         else
133           # Use data alignment as default
134           alignment = @DATA_ALIGNMENT
135         end
136       end
137       emit ".align #{alignment}\n" unless alignment == 0
138     end
140     # Return the offset from $sp at which the nth (0-based) argument is
141     # stored.
142     def arg_offset n
143       @frame_size + n * @WORDSIZE
144     end
146     # Return an $sp-relative reference for the nth (0-based) argument
147     def arg_reference n
148       "#{arg_offset n}($sp)"
149     end
151     # Return the register in which the nth (0-based) argument is stored, or
152     # nil if not stored in a register
153     def arg_register n
154       if register_arg? n
155         "$#{@REGISTER_ARG_BASE + n}"
156       else
157         nil
158       end
159     end
161     # Test if op is a binary operation
162     def assymetric_binop? op
163       [:div, :mod, :sub].member?(op)
164     end
166     # Test if a value is an at-expression
167     def at_expr? value
168       value.respond_to?(:[]) && value[0] == :'@'
169     end
171     # Begins a new block.
172     def begin_block *code
173       emit "# begin block\n"
174       # If we are at top-level, create a frame
175       if @environment == @top_level
176         create_frame count_locals(code)
177       end
178       environment = Environment.new @environment
179       @environment = environment
180     end
182     # Emit function prologue and declare _formals_ as function arguments
183     def begin_function formals, nlocals
184       if @environment != @top_level
185         raise "Cannot begin function when already in a function"
186       end
188       emit "# function #{formals.join ' '}\n"
189       environment = Environment.new @environment
190       environment.add_args formals
191       @environment = environment
192       @function_end_label = gensym
193       emit_function_prologue formals, nlocals
194     end
196     # Test if op is a binary operation
197     def binop? op
198       assymetric_binop?(op) || symmetric_binop?(op)
199     end
201     # Define a byte with the given value
202     def byte value
203       emit ".byte #{value}\n"
204     end
206     # Call a function.
207     def call func, *args
208       emit "# call #{func} #{args.join ' '}\n"
209       # Grow the stack frame, subject to 3 conditions:
210       # 1. There must be enough space to hold all arguments
211       # 2. $sp must remain a multiple of 8
212       # 3. We must provide space for at least 4 words
213       increment = ([args.length, 4].max * @WORDSIZE + 7) / 8 * 8
214       emit "addiu $sp, $sp, -#{increment}\n"
215       @frame_size = @frame_size + increment
217       # Put arguments in the right places
218       n = 0
219       while n < args.length
220         if n < @NREGISTER_ARGS
221           # Put arguments up to @NREGISTER_ARGS in registers
222           load_value_into_register args[n], arg_register(n)
223         else
224           # Put other arguments on the stack
225           load_value_into_register args[n], @TEMPORARY
226           emit "sw #{@TEMPORARY}, #{n * @WORDSIZE}($sp)\n"
227         end
228         n = n + 1
229       end
231       # Load function address
232       if global? func
233         if @imports.has_key? func
234           # Load address from global offset table
235           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
236         else
237           # Assume label defined in this module
238           emit "lui #{@FUNCTION}, %hi(#{func})\n"
239           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
240         end
241       else
242         # Load address
243         load_value_into_register func, "#{@FUNCTION}"
244       end
246       # Perform call
247       emit "jalr #{@FUNCTION}\n"
248       # brach delay slot
249       emit "nop\n"
251       # Restore original stack frame
252       emit "addiu $sp, $sp, #{increment}\n"
253       @frame_size = @frame_size - increment
255       # restore gp
256       emit "lw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
257     end
259     # Start a conditional using the specified branch instruction
260     # after the comparison.
261     def common_if comp, x, y = nil
262       emit "# #{comp} #{x} #{y}\n"
264       temporaries = @TEMPORARIES.dup
265       xreg = load_value x, temporaries[0]
266       temporaries.delete xreg
267       yreg = load_value y, temporaries[0]
268       temporaries.delete yreg
270       falselabel = @environment.gensym
271       @if_labels.push falselabel
273       case comp
274       when :ifeq
275         emit "bne #{xreg}, #{yreg}, #{falselabel}\n"
276       when :ifge
277         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
278         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
279       when :ifgt
280         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
281         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
282       when :ifle
283         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
284         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
285       when :iflt
286         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
287         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
288       when :ifne
289         emit "beq #{xreg}, #{yreg}, #{falselabel}\n"
290       else
291         raise "Unknown conditional: #{comp}"
292       end
293       emit "nop\n"
294     end
296     # Counts the number of local variables created in
297     # a sequence of statements.
298     def count_locals statements
299        count = 0
300        each_statement(statements) do |statement|
301          if statement[0] == :let
302            # let introduces a single local
303            count = count + 1
304          end
305        end
306        count
307     end
309     # Creates an activation frame which can store nlocals local variables
310     def create_frame nlocals
311       @frame_size = (@INITIAL_FRAME_SIZE + nlocals * @WORDSIZE + 7) / 8 * 8
312       emit "addiu $sp, $sp, -#{@frame_size}\n"
313     end
315     # Emit function prologue.
316     def emit_function_prologue formals = [], nlocals = 0
317       # Calculate new value for $gp
318       emit "lui #{@GOT}, %hi(_gp_disp)\n"
319       emit "addiu #{@GOT}, %lo(_gp_disp)\n"
320       emit "addu #{@GOT}, #{@GOT}, #{@FUNCTION}\n"
322       # Save parameters 0 .. 3 in the stack space that the caller
323       # should have allocated for them.
324       [@NREGISTER_ARGS, formals.length].min.times do |n|
325         emit "sw $#{n + @REGISTER_ARG_BASE}, #{n * @WORDSIZE}($29)\n"
326       end
328       create_frame nlocals
330       # Save return address
331       emit "sw $31, #{@frame_size - @WORDSIZE}($sp)\n"
333       # Save gp
334       emit "sw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
335     end
337     # End a function body
338     def end_function
339       if @environment == @top_level
340         raise "Cannot end function when not in a function"
341       end
343       emit "# function epilogue\n"
345       label @function_end_label
346       # Restore saved locals
347       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
348         emit "lw #{local_register n}, #{local_reference n}\n"
349       end
350       # Load return address
351       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
352       # Restore stack pointer
353       emit "addiu $sp, $sp, #{@frame_size}\n"
354       # Return
355       emit "jr $31\n"
356       emit "nop\n"
358       emit "# end function\n\n"
360       @function_end_label = nil
361       @environment = @top_level
362     end
364     # Ends the current block.
365     def end_block
366       emit "# end block\n"
368       # If we are returning to top level, restore stack pointer
369       if @environment.parent == @top_level
370         emit "addiu $sp, $sp, #{@frame_size}\n"
371       end
373       # Restore old value of @environment
374       @environment = @environment.parent
375     end
377     # End a conditional.
378     def end_if
379       label = @if_labels.pop
380       emit "#{label}:\n"
381     end
383     # Evaluate the binary operation expr and store the result in register
384     def eval_binop expr, register
385       temporaries = @TEMPORARIES.dup
386       x = load_value expr[1], temporaries[0]
387       temporaries.delete x
388       y = load_value expr[2], temporaries[0]
389       temporaries.delete y
391       case expr[0]
392       when :div
393         emit "div $0, #{x}, #{y}\n"
394         emit "mflo #{register}\n"
395       when :mod
396         emit "div $0, #{x}, #{y}\n"
397         emit "mfhi #{register}\n"
398       when :mul
399         emit "mult #{x}, #{y}\n"
400         emit "mflo #{register}\n"
401       else
402         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
403       end
404     end
406     # Evaluate the expression expr and store the result in register
407     def eval_expr expr, register
408       if expr.length == 1
409         # Load value
410         load_value_into_register expr[0], register
411       else
412         # Evaluate expression
413         op = expr[0]
414         case op
415         when :call
416           call *expr[1..-1]
417           emit "move #{register}, #{@RETURN}\n" if register != @RETURN
418         when :'get-byte'
419           get_byte expr[1], expr[2], register
420         when :'get-word'
421           get_word expr[1], expr[2], register
422         when :not
423             eval_binop [:nor, 0, expr[1]], register
424         else
425           if binop? op
426             eval_binop expr, register
427           else
428             raise "Not a magic word: #{op}"
429           end
430         end
431       end
432     end
434     # Export symbols from the current section
435     def export *symbols
436       symbols.each { |sym| emit ".globl #{sym}\n" }
437     end
439     # Add a function to the current section
440     def function formals, *code
441       nlocals = count_locals code
442       begin_function formals, nlocals
443       code.each { |action| add section, action }
444       end_function
445     end
447     # Load byte from _base_ + _offset_ into _register_
448     def get_byte base, offset, register
449       # If base is an integer, but offset isn't, swap them
450       if !integer?(offset) && integer?(base)
451         base, offset = [offset, base]
452       end
454       if integer? offset
455         base_reg = load_value base
456         emit "lb #{register}, #{offset}(#{base_reg})\n"
457       else
458         eval_binop [:add, base, offset], @TEMPORARY
459         emit "lb #{register}, 0(#{@TEMPORARY})\n"
460       end
461     end
463     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
464     def get_word base, offset, register
465       if integer? offset
466         base_reg = load_value base
467         emit "lw #{register}, #{offset * @WORDSIZE}(#{base_reg})\n"
468       else
469         offset_reg = @TEMPORARIES.pop
470         begin
471           load_value_into_register offset, offset_reg
472           base_reg = load_value base
473           emit "sll #{offset_reg}, #{offset_reg}, 2\n" # multiply by @WORDSIZE
474           emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
475           emit "lw #{register}, 0(#{@TEMPORARY})\n"
476         ensure
477           @TEMPORARIES.push offset_reg
478         end
479       end
480     end
482     # Test if a symbol refers to a global
483     def global? symbol
484       symbol?(symbol) && @environment[symbol] == nil
485     end
487     # Jump to a label.
488     def goto label
489       emit "j #{label}\n"
490       emit "nop\n"
491     end
493     # Start the false path of a conditional.
494     def ifelse
495       emit "# else\n"
496       newlabel = @environment.gensym
497       emit "j #{newlabel}\n"
498       emit "nop\n"
499       label = @if_labels.pop
500       emit "#{label}:\n"
501       @if_labels.push newlabel
502     end
504     # Test if x is equal to y
505     def ifeq x, y
506       common_if :ifeq, x, y
507     end
509     # Test if x is greater than or equal to y
510     def ifge x, y
511       common_if :ifge, x, y
512     end
514     # Test if x is strictly greater than y
515     def ifgt x, y
516       common_if :ifgt, x, y
517     end
519     # Test if x is less than or equal to y
520     def ifle x, y
521       common_if :ifle, x, y
522     end
524     # Test if x is strictly less than y
525     def iflt x, y
526       common_if :iflt, x, y
527     end
529     # Test if x different from y
530     def ifne x, y
531       common_if :ifne, x, y
532     end
534     # Import labels into the current section
535     def import *symbols
536       # Record imported labels in @imports
537       symbols.each { |sym| @imports[sym] = sym }
538     end
540     # Test if a value is an integer
541     def integer? value
542       value.kind_of? Integer
543     end
545     # Emit a label
546     def label name
547       emit "#{name}:\n"
548     end
550     # Introduce a new local variable
551     def let symbol, *expr
552       emit "# let #{symbol} #{expr.join ' '}\n"
553       n = @environment.locals
554       @environment.add_local symbol
556       # Extend stack frame, if necessary.
557       # This should never be necessary, because we allocate enough
558       # space in the top-level function or block.
559       if @environment.locals > max_locals
560         $stderr.puts "WARNING: Stack frame too small. Possible BUG"
561         $stderr.puts "Frame size #{@frame_size}, max locals #{max_locals}" +
562                      ", actual locals #{@environment.locals}"
563         # Extend frame by 8 bytes, to keep $sp a multiple of 8
564         emit "addiu $sp, $sp, -8\n"
565         @frame_size = @frame_size + 8
566       end
568       register = local_register n
569       ref = local_reference n
570       if register
571         # We will use a register to store the value
572         # Save current value of register
573         emit "sw #{register}, #{ref}\n"
574         # Set new value
575         eval_expr expr, register
576       else
577         # We will use the stack to store the value
578         eval_expr expr, @TEMPORARY
579         emit "sw #{@TEMPORARY}, #{ref}\n"
580       end
581     end
583     # Load the value at the given address.
584     def load_at address, register = @TEMPORARY
585       load_value_into_register address, register
586       emit "lw #{register}, 0(#{register})\n"
587       register
588     end
590     # Load a value into a register.
591     # Returns the name of the register.
592     # If the value was already in a register, the name of that
593     # register is returned.
594     # Else, the value is loaded into a register and the name of
595     # that register is returned. The register to use in that case
596     # may be specified using the optional second argument.
597     def load_value x, register = @TEMPORARY
598       if x == 0
599         return "$0"
600       elsif integer? x
601         if x >= -32768 && x <= 32767
602           emit "addiu #{register}, $0, #{x}\n"
603           return register
604         else
605           emit "lui #{register}, #{x >> 16}\n"
606           emit "ori #{register}, #{register}, #{x & 0xffff}\n"
607           return register
608         end
609       elsif symbol? x
610         binding = @environment[x]
611         if binding
612           case binding[0]
613           when :arg
614             emit "lw #{register}, #{arg_reference binding[1]}\n"
615             return register
616           when :local
617             n = binding[1]
618             if register_local? n
619               return local_register(n)
620             else
621               emit "lw #{register}, #{local_reference n}\n"
622               return register
623             end
624           else
625             raise "Don't know how to load #{x.inspect}"
626           end
627         else
628           # Assume global
629           emit "lui #{register}, %hi(#{x})\n"
630           emit "addiu #{register}, %lo(#{x})\n"
631           return register
632         end
633       elsif at_expr? x
634         load_at x[1], register
635       else
636         raise "Don't know how to load #{x.inspect}"
637       end
638     end
640     # Load a value into a specific register
641     def load_value_into_register x, register
642       reg = load_value x, register
643       if reg != register
644         emit "move #{register}, #{reg}\n"
645       end
646     end
648     # Return the offset from $sp at which the nth (0-based) local variable is
649     # stored. For register locals this is the offset at which the saved
650     # value (from the calling function) is stored.
651     def local_offset n
652       @frame_size - @INITIAL_FRAME_SIZE - (n + 1) * @WORDSIZE
653     end
655     # Return an $sp-relative reference for the nth (0-based) local
656     def local_reference n
657       "#{local_offset n}($sp)"
658     end
660     # Return the register in which the nth local (0-based) is stored, or
661     # nil if not stored in a register
662     def local_register n
663       if register_local? n
664         "$#{@REGISTER_LOCAL_BASE + n}"
665       else
666         nil
667       end
668     end
670     # Compute the maximum number of locals that would fit in the current
671     # frame size.
672     def max_locals
673       (@frame_size - @INITIAL_FRAME_SIZE) / @WORDSIZE
674     end
676     # Calculate the number of stack arguments,
677     # given the total number of arguments.
678     def number_of_stack_arguments n
679       [0, n - @NREGISTER_ARGS].max
680     end
682     # Returns true if the nth (0-based) argument is stored in a register
683     def register_arg? n
684       n < @NREGISTER_ARGS
685     end
687     # Returns true if the nth (0-based) local is stored in a register
688     def register_local? n
689       n < @NREGISTER_LOCALS
690     end
692     # Return a from a function.
693     # 
694     # _words_ may contain an expression to be evaluated. The result
695     # of the evaluation is returned from the function.
696     def ret *words
697       emit "# return #{words.join ' '}\n"
698       # Compute return value and store it in @RETURN
699       eval_expr(words, @RETURN) unless words.empty?
700       # Go to epilogue
701       goto @function_end_label
702     end
703     
704     # Set a variable to the result of evaluating an expression
705     def set symbol, *expr
706       emit "# set #{symbol} #{expr.join ' '}\n"
708       x = @environment[symbol]
709       if x == nil
710         raise "Cannot change value of constant #{symbol}"
711       end
713       if x[0] == :local
714         register = local_register x[1]
715       else
716         register = nil
717       end
719       if register
720         # Set new value
721         eval_expr expr, register
722       else
723         case x[0]
724         when :local
725           ref = local_reference x[1]
726         when :arg
727           ref = arg_reference x[1]
728         else
729           raise "??? #{sym} is neither a local nor an argument"
730         end
731         eval_expr expr, @TEMPORARY
732         emit "sw #{@TEMPORARY}, #{ref}\n"
733       end
734     end
736     # Set the byte at _base_ + _offset_ to _value_
737     def set_byte base, offset, value
738       emit "# set-byte #{base} #{offset} #{value}\n"
739       # If base is an integer, but offset isn't, swap them
740       if !integer?(offset) && integer?(base)
741         base, offset = [offset, base]
742       end
744       value_reg = @TEMPORARIES.pop
745       load_value_into_register value, value_reg
746       begin
747         if integer? offset
748           base_reg = load_value base
749           emit "sb #{value_reg}, #{offset}(#{base_reg})\n"
750         else
751           eval_binop [:add, base, offset], @TEMPORARY
752           emit "sb #{value_reg}, 0(#{@TEMPORARY})\n"
753         end
754       ensure
755         @TEMPORARIES.push value_reg
756       end
757     end
759     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
760     def set_word base, offset, value
761       emit "# set-word #{base} #{offset} #{value}\n"
763       value_reg = @TEMPORARIES.pop
764       load_value_into_register value, value_reg
765       begin
766         if integer? offset
767           base_reg = load_value base
768           emit "sw #{value_reg}, #{offset * @WORDSIZE}(#{base_reg})\n"
769         else
770           offset_reg = @TEMPORARIES.pop
771           begin
772             load_value_into_register offset, offset_reg
773             base_reg = load_value base
774             emit "sll #{offset_reg}, #{offset_reg}, 2\n"
775             emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
776             emit "sw #{value_reg}, 0(#{@TEMPORARY})\n"
777           ensure
778             @TEMPORARIES.push offset_reg
779           end
780         end
781       ensure
782         @TEMPORARIES.push value_reg
783       end
784     end
786     # Define a string with the given value
787     def string value
788       code = ''
789       value.each_byte do |b|
790         if b == 92
791           code << "\\\\"
792         elsif b >= 32 && b < 127 && b != 34
793           code << b.chr
794         else
795           code << sprintf("\\%03o", b)
796         end
797       end
798       emit ".ascii \"#{code}\"\n"
799     end
801     # Test if a value is a symbol
802     def symbol? value
803       value.kind_of? Symbol
804     end
806     # Test if op is a symmetric binary operation (i.e. it will yield the
807     # same result if the order of its source operands is changed).
808     def symmetric_binop? op
809       [:add, :and, :mul, :or, :xor].member? op
810     end
812     # Call a function, re-using the current call frame if possible.
813     def tail_call func, *args
814       emit "# tail-call #{func} #{args.join ' '}\n"
816       # Compute number of stack arguments
817       nstackargs = number_of_stack_arguments args.length
818       # If we need more stack arguments than we have now,
819       # perform a normal call and return
820       if nstackargs > number_of_stack_arguments(@environment.args)
821         emit "# Not enough space for proper tail call; using regular call\n"
822         ret :call, func, *args
823       end
825       # TODO
827       # Back up any stack arguments we will need after we overwrite them
828       temporaries = @TEMPORARIES.dup
829       nlocals = @environment.locals
830       (@NREGISTER_ARGS...args.length).each do |i|
831         x = @environment[args[i]]
832         if x && x[0] == :arg && x[1] >= @NREGISTER_ARGS && x[1] < i
833           # args[i] is a stack arg, but has an index < i
834           # That means that, by the time we get to pass arg[i] to the called
835           # function, it will have been overwritten. So we make a backup.
836           if temporaries.empty?
837             # Oh dear, we're out of temporaries.
838             # Store the value in the current stack frame, extending it
839             # as necessary.
840             if nlocals >= max_locals
841               emit "addiu $sp, -8\n"
842               @frame_size = @frame_size + 8
843             end
844             reg = load_value args[i]
845             emit "sw #{reg}, #{local_reference nlocals}\n"
846             args[i] = [:local, nlocals]
847             nlocals = nlocals + 1
848           else
849             # Load the argument into a temporary
850             reg = temporaries.shift
851             load_value_into_register args[i], reg
852             # Update args[i] so we know how to get to it later
853             args[i] = [:reg, reg]
854           end
855         end
856       end
858       # Set stack arguments
859       (@NREGISTER_ARGS...args.length).each do |i|
860         arg = args[i]
861         reg = @TEMPORARY
863         # Load value
864         if arg.kind_of? Array
865           # Special cases, created above
866           case arg[0]
867           when :reg
868             reg = arg[1]
869           when :local
870             emit "lw #{reg}, #{local_reference arg[1]}\n"
871           end
872         else
873           load_value_into_register arg, reg
874         end
876         # Store value in designated place
877         emit "sw #{reg}, #{arg_reference i}\n"
878       end
880       # Set register arguments
881       [@NREGISTER_ARGS,args.length].min.times do |i|
882         reg = arg_register i
883         load_value_into_register args[i], reg
884       end
886       # Restore saved registers
887       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
888         emit "lw #{local_register n}, #{local_reference n}\n"
889       end
890       # Restore return address
891       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
893       # Adjust stack pointer
894       emit "addiu $sp, #{@frame_size}\n"
896       # Load function address
897       if global? func
898         if @imports.has_key? func
899           # Load address from global offset table
900           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
901         else
902           # Assume label defined in this module
903           emit "lui #{@FUNCTION}, %hi(#{func})\n"
904           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
905         end
906       else
907         # Load address
908         load_value_into_register func, "#{@FUNCTION}"
909       end
911       # Perform call
912       emit "jr #{@FUNCTION}\n"
913       # brach delay slot
914       emit "nop\n"
915     end
917     # Define a word with the given value
918     def word value
919       emit ".int #{value}\n"
920     end
922     # Write generated code to the given IO object.
923     def write io
924       io.puts ".set noat"
925       @sections.each do |section,code|
926         unless code.empty?
927           io.puts ".section #{section.to_s}"
928           io.puts code
929           io.puts
930         end
931       end
932     end
934   end
936   # Register class for big endian MIPS
937   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
938                                            :architecture => :mips,
939                                            :format => :gas
942   # Register class for little endian MIPS
943   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
944                                            :architecture => :mipsel,
945                                            :format => :gas