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