MipsGasGenerator: added support for tail calls.
[voodoo-lang.git] / lib / voodoo / generators / mips_gas_generator.rb
blob782b6a4f2e8c2b728e718c404677bb67ae50a1ba
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     end
118     # Return the offset from $sp at which the nth (0-based) argument is
119     # stored.
120     def arg_offset n
121       @frame_size + n * @WORDSIZE
122     end
124     # Return an $sp-relative reference for the nth (0-based) argument
125     def arg_reference n
126       "#{arg_offset n}($sp)"
127     end
129     # Return the register in which the nth (0-based) argument is stored, or
130     # nil if not stored in a register
131     def arg_register n
132       if register_arg? n
133         "$#{@REGISTER_ARG_BASE + n}"
134       else
135         nil
136       end
137     end
139     # Test if op is a binary operation
140     def assymetric_binop? op
141       [:div, :mod, :sub].member?(op)
142     end
144     # Emit function prologue and declare _formals_ as function arguments
145     def begin_function formals, nlocals
146       if @environment != @top_level
147         raise "Cannot begin function when already in a function"
148       end
150       emit "# function #{formals.join ' '}\n"
151       environment = Environment.new @environment
152       environment.add_args formals
153       @environment = environment
154       @function_end_label = gensym
155       emit_function_prologue formals, nlocals
156     end
158     # Test if op is a binary operation
159     def binop? op
160       assymetric_binop?(op) || symmetric_binop?(op)
161     end
163     # Define a byte with the given value
164     def byte value
165       emit ".byte #{value}\n"
166     end
168     # Call a function.
169     def call func, *args
170       emit "# call #{func} #{args.join ' '}\n"
171       # Grow the stack frame, subject to 3 conditions:
172       # 1. There must be enough space to hold all arguments
173       # 2. $sp must remain a multiple of 8
174       # 3. We must provide space for at least 4 words
175       increment = ([args.length, 4].max * @WORDSIZE + 7) / 8 * 8
176       emit "addiu $sp, $sp, -#{increment}\n"
177       @frame_size = @frame_size + increment
179       # Put arguments in the right places
180       n = 0
181       while n < args.length
182         if n < @NREGISTER_ARGS
183           # Put arguments up to @NREGISTER_ARGS in registers
184           load_value_into_register args[n], arg_register(n)
185         else
186           # Put other arguments on the stack
187           load_value_into_register args[n], @TEMPORARY
188           emit "sw #{@TEMPORARY}, #{n * @WORDSIZE}($sp)\n"
189         end
190         n = n + 1
191       end
193       # Load function address
194       if global? func
195         if @imports.has_key? func
196           # Load address from global offset table
197           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
198         else
199           # Assume label defined in this module
200           emit "lui #{@FUNCTION}, %hi(#{func})\n"
201           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
202         end
203       else
204         # Load address
205         load_value_into_register func, "#{@FUNCTION}"
206       end
208       # Perform call
209       emit "jalr #{@FUNCTION}\n"
210       # brach delay slot
211       emit "nop\n"
213       # Restore original stack frame
214       emit "addiu $sp, $sp, #{increment}\n"
215       @frame_size = @frame_size - increment
217       # restore gp
218       emit "lw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
219     end
221     # Start a conditional using the specified branch instruction
222     # after the comparison.
223     def common_if comp, x, y = nil
224       emit "# #{comp} #{x} #{y}\n"
226       temporaries = @TEMPORARIES.dup
227       xreg = load_value x, temporaries[0]
228       temporaries.delete xreg
229       yreg = load_value y, temporaries[0]
230       temporaries.delete yreg
232       falselabel = @environment.gensym
233       @if_labels.push falselabel
235       case comp
236       when :ifeq
237         emit "bne #{xreg}, #{yreg}, #{falselabel}\n"
238       when :ifge
239         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
240         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
241       when :ifgt
242         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
243         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
244       when :ifle
245         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
246         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
247       when :iflt
248         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
249         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
250       when :ifne
251         emit "beq #{xreg}, #{yreg}, #{falselabel}\n"
252       else
253         raise "Unknown conditional: #{comp}"
254       end
255       emit "nop\n"
256     end
258     # Emit function prologue.
259     def emit_function_prologue formals = [], nlocals = 0
260       # Calculate new value for $gp
261       emit "lui #{@GOT}, %hi(_gp_disp)\n"
262       emit "addiu #{@GOT}, %lo(_gp_disp)\n"
263       emit "addu #{@GOT}, #{@GOT}, #{@FUNCTION}\n"
265       # Save parameters 0 .. 3 in the stack space that the caller
266       # should have allocated for them.
267       [@NREGISTER_ARGS, formals.length].min.times do |n|
268         emit "sw $#{n + @REGISTER_ARG_BASE}, #{n * @WORDSIZE}($29)\n"
269       end
271       # Create initial frame
272       @frame_size = (@INITIAL_FRAME_SIZE + nlocals * @WORDSIZE + 7) / 8 * 8
273       emit "addiu $sp, $sp, -#{@frame_size}\n"
275       # Save return address
276       emit "sw $31, #{@frame_size - @WORDSIZE}($sp)\n"
278       # Save gp
279       emit "sw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
280     end
282     # End a function body
283     def end_function
284       if @environment == @top_level
285         raise "Cannot end function when not in a function"
286       end
288       emit "# function epilogue\n"
290       label @function_end_label
291       # Restore saved locals
292       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
293         emit "lw #{local_register n}, #{local_reference n}\n"
294       end
295       # Load return address
296       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
297       # Restore stack pointer
298       emit "addiu $sp, $sp, #{@frame_size}\n"
299       # Return
300       emit "jr $31\n"
301       emit "nop\n"
303       emit "# end function\n\n"
305       @function_end_label = nil
306       @environment = @top_level
307     end
309     # End a conditional.
310     def end_if
311       label = @if_labels.pop
312       emit "#{label}:\n"
313     end
315     # Evaluate the binary operation expr and store the result in register
316     def eval_binop expr, register
317       temporaries = @TEMPORARIES.dup
318       x = load_value expr[1], temporaries[0]
319       temporaries.delete x
320       y = load_value expr[2], temporaries[0]
321       temporaries.delete y
323       case expr[0]
324       when :div
325         emit "div $0, #{x}, #{y}\n"
326         emit "mflo #{register}\n"
327       when :mod
328         emit "div $0, #{x}, #{y}\n"
329         emit "mfhi #{register}\n"
330       when :mul
331         emit "mult #{x}, #{y}\n"
332         emit "mflo #{register}\n"
333       else
334         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
335       end
336     end
338     # Evaluate the expression expr and store the result in register
339     def eval_expr expr, register
340       if expr.length == 1
341         # Load value
342         load_value_into_register expr[0], register
343       else
344         # Evaluate expression
345         op = expr[0]
346         case op
347         when :call
348           call *expr[1..-1]
349           emit "move #{register}, #{@RETURN}\n" if register != @RETURN
350         when :'get-byte'
351           get_byte expr[1], expr[2], register
352         when :'get-word'
353           get_word expr[1], expr[2], register
354         when :not
355             eval_binop [:nor, 0, expr[1]], register
356         else
357           if binop? op
358             eval_binop expr, register
359           else
360             raise "Not a magic word: #{op}"
361           end
362         end
363       end
364     end
366     # Export symbols from the current section
367     def export *symbols
368       symbols.each { |sym| emit ".globl #{sym}\n" }
369     end
371     # Add a function to the current section
372     def function formals, *code
373       # Set nlocals to the number of local variables in the function
374       nlocals = 0
375       code.each { |action| nlocals = nlocals + 1 if action[0] == :let }
376       begin_function formals, nlocals
377       code.each { |action| add section, action }
378       end_function
379     end
381     # Load byte from _base_ + _offset_ into _register_
382     def get_byte base, offset, register
383       # If base is an integer, but offset isn't, swap them
384       if !integer?(offset) && integer?(base)
385         base, offset = [offset, base]
386       end
388       if integer? offset
389         base_reg = load_value base
390         emit "lb #{register}, #{offset}(#{base_reg})\n"
391       else
392         eval_binop [:add, base, offset], @TEMPORARY
393         emit "lb #{register}, 0(#{@TEMPORARY})\n"
394       end
395     end
397     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
398     def get_word base, offset, register
399       if integer? offset
400         base_reg = load_value base
401         emit "lw #{register}, #{offset * @WORDSIZE}(#{base_reg})\n"
402       else
403         offset_reg = @TEMPORARIES.pop
404         begin
405           load_value_into_register offset, offset_reg
406           base_reg = load_value base
407           emit "sll #{offset_reg}, #{offset_reg}, 2\n" # multiply by @WORDSIZE
408           emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
409           emit "lw #{register}, 0(#{@TEMPORARY})\n"
410         ensure
411           @TEMPORARIES.push offset_reg
412         end
413       end
414     end
416     # Test if a symbol refers to a global
417     def global? symbol
418       symbol?(symbol) && @environment[symbol] == nil
419     end
421     # Jump to a label.
422     def goto label
423       emit "j #{label}\n"
424       emit "nop\n"
425     end
427     # Start the false path of a conditional.
428     def ifelse
429       emit "# else\n"
430       newlabel = @environment.gensym
431       emit "j #{newlabel}\n"
432       emit "nop\n"
433       label = @if_labels.pop
434       emit "#{label}:\n"
435       @if_labels.push newlabel
436     end
438     # Test if x is equal to y
439     def ifeq x, y
440       common_if :ifeq, x, y
441     end
443     # Test if x is greater than or equal to y
444     def ifge x, y
445       common_if :ifge, x, y
446     end
448     # Test if x is strictly greater than y
449     def ifgt x, y
450       common_if :ifgt, x, y
451     end
453     # Test if x is less than or equal to y
454     def ifle x, y
455       common_if :ifle, x, y
456     end
458     # Test if x is strictly less than y
459     def iflt x, y
460       common_if :iflt, x, y
461     end
463     # Test if x different from y
464     def ifne x, y
465       common_if :ifne, x, y
466     end
468     # Import labels into the current section
469     def import *symbols
470       # Record imported labels in @imports
471       symbols.each { |sym| @imports[sym] = sym }
472     end
474     # Test if a value is an integer
475     def integer? value
476       value.kind_of? Integer
477     end
479     # Emit a label
480     def label name
481       emit "#{name}:\n"
482     end
484     # Introduce a new local variable
485     def let symbol, *expr
486       emit "# let #{symbol} #{expr.join ' '}\n"
487       n = @environment.locals
488       @environment.add_local symbol
490       # Extend stack frame, if necessary
491       if @environment.locals > max_locals
492         $stderr.puts "WARNING: Stack frame too small. Possible BUG"
493         # Extend frame by 8 bytes, to keep $sp a multiple of 8
494         emit "addiu $sp, $sp, -8\n"
495         @frame_size = @frame_size + 8
496       end
498       register = local_register n
499       ref = local_reference n
500       if register
501         # Save current value of register
502         emit "sw #{register}, #{ref}\n"
503         # Set new value
504         eval_expr expr, register
505       else
506         eval_expr expr, @TEMPORARY
507         emit "sw #{@TEMPORARY}, #{ref}\n"
508       end
509     end
511     # Load a value into a register.
512     # Returns the name of the register.
513     # If the value was already in a register, the name of that
514     # register is returned.
515     # Else, the value is loaded into a register and the name of
516     # that register is returned. The register to use in that case
517     # may be specified using the optional second argument.
518     def load_value x, register = @TEMPORARY
519       if x == 0
520         return "$0"
521       elsif integer? x
522         if x >= -32768 && x <= 32767
523           emit "addiu #{register}, $0, #{x}\n"
524           return register
525         else
526           emit "lui #{register}, #{x >> 16}\n"
527           emit "ori #{register}, #{register}, #{x & 0xffff}\n"
528           return register
529         end
530       elsif symbol? x
531         binding = @environment[x]
532         if binding
533           case binding[0]
534           when :arg
535             emit "lw #{register}, #{arg_reference binding[1]}\n"
536             return register
537           when :local
538             n = binding[1]
539             if register_local? n
540               return local_register(n)
541             else
542               emit "lw #{register}, #{local_reference n}\n"
543               return register
544             end
545           else
546             raise "Don't know how to load #{x.inspect}"
547           end
548         else
549           # Assume global
550           emit "lui #{register}, %hi(#{x})\n"
551           emit "addiu #{register}, %lo(#{x})\n"
552           return register
553         end
554       else
555         raise "Don't know how to load #{x.inspect}"
556       end
557     end
559     # Load a value into a specific register
560     def load_value_into_register x, register
561       reg = load_value x, register
562       if reg != register
563         emit "move #{register}, #{reg}\n"
564       end
565     end
567     # Return the offset from $sp at which the nth (0-based) local variable is
568     # stored. For register locals this is the offset at which the saved
569     # value (from the calling function) is stored.
570     def local_offset n
571       @frame_size - @INITIAL_FRAME_SIZE - (n + 1) * @WORDSIZE
572     end
574     # Return an $sp-relative reference for the nth (0-based) local
575     def local_reference n
576       "#{local_offset n}($sp)"
577     end
579     # Return the register in which the nth local (0-based) is stored, or
580     # nil if not stored in a register
581     def local_register n
582       if register_local? n
583         "$#{@REGISTER_LOCAL_BASE + n}"
584       else
585         nil
586       end
587     end
589     # Compute the maximum number of locals that would fit in the current
590     # frame size.
591     def max_locals
592       (@frame_size - @INITIAL_FRAME_SIZE) / @WORDSIZE
593     end
595     # Calculate the number of stack arguments,
596     # given the total number of arguments.
597     def number_of_stack_arguments n
598       [0, n - @NREGISTER_ARGS].max
599     end
601     # Given an input file name, returns the canonical output file name
602     # for this code generator.
603     def output_file_name input_name
604       input_name.sub(/\.voo$/, '') + output_file_suffix
605     end    
607     # Returns the canonical filename suffix for files generated with
608     # this generator.
609     def output_file_suffix
610       '.s'
611     end
613     # Returns true if the nth (0-based) argument is stored in a register
614     def register_arg? n
615       n < @NREGISTER_ARGS
616     end
618     # Returns true if the nth (0-based) local is stored in a register
619     def register_local? n
620       n < @NREGISTER_LOCALS
621     end
623     # Return a from a function.
624     # 
625     # _words_ may contain an expression to be evaluated. The result
626     # of the evaluation is returned from the function.
627     def ret *words
628       emit "# return #{words.join ' '}\n"
629       # Compute return value and store it in @RETURN
630       eval_expr words, @RETURN
631       # Go to epilogue
632       goto @function_end_label
633     end
634     
635     # Set a variable to the result of evaluating an expression
636     def set symbol, *expr
637       emit "# set #{symbol} #{expr.join ' '}\n"
639       x = @environment[symbol]
640       if x == nil
641         raise "Cannot change value of constant #{symbol}"
642       end
644       if x[0] == :local
645         register = local_register x[1]
646       else
647         register = nil
648       end
650       if register
651         # Set new value
652         eval_expr expr, register
653       else
654         case x[0]
655         when :local
656           ref = local_reference x[1]
657         when :arg
658           ref = arg_reference x[1]
659         else
660           raise "??? #{sym} is neither a local nor an argument"
661         end
662         eval_expr expr, @TEMPORARY
663         emit "sw #{@TEMPORARY}, #{ref}\n"
664       end
665     end
667     # Set the byte at _base_ + _offset_ to _value_
668     def set_byte base, offset, value
669       emit "# set-byte #{base} #{offset} #{value}\n"
670       # If base is an integer, but offset isn't, swap them
671       if !integer?(offset) && integer?(base)
672         base, offset = [offset, base]
673       end
675       value_reg = @TEMPORARIES.pop
676       load_value_into_register value, value_reg
677       begin
678         if integer? offset
679           base_reg = load_value base
680           emit "sb #{value_reg}, #{offset}(#{base_reg})\n"
681         else
682           eval_binop [:add, base, offset], @TEMPORARY
683           emit "sb #{value_reg}, 0(#{@TEMPORARY})\n"
684         end
685       ensure
686         @TEMPORARIES.push value_reg
687       end
688     end
690     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
691     def set_word base, offset, value
692       emit "# set-word #{base} #{offset} #{value}\n"
694       value_reg = @TEMPORARIES.pop
695       load_value_into_register value, value_reg
696       begin
697         if integer? offset
698           base_reg = load_value base
699           emit "sw #{value_reg}, #{offset * @WORDSIZE}(#{base_reg})\n"
700         else
701           offset_reg = @TEMPORARIES.pop
702           begin
703             load_value_into_register offset, offset_reg
704             base_reg = load_value base
705             emit "sll #{offset_reg}, #{offset_reg}, 2\n"
706             emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
707             emit "sw #{value_reg}, 0(#{@TEMPORARY})\n"
708           ensure
709             @TEMPORARIES.push offset_reg
710           end
711         end
712       ensure
713         @TEMPORARIES.push value_reg
714       end
715     end
717     # Define a string with the given value
718     def string value
719       code = ''
720       value.each_byte do |b|
721         if b >= 32 && b < 128
722           code << b.chr
723         else
724           code << sprintf("\\%03o", b)
725         end
726       end
727       emit ".ascii \"#{code}\"\n"
728     end
730     # Test if a value is a symbol
731     def symbol? value
732       value.kind_of? Symbol
733     end
735     # Test if op is a symmetric binary operation (i.e. it will yield the
736     # same result if the order of its source operands is changed).
737     def symmetric_binop? op
738       [:add, :and, :mul, :or, :xor].member? op
739     end
741     # Call a function, re-using the current call frame if possible.
742     def tail_call func, *args
743       emit "# tail-call #{func} #{args.join ' '}\n"
745       # Compute number of stack arguments
746       nstackargs = number_of_stack_arguments args.length
747       # If we need more stack arguments than we have now,
748       # perform a normal call and return
749       if nstackargs > number_of_stack_arguments(@environment.args)
750         emit "# Not enough space for proper tail call; using regular call\n"
751         ret :call, func, *args
752       end
754       # TODO
756       # Back up any stack arguments we will need after we overwrite them
757       temporaries = @TEMPORARIES.dup
758       nlocals = @environment.locals
759       (@NREGISTER_ARGS...args.length).each do |i|
760         x = @environment[args[i]]
761         if x && x[0] == :arg && x[1] >= @NREGISTER_ARGS && x[1] < i
762           # args[i] is a stack arg, but has an index < i
763           # That means that, by the time we get to pass arg[i] to the called
764           # function, it will have been overwritten. So we make a backup.
765           if temporaries.empty?
766             # Oh dear, we're out of temporaries.
767             # Store the value in the current stack frame, extending it
768             # as necessary.
769             if nlocals >= max_locals
770               emit "addiu $sp, -8\n"
771               @frame_size = @frame_size + 8
772             end
773             reg = load_value args[i]
774             emit "sw #{reg}, #{local_reference nlocals}\n"
775             args[i] = [:local, nlocals]
776             nlocals = nlocals + 1
777           else
778             # Load the argument into a temporary
779             reg = temporaries.shift
780             load_value_into_register args[i], reg
781             # Update args[i] so we know how to get to it later
782             args[i] = [:reg, reg]
783           end
784         end
785       end
787       # Set stack arguments
788       (@NREGISTER_ARGS...args.length).each do |i|
789         arg = args[i]
790         reg = @TEMPORARY
792         # Load value
793         if arg.kind_of? Array
794           # Special cases, created above
795           case arg[0]
796           when :reg
797             reg = arg[1]
798           when :local
799             emit "lw #{reg}, #{local_reference arg[1]}\n"
800           end
801         else
802           load_value_into_register arg, reg
803         end
805         # Store value in designated place
806         emit "sw #{reg}, #{arg_reference i}\n"
807       end
809       # Set register arguments
810       [@NREGISTER_ARGS,args.length].min.times do |i|
811         reg = arg_register i
812         load_value_into_register args[i], reg
813       end
815       # Restore saved registers
816       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
817         emit "lw #{local_register n}, #{local_reference n}\n"
818       end
819       # Restore return address
820       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
822       # Adjust stack pointer
823       emit "addiu $sp, #{@frame_size}\n"
825       # Load function address
826       if global? func
827         if @imports.has_key? func
828           # Load address from global offset table
829           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
830         else
831           # Assume label defined in this module
832           emit "lui #{@FUNCTION}, %hi(#{func})\n"
833           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
834         end
835       else
836         # Load address
837         load_value_into_register func, "#{@FUNCTION}"
838       end
840       # Perform call
841       emit "jr #{@FUNCTION}\n"
842       # brach delay slot
843       emit "nop\n"
844     end
846     # Define a word with the given value
847     def word value
848       emit ".int #{value}\n"
849     end
851     # Write generated code to the given IO object.
852     def write io
853       io.puts ".set noat"
854       @sections.each do |section,code|
855         unless code.empty?
856           io.puts ".section #{section.to_s}"
857           io.puts code
858           io.puts
859         end
860       end
861     end
863   end
865   # Register class for big endian MIPS
866   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
867                                            :architecture => :mips,
868                                            :format => :gas
871   # Register class for little endian MIPS
872   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
873                                            :architecture => :mipsel,
874                                            :format => :gas