Update MIPS code generator to work with refactored environment
[voodoo-lang.git] / lib / voodoo / generators / mips_gas_generator.rb
blobebf9c34c31a349b8ff51a7437d76c2097a4f55c3
1 require 'voodoo/generators/common_code_generator'
3 module Voodoo
4   # = MIPS GNU Assembler Code Generator
5   #
6   # The MIPS code generator generates 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 activation 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       @features.merge! \
121         :'bits-per-word' => '32',
122         :'bytes-per-word' => '4'
123       case @architecture
124       when :mips
125         @features[:'byte-order'] = 'big-endian'
126       when :mipsel
127         @features[:'byte-order'] = 'little-endian'
128       else
129         raise ArgumentError.new("#{self.class} does not support " +
130                                 "architecture #{@architecture}")
131       end
132     end
134     def align alignment = nil
135       unless alignment
136         # Get default alignment
137         case @section
138         when :code
139           alignment = @CODE_ALIGNMENT
140         when :data
141           alignment = @DATA_ALIGNMENT
142         when :function
143           alignment = @FUNCTION_ALIGNMENT
144         else
145           # Use data alignment as default
146           alignment = @DATA_ALIGNMENT
147         end
148       end
149       emit ".align #{alignment}\n" unless alignment == 0
150     end
152     # Return the offset from the frame base at which the nth argument is
153     # stored.
154     def arg_offset n
155       n * @WORDSIZE
156     end
158     # Return an $sp-relative reference for the nth (0-based) argument
159     def arg_reference n
160       offset_reference(arg_offset(n))
161     end
163     # Return the register in which the nth (0-based) argument is stored, or
164     # nil if not stored in a register
165     def arg_register n
166       if register_arg? n
167         "$#{@REGISTER_ARG_BASE + n}"
168       else
169         nil
170       end
171     end
173     # Test if op is a binary operation
174     def assymetric_binop? op
175       [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op)
176     end
178     # Test if a value is an at-expression
179     def at_expr? value
180       value.respond_to?(:[]) && value[0] == :'@'
181     end
183     # Begins a new block.
184     def begin_block *code
185       emit "# begin block\n"
186       # If we are at top-level, create a frame
187       if @environment == @top_level
188         create_frame count_locals(code)
189       end
190       environment = Environment.new @environment
191       @environment = environment
192     end
194     # Emit function prologue and declare _formals_ as function arguments
195     def begin_function formals, nlocals
196       if @environment != @top_level
197         raise "Cannot begin function when already in a function"
198       end
200       environment = Environment.new @environment
201       @frame_size = 0
202       formals.each {|x| environment.add_arg x, arg_offset(environment.args)}
203       @environment = environment
204       @function_end_label = gensym
205       emit_function_prologue formals, nlocals
206     end
208     # Test if op is a binary operation
209     def binop? op
210       assymetric_binop?(op) || symmetric_binop?(op)
211     end
213     # Define a byte with the given value
214     def byte value
215       emit ".byte #{value}\n"
216     end
218     # Call a function.
219     def call func, *args
220       emit "# call #{func} #{args.join ' '}\n"
221       # Grow the stack frame, subject to 3 conditions:
222       # 1. There must be enough space to hold all arguments
223       # 2. $sp must remain a multiple of 8
224       # 3. We must provide space for at least 4 words
225       increment = ([args.length, 4].max * @WORDSIZE + 7) / 8 * 8
226       emit "addiu $sp, $sp, -#{increment}\n"
227       @frame_size = @frame_size + increment
229       # Put arguments in the right places
230       n = 0
231       while n < args.length
232         if n < @NREGISTER_ARGS
233           # Put arguments up to @NREGISTER_ARGS in registers
234           load_value_into_register args[n], arg_register(n)
235         else
236           # Put other arguments on the stack
237           load_value_into_register args[n], @TEMPORARY
238           emit "sw #{@TEMPORARY}, #{n * @WORDSIZE}($sp)\n"
239         end
240         n = n + 1
241       end
243       # Load function address
244       if global? func
245         if @imports.has_key? func
246           # Load address from global offset table
247           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
248         else
249           # Assume label defined in this module
250           emit "lui #{@FUNCTION}, %hi(#{func})\n"
251           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
252         end
253       else
254         # Load address
255         load_value_into_register func, "#{@FUNCTION}"
256       end
258       # Perform call
259       emit "jalr #{@FUNCTION}\n"
260       # brach delay slot
261       emit "nop\n"
263       # Restore original stack frame
264       emit "addiu $sp, $sp, #{increment}\n"
265       @frame_size = @frame_size - increment
267       # restore gp
268       emit "lw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
269     end
271     # Start a conditional using the specified branch instruction
272     # after the comparison.
273     def common_if comp, x, y = nil
274       emit "# #{comp} #{x} #{y}\n"
276       temporaries = @TEMPORARIES.dup
277       xreg = load_value x, temporaries[0]
278       temporaries.delete xreg
279       yreg = load_value y, temporaries[0]
280       temporaries.delete yreg
282       falselabel = @environment.gensym
283       @if_labels.push falselabel
285       case comp
286       when :ifeq
287         emit "bne #{xreg}, #{yreg}, #{falselabel}\n"
288       when :ifge
289         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
290         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
291       when :ifgt
292         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
293         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
294       when :ifle
295         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
296         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
297       when :iflt
298         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
299         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
300       when :ifne
301         emit "beq #{xreg}, #{yreg}, #{falselabel}\n"
302       else
303         raise "Unknown conditional: #{comp}"
304       end
305       emit "nop\n"
306     end
308     # Counts the number of local variables created in
309     # a sequence of statements.
310     def count_locals statements
311        count = 0
312        each_statement(statements) do |statement|
313          if statement[0] == :let
314            # let introduces a single local
315            count = count + 1
316          end
317        end
318        count
319     end
321     # Creates an activation frame which can store nlocals local variables
322     def create_frame nlocals
323       @frame_size = (@INITIAL_FRAME_SIZE + nlocals * @WORDSIZE + 7) / 8 * 8
324       emit "addiu $sp, $sp, -#{@frame_size}\n"
325     end
327     # Emit function prologue.
328     def emit_function_prologue formals = [], nlocals = 0
329       # Calculate new value for $gp
330       emit "lui #{@GOT}, %hi(_gp_disp)\n"
331       emit "addiu #{@GOT}, %lo(_gp_disp)\n"
332       emit "addu #{@GOT}, #{@GOT}, #{@FUNCTION}\n"
334       # Save parameters 0 .. 3 in the stack space that the caller
335       # should have allocated for them.
336       [@NREGISTER_ARGS, formals.length].min.times do |n|
337         ref = offset_reference(@environment[formals[n]])
338         emit "sw $#{n + @REGISTER_ARG_BASE}, #{ref}\n"
339       end
341       create_frame nlocals
343       # Save return address
344       emit "sw $31, #{@frame_size - @WORDSIZE}($sp)\n"
346       # Save gp
347       emit "sw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
348     end
350     # End a function body
351     def end_function
352       if @environment == @top_level
353         raise "Cannot end function when not in a function"
354       end
356       emit "# function epilogue\n"
358       label @function_end_label
359       # Restore saved locals
360       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
361         emit "lw #{local_register n}, #{local_reference n}\n"
362       end
363       # Load return address
364       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
365       # Restore stack pointer
366       emit "addiu $sp, $sp, #{@frame_size}\n"
367       # Return
368       emit "jr $31\n"
369       emit "nop\n"
371       emit "# end function\n\n"
373       @function_end_label = nil
374       @environment = @top_level
375     end
377     # Ends the current block.
378     def end_block
379       emit "# end block\n"
381       # If we are returning to top level, restore stack pointer
382       if @environment.parent == @top_level
383         emit "addiu $sp, $sp, #{@frame_size}\n"
384       end
386       # Restore old value of @environment
387       @environment = @environment.parent
388     end
390     # End a conditional.
391     def end_if
392       label = @if_labels.pop
393       emit "#{label}:\n"
394     end
396     # Evaluate the binary operation expr and store the result in register
397     def eval_binop expr, register
398       temporaries = @TEMPORARIES.dup
399       x = load_value expr[1], temporaries[0]
400       temporaries.delete x
401       y = load_value expr[2], temporaries[0]
402       temporaries.delete y
404       case expr[0]
405       when :asr
406         emit "srav #{register}, #{x}, #{y}\n"
407       when :bsr
408         emit "srlv #{register}, #{x}, #{y}\n"
409       when :div
410         emit "div $0, #{x}, #{y}\n"
411         emit "mflo #{register}\n"
412       when :mod
413         emit "div $0, #{x}, #{y}\n"
414         emit "mfhi #{register}\n"
415       when :mul
416         emit "mult #{x}, #{y}\n"
417         emit "mflo #{register}\n"
418       when :rol
419         emit "subu #{@TEMPORARY}, $0, #{y}\n"
420         emit "srlv #{@TEMPORARY}, #{x}, #{@TEMPORARY}\n"
421         emit "sllv #{register}, #{x}, #{y}\n"
422         emit "or #{register}, #{register}, #{@TEMPORARY}\n"
423       when :ror
424         emit "subu #{@TEMPORARY}, $0, #{y}\n"
425         emit "sllv #{@TEMPORARY}, #{x}, #{@TEMPORARY}\n"
426         emit "srlv #{register}, #{x}, #{y}\n"
427         emit "or #{register}, #{register}, #{@TEMPORARY}\n"
428       when :shl
429         emit "sllv #{register}, #{x}, #{y}\n"
430       when :shr
431         emit "srlv #{register}, #{x}, #{y}\n"
432       else
433         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
434       end
435     end
437     # Evaluate the expression expr and store the result in register
438     def eval_expr expr, register
439       if expr.length == 1
440         # Load value
441         load_value_into_register expr[0], register
442       else
443         # Evaluate expression
444         op = expr[0]
445         case op
446         when :call
447           call *expr[1..-1]
448           emit "move #{register}, #{@RETURN}\n" if register != @RETURN
449         when :'get-byte'
450           get_byte expr[1], expr[2], register
451         when :'get-word'
452           get_word expr[1], expr[2], register
453         when :not
454             eval_binop [:nor, 0, expr[1]], register
455         else
456           if binop? op
457             eval_binop expr, register
458           else
459             raise "Not a magic word: #{op}"
460           end
461         end
462       end
463     end
465     # Export symbols from the current section
466     def export *symbols
467       symbols.each { |sym| emit ".globl #{sym}\n" }
468     end
470     # Add a function to the current section
471     def function formals, *code
472       nlocals = count_locals code
473       begin_function formals, nlocals
474       code.each { |action| add section, action }
475       end_function
476     end
478     # Load byte from _base_ + _offset_ into _register_
479     def get_byte base, offset, register
480       # If base is an integer, but offset isn't, swap them
481       if !integer?(offset) && integer?(base)
482         base, offset = [offset, base]
483       end
485       if integer? offset
486         base_reg = load_value base
487         emit "lb #{register}, #{offset}(#{base_reg})\n"
488       else
489         eval_binop [:add, base, offset], @TEMPORARY
490         emit "lb #{register}, 0(#{@TEMPORARY})\n"
491       end
492     end
494     # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
495     def get_word base, offset, register
496       if integer? offset
497         base_reg = load_value base
498         emit "lw #{register}, #{offset * @WORDSIZE}(#{base_reg})\n"
499       else
500         offset_reg = @TEMPORARIES.pop
501         begin
502           load_value_into_register offset, offset_reg
503           base_reg = load_value base
504           emit "sll #{offset_reg}, #{offset_reg}, 2\n" # multiply by @WORDSIZE
505           emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
506           emit "lw #{register}, 0(#{@TEMPORARY})\n"
507         ensure
508           @TEMPORARIES.push offset_reg
509         end
510       end
511     end
513     # Test if a symbol refers to a global
514     def global? symbol
515       symbol?(symbol) && @environment[symbol] == nil
516     end
518     # Jump to a label.
519     def goto label
520       emit "j #{label}\n"
521       emit "nop\n"
522     end
524     # Start the false path of a conditional.
525     def ifelse
526       emit "# else\n"
527       newlabel = @environment.gensym
528       emit "j #{newlabel}\n"
529       emit "nop\n"
530       label = @if_labels.pop
531       emit "#{label}:\n"
532       @if_labels.push newlabel
533     end
535     # Test if x is equal to y
536     def ifeq x, y
537       common_if :ifeq, x, y
538     end
540     # Test if x is greater than or equal to y
541     def ifge x, y
542       common_if :ifge, x, y
543     end
545     # Test if x is strictly greater than y
546     def ifgt x, y
547       common_if :ifgt, x, y
548     end
550     # Test if x is less than or equal to y
551     def ifle x, y
552       common_if :ifle, x, y
553     end
555     # Test if x is strictly less than y
556     def iflt x, y
557       common_if :iflt, x, y
558     end
560     # Test if x different from y
561     def ifne x, y
562       common_if :ifne, x, y
563     end
565     # Import labels into the current section
566     def import *symbols
567       # Record imported labels in @imports
568       symbols.each { |sym| @imports[sym] = sym }
569     end
571     # Test if a value is an integer
572     def integer? value
573       value.kind_of? Integer
574     end
576     # Emit a label
577     def label name
578       emit "#{name}:\n"
579     end
581     # Introduces a new local variable.
582     def let symbol, *expr
583       emit "# let #{symbol} #{expr.join ' '}\n"
584       n = @environment.locals
585       register = local_register n
586       ref = local_reference n
587       if register
588         # We will use a register to store the value
589         @environment.add_local symbol, register
590         # Save current value of register
591         emit "sw #{register}, #{ref}\n"
592         # Set new value
593         eval_expr expr, register
594       else
595         # We will use the stack to store the value
596         @environment.add_local symbol, local_offset(n)
597         eval_expr expr, @TEMPORARY
598         emit "sw #{@TEMPORARY}, #{ref}\n"
599       end
600     end
602     # Loads the value at the given address.
603     def load_at address, register = @TEMPORARY
604       load_value_into_register address, register
605       emit "lw #{register}, 0(#{register})\n"
606       register
607     end
609     # Loads a value into a register.
610     # Returns the name of the register.
611     # If the value was already in a register, the name of that
612     # register is returned.
613     # Else, the value is loaded into a register and the name of
614     # that register is returned. The register to use in that case
615     # may be specified using the optional second argument.
616     def load_value x, register = @TEMPORARY
617       if x == 0
618         return "$0"
619       elsif integer? x
620         if x >= -32768 && x <= 32767
621           emit "addiu #{register}, $0, #{x}\n"
622           return register
623         else
624           emit "lui #{register}, #{x >> 16}\n"
625           emit "ori #{register}, #{register}, #{x & 0xffff}\n"
626           return register
627         end
628       elsif symbol? x
629         binding = @environment[x]
630         if binding.kind_of? String
631           # Value is already in a register. Return register name.
632           return binding
633         elsif binding.kind_of? Integer
634           # Load value from memory.
635           emit "lw #{register}, #{offset_reference binding}\n"
636           return register
637         else
638           # Assume global
639           emit "lui #{register}, %hi(#{x})\n"
640           emit "addiu #{register}, %lo(#{x})\n"
641           return register
642         end
643       elsif at_expr? x
644         load_at x[1], register
645       else
646         raise "Don't know how to load #{x.inspect}"
647       end
648     end
650     # Load a value into a specific register
651     def load_value_into_register x, register
652       reg = load_value x, register
653       if reg != register
654         emit "move #{register}, #{reg}\n"
655       end
656     end
658     # Return the offset from the frame base at which the nth local is stored.
659     # For register locals this is the offset at which the saved
660     # value (from the calling function) is stored.
661     def local_offset n
662       -(n + 3) * @WORDSIZE
663     end
665     # Return an $sp-relative reference for the nth (0-based) local
666     def local_reference n
667       offset_reference(local_offset(n))
668     end
670     # Return the register in which the nth local (0-based) is stored, or
671     # nil if not stored in a register
672     def local_register n
673       if register_local? n
674         "$#{@REGISTER_LOCAL_BASE + n}"
675       else
676         nil
677       end
678     end
680     # Compute the maximum number of locals that would fit in the current
681     # frame size.
682     def max_locals
683       (@frame_size - @INITIAL_FRAME_SIZE) / @WORDSIZE
684     end
686     # Calculate the number of stack arguments,
687     # given the total number of arguments.
688     def number_of_stack_arguments n
689       [0, n - @NREGISTER_ARGS].max
690     end
692     # Given an offset relative to the base of the frame, returns
693     # an reference to that memory location.
694     def offset_reference offset
695       "#{offset + @frame_size}($sp)"
696     end
698     # Returns true if the nth (0-based) argument is stored in a register
699     def register_arg? n
700       n < @NREGISTER_ARGS
701     end
703     # Returns true if the nth (0-based) local is stored in a register
704     def register_local? n
705       n < @NREGISTER_LOCALS
706     end
708     # Return a from a function.
709     # 
710     # _words_ may contain an expression to be evaluated. The result
711     # of the evaluation is returned from the function.
712     def ret *words
713       emit "# return #{words.join ' '}\n"
714       # Compute return value and store it in @RETURN
715       eval_expr(words, @RETURN) unless words.empty?
716       # Go to epilogue
717       goto @function_end_label
718     end
719     
720     # Set a variable to the result of evaluating an expression
721     def set symbol, *expr
722       if at_expr? symbol
723         eval_expr expr, @RETURN
724         load_value_into_register symbol.to_s[1..-1].to_sym, @TEMPORARY
725         emit "sw #{@RETURN}, 0(#{@TEMPORARY})\n"
726       else
727         x = @environment[symbol]
728         if x == nil
729           raise "Cannot change value of constant #{symbol}"
730         elsif x.kind_of? String
731           # Register
732           eval_expr expr, x
733         else
734           # Should be an integer.
735           eval_expr expr, @TEMPORARY
736           emit "sw #{@TEMPORARY}, #{offset_reference x}\n"
737         end
738       end
739     end
741     # Set the byte at _base_ + _offset_ to _value_
742     def set_byte base, offset, value
743       emit "# set-byte #{base} #{offset} #{value}\n"
744       # If base is an integer, but offset isn't, swap them
745       if !integer?(offset) && integer?(base)
746         base, offset = [offset, base]
747       end
749       value_reg = @TEMPORARIES.pop
750       load_value_into_register value, value_reg
751       begin
752         if integer? offset
753           base_reg = load_value base
754           emit "sb #{value_reg}, #{offset}(#{base_reg})\n"
755         else
756           eval_binop [:add, base, offset], @TEMPORARY
757           emit "sb #{value_reg}, 0(#{@TEMPORARY})\n"
758         end
759       ensure
760         @TEMPORARIES.push value_reg
761       end
762     end
764     # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
765     def set_word base, offset, value
766       emit "# set-word #{base} #{offset} #{value}\n"
768       value_reg = @TEMPORARIES.pop
769       load_value_into_register value, value_reg
770       begin
771         if integer? offset
772           base_reg = load_value base
773           emit "sw #{value_reg}, #{offset * @WORDSIZE}(#{base_reg})\n"
774         else
775           offset_reg = @TEMPORARIES.pop
776           begin
777             load_value_into_register offset, offset_reg
778             base_reg = load_value base
779             emit "sll #{offset_reg}, #{offset_reg}, 2\n"
780             emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
781             emit "sw #{value_reg}, 0(#{@TEMPORARY})\n"
782           ensure
783             @TEMPORARIES.push offset_reg
784           end
785         end
786       ensure
787         @TEMPORARIES.push value_reg
788       end
789     end
791     # Define a string with the given value
792     def string value
793       code = ''
794       value.each_byte do |b|
795         if b == 92
796           code << "\\\\"
797         elsif b >= 32 && b < 127 && b != 34
798           code << b.chr
799         else
800           code << sprintf("\\%03o", b)
801         end
802       end
803       emit ".ascii \"#{code}\"\n"
804     end
806     # Test if a value is a symbol
807     def symbol? value
808       value.kind_of? Symbol
809     end
811     # Test if op is a symmetric binary operation (i.e. it will yield the
812     # same result if the order of its source operands is changed).
813     def symmetric_binop? op
814       [:add, :and, :mul, :or, :xor].member? op
815     end
817     # Call a function, re-using the current call frame if possible.
818     def tail_call func, *args
819       emit "# tail-call #{func} #{args.join ' '}\n"
821       # Compute number of stack arguments
822       nstackargs = number_of_stack_arguments args.length
823       # If we need more stack arguments than we have now,
824       # perform a normal call and return
825       if nstackargs > number_of_stack_arguments(@environment.args)
826         emit "# Not enough space for proper tail call; using regular call\n"
827         ret :call, func, *args
828       end
830       # Back up any stack arguments we will need after we overwrite them
831       temporaries = @TEMPORARIES.dup
832       nlocals = @environment.locals
833       (@NREGISTER_ARGS...args.length).each do |i|
834         x = @environment[args[i]]
835         if x && x[0] == :arg && x[1] >= @NREGISTER_ARGS && x[1] < i
836           # args[i] is a stack arg, but has an index < i
837           # That means that, by the time we get to pass arg[i] to the called
838           # function, it will have been overwritten. So we make a backup.
839           if temporaries.empty?
840             # Oh dear, we're out of temporaries.
841             # Store the value in the current stack frame, extending it
842             # as necessary.
843             if nlocals >= max_locals
844               emit "addiu $sp, -8\n"
845               @frame_size = @frame_size + 8
846             end
847             reg = load_value args[i]
848             emit "sw #{reg}, #{local_reference nlocals}\n"
849             args[i] = [:local, nlocals]
850             nlocals = nlocals + 1
851           else
852             # Load the argument into a temporary
853             reg = temporaries.shift
854             load_value_into_register args[i], reg
855             # Update args[i] so we know how to get to it later
856             args[i] = [:reg, reg]
857           end
858         end
859       end
861       # Set stack arguments
862       (@NREGISTER_ARGS...args.length).each do |i|
863         arg = args[i]
864         reg = @TEMPORARY
866         # Load value
867         if arg.kind_of? Array
868           # Special cases, created above
869           case arg[0]
870           when :reg
871             reg = arg[1]
872           when :local
873             emit "lw #{reg}, #{local_reference arg[1]}\n"
874           end
875         else
876           load_value_into_register arg, reg
877         end
879         # Store value in designated place
880         emit "sw #{reg}, #{arg_reference i}\n"
881       end
883       # Set register arguments
884       [@NREGISTER_ARGS,args.length].min.times do |i|
885         reg = arg_register i
886         load_value_into_register args[i], reg
887       end
889       # Restore saved registers
890       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
891         emit "lw #{local_register n}, #{local_reference n}\n"
892       end
893       # Restore return address
894       emit "lw $31, #{@frame_size - @WORDSIZE}($sp)\n"
896       # Adjust stack pointer
897       emit "addiu $sp, #{@frame_size}\n"
899       # Load function address
900       if global? func
901         if @imports.has_key? func
902           # Load address from global offset table
903           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
904         else
905           # Assume label defined in this module
906           emit "lui #{@FUNCTION}, %hi(#{func})\n"
907           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
908         end
909       else
910         # Load address
911         load_value_into_register func, "#{@FUNCTION}"
912       end
914       # Perform call
915       emit "jr #{@FUNCTION}\n"
916       # brach delay slot
917       emit "nop\n"
918     end
920     # Define a word with the given value
921     def word value
922       emit ".int #{value}\n"
923     end
925     # Write generated code to the given IO object.
926     def write io
927       io.puts ".set noat"
928       @sections.each do |section,code|
929         unless code.empty?
930           io.puts ".section #{section.to_s}"
931           io.puts code
932           io.puts
933         end
934       end
935     end
937   end
939   # Register class for big endian MIPS
940   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
941                                            :architecture => :mips,
942                                            :format => :gas
945   # Register class for little endian MIPS
946   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
947                                            :architecture => :mipsel,
948                                            :format => :gas