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