reject programs that use symbols that have not been defined or imported
[voodoo-lang.git] / lib / voodoo / generators / mips_gas_generator.rb
blobefd57781c8842c1c04e67b823e22498d5a544dbc
1 require 'voodoo/generators/common_code_generator'
2 require 'set'
4 module Voodoo
5   # = MIPS GNU Assembler Code Generator
6   #
7   # The MIPS code generator generates assembly code for use with
8   # the GNU assembler.
9   #
10   # == Calling Convention
11   #
12   # The first four arguments are passed in the registers $4 through $7.
13   # Any additional arguments are passed on the stack, starting at
14   # $sp + 16. Words $sp through $sp + 12 will be available for the called
15   # function to use. $sp will always be a multiple of 8.
16   #
17   # The return address for the called function is passed in $31.
18   #
19   # When performing a position-independent call, the address of the called
20   # function is passed in $25.
21   #
22   # The called function will store its return value in $2.
23   #
24   # The called function is required to preserve the values of registers
25   # $16 through $23 and register $30.
26   #
27   # This calling convention is compatible with the System V ELF ABI.
28   #
29   # == Call Frames
30   #
31   # Call frames have the following layout:
32   #
33   # When a function is called, it receives a stack frame that looks like
34   # the following:
35   #
36   #   :
37   #   old frame
38   #   argn
39   #   :
40   #   arg4
41   #   empty3
42   #   empty2
43   #   empty1
44   #   empty0    <-- $sp points here
45   #
46   # The function prologue of functions generated by this code generator
47   # creates activation frames that look as follows:
48   #
49   # :
50   # old frame
51   # argn
52   # :
53   # arg4
54   # arg3
55   # arg2
56   # arg1
57   # arg0       <-- $fp points here
58   # return address
59   # pointer to Global Offset Table
60   # saved $fp
61   # local0
62   # :
63   # local7
64   # local8
65   # :
66   # localn
67   # padding    <-- $sp points here
68   #
69   # In words:
70   #
71   # The four empty slots provided by the caller are used to store
72   # arguments 0 through 3 (originally passed in $4 through $7),
73   # if necessary.
74   #
75   # The stack frame created below the four slots provided by the caller
76   # contains the following data, in order:
77   #
78   # - Saved return address (originally passed in $31), if necessary.
79   #
80   # - Saved pointer to global offset table (computed from $25), if necessary.
81   #
82   # - Saved value of $fp, if necessary.
83   #
84   # - Saved values of caller's locals 0 through 7
85   #   (originally in $16 through $23), if necessary.
86   #
87   # - Values of our locals > 8, if necessary.
88   #
89   # - Padding to align $sp on a multiple of 8, if necessary.
90   #
91   #
92   # In accordance with the System V ELF ABI for MIPS, the pointer to
93   # the global offset table is calculated as follows:
94   #
95   # $gp = _gp_disp + $25
96   #
97   # where $gp is the register to store the pointer, $25 is the register
98   # holding the address of the called function, and _gp_disp is the
99   # offset between the beginning of the function and the global offset table.
100   #
101   # Callee-Save Registers
102   #
103   # Registers $16 through $23 and $28 through $30 are callee-save.
104   #
105   # All other registers are caller-save.
106   #
107   class MIPSGasGenerator < CommonCodeGenerator
108     def initialize params
109       @WORDSIZE_BITS = 2
110       @WORDSIZE = 1 << @WORDSIZE_BITS
111       @CODE_ALIGNMENT = 0
112       @DATA_ALIGNMENT = @WORDSIZE
113       @STACK_ALIGNMENT_BITS = 3
114       @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
115       @FP_OFFSET = -3 * @WORDSIZE
116       @FUNCTION_ALIGNMENT = @WORDSIZE
117       @GP_OFFSET = -2 * @WORDSIZE
118       @INITIAL_FRAME_SIZE = 4 * @WORDSIZE
119       @REGISTER_ARG_BASE = 4
120       @NREGISTER_ARGS = 4
121       @LOCAL_REGISTERS = [:'$16', :'$17', :'$18', :'$19',
122                           :'$20', :'$21', :'$22', :'$23']
123       @LOCAL_REGISTERS_SET = Set.new @LOCAL_REGISTERS
124       @REGISTER_LOCAL_BASE = 16
125       @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
126       @RA_OFFSET = -@WORDSIZE
127       @RETURN = :'$2'
128       @TEMPORARY = :'$1'
129       @FUNCTION = :'$25'
130       @GOT = :'$28'
131       @SAVE_FRAME_REGISTERS = [:'$16', :'$17', :'$18', :'$19', :'$20',
132                                :'$21', :'$22', :'$23', :'$28', :'$29',
133                                :'$30']
134       @SAVED_FRAME_LAYOUT = {}
135       @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
136       @TEMPORARIES = [:'$8', :'$9', :'$10', :'$11',
137                       :'$12', :'$13', :'$14', :'$15']
138       @function_end_label = nil
139       @imports = {}
140       @if_labels = []
141       super params
142       @output_file_suffix = '.s'
143       @saved_registers = []
144       @features.merge! \
145         :'bits-per-word' => '32',
146         :'bytes-per-word' => '4'
147       case @architecture
148       when :mips
149         @features[:'byte-order'] = 'big-endian'
150       when :mipsel
151         @features[:'byte-order'] = 'little-endian'
152       else
153         raise ArgumentError.new("#{self.class} does not support " +
154                                 "architecture #{@architecture}")
155       end
156     end
158     # Adds immediate to source and stores the result in target.
159     def addiu target, source, immediate, temporary = @TEMPORARY
160       if immediate >= -32768 && immediate < 32767
161         emit "addiu #{target}, #{source}, #{immediate}\n"
162       elsif source == "$0"
163         emit "lui #{target}, #{(immediate >> 16) & 0xffff}\n"
164         emit "ori #{target}, #{target}, #{immediate & 0xffff}\n"
165       else
166         addiu temporary, "$0", immediate
167         emit "addu #{target}, #{source}, #{temporary}\n"
168       end
169     end
171     # Return the offset from the frame base at which the nth argument is
172     # stored.
173     def arg_offset n
174       n * @WORDSIZE
175     end
177     # Returns an $fp-relative reference for the nth (0-based) argument.
178     def arg_reference n
179       offset_reference(arg_offset(n))
180     end
182     # Returns the register in which the nth (0-based) argument is stored, or
183     # nil if not stored in a register.
184     def arg_register n
185       if register_arg? n
186         "$#{@REGISTER_ARG_BASE + n}"
187       else
188         nil
189       end
190     end
192     def auto_bytes n, register
193       if n.kind_of? Integer
194         # Maintain stack alignment
195         n = (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
196         grow_stack n
197       else
198         temporary = @TEMPORARIES.pop
199         begin
200           load_value_into_register n, register
201           emit "addi #{register}, #{@STACK_ALIGNMENT - 1}\n"
202           emit "li #{temporary}, -#{@STACK_ALIGNMENT}\n"
203           emit "and #{register}, #{register}, #{temporary}\n"
204           emit "sub $sp, #{register}\n"
205         ensure
206           @TEMPORARIES.push temporary
207         end
208       end
209       emit "move #{register}, $sp\n" unless register == "$sp"
210     end
212     def auto_words n, register
213       if n.kind_of? Integer
214         auto_bytes n * @WORDSIZE, register
215       else
216         load_value_into_register n, register
217         if @STACK_ALIGNMENT_BITS > @WORDSIZE_BITS
218           bits = @STACK_ALIGNMENT_BITS - @WORDSIZE_BITS
219           emit "addi #{register}, #{(1 << bits) - 1}\n"
220           emit "srl #{register}, #{register}, #{bits}\n"
221           emit "sll #{register}, #{register}, #{@STACK_ALIGNMENT_BITS}\n"
222         else
223           emit "sll #{register}, #{register}, #{@WORDSIZE_BITS}\n"
224         end
225         emit "sub $sp, $sp, #{register}\n"
226         emit "move #{register}, $sp\n" unless register == "$sp"
227       end
228     end
230     # Begins a new block.
231     def begin_block *code
232       # If we are at top-level, create a frame
233       if @environment == @top_level
234         create_frame count_locals(code)
235       end
236       environment = Environment.new @environment
237       @environment = environment
238     end
240     # Emits function prologue and declare _formals_ as function arguments.
241     def begin_function formals, nlocals
242       if @environment != @top_level
243         raise "Cannot begin function when already in a function"
244       end
246       environment = Environment.new @environment
247       @frame_size = 0
248       formals.each {|x| environment.add_arg x, arg_offset(environment.args)}
249       @environment = environment
250       @function_end_label = gensym
251       emit_function_prologue formals, nlocals
252     end
254     # Defines a byte with the given value.
255     def byte value
256       emit ".byte #{value}\n"
257     end
259     # Calls a function.
260     def call func, *args
261       # Grow the stack frame, subject to 3 conditions:
262       # 1. There must be enough space to hold all arguments
263       # 2. $sp must remain a multiple of 8
264       # 3. We must provide space for at least 4 words
265       increment = ([args.length, 4].max * @WORDSIZE + 7) / 8 * 8
266       grow_stack increment
268       # Put arguments in the right places
269       n = 0
270       while n < args.length
271         if n < @NREGISTER_ARGS
272           # Put arguments up to @NREGISTER_ARGS in registers
273           load_value_into_register args[n], arg_register(n)
274         else
275           # Put other arguments on the stack
276           load_value_into_register args[n], @TEMPORARY
277           emit "sw #{@TEMPORARY}, #{n * @WORDSIZE}($sp)\n"
278         end
279         n = n + 1
280       end
282       # Load function address
283       if global? func
284         @symbol_tracker.use func
285         if @imports.has_key? func
286           # Load address from global offset table
287           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
288         else
289           # Assume label defined in this module
290           emit "lui #{@FUNCTION}, %hi(#{func})\n"
291           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
292         end
293       else
294         # Load address
295         load_value_into_register func, "#{@FUNCTION}"
296       end
298       # Perform call
299       emit "jalr #{@FUNCTION}\n"
300       # brach delay slot
301       emit "nop\n"
303       # Restore original stack frame
304       grow_stack -increment
306       # restore gp
307       emit "lw #{@GOT}, #{@GP_OFFSET}($fp)\n"
308     end
310     # Emits a comment.
311     def comment text
312       emit "# #{text}\n"
313     end
315     # Starts a conditional using the specified branch instruction
316     # after the comparison.
317     def common_if comp, x, y = nil
318       temporaries = @TEMPORARIES.dup
319       xreg = load_value x, temporaries[0]
320       temporaries.delete xreg
321       yreg = load_value y, temporaries[0]
322       temporaries.delete yreg
324       falselabel = @environment.gensym
325       @if_labels.push falselabel
327       case comp
328       when :ifeq
329         emit "bne #{xreg}, #{yreg}, #{falselabel}\n"
330       when :ifge
331         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
332         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
333       when :ifgt
334         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
335         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
336       when :ifle
337         emit "slt #{@TEMPORARY}, #{yreg}, #{xreg}\n"
338         emit "bne #{@TEMPORARY}, $0, #{falselabel}\n"
339       when :iflt
340         emit "slt #{@TEMPORARY}, #{xreg}, #{yreg}\n"
341         emit "beq #{@TEMPORARY}, $0, #{falselabel}\n"
342       when :ifne
343         emit "beq #{xreg}, #{yreg}, #{falselabel}\n"
344       else
345         raise "Unknown conditional: #{comp}"
346       end
347       emit "nop\n"
348     end
350     # Creates an activation frame which can store nlocals local variables.
351     def create_frame nlocals
352       @frame_size = @INITIAL_FRAME_SIZE
353       if nlocals > 0
354         @frame_size = @frame_size + (nlocals * @WORDSIZE + 7) / 8 * 8
355       end
356       grow_stack @frame_size
357       @saved_registers = []
358     end
360     def emit_align alignment
361       emit ".align #{alignment}\n"
362     end
364     # Exports symbols from the current section.
365     def emit_export *symbols
366       symbols.each { |sym| emit ".globl #{sym}\n" }
367     end
369     # Emits function prologue.
370     def emit_function_prologue formals = [], nlocals = 0
371       # Calculate new value for $gp
372       emit "lui #{@GOT}, %hi(_gp_disp)\n"
373       emit "addiu #{@GOT}, %lo(_gp_disp)\n"
374       emit "addu #{@GOT}, #{@GOT}, #{@FUNCTION}\n"
376       create_frame nlocals
378       # Save return address
379       emit "sw $31, #{@frame_size - @WORDSIZE}($sp)\n"
381       # Save gp
382       emit "sw #{@GOT}, #{@frame_size - 2 * @WORDSIZE}($sp)\n"
384       # Save fp
385       emit "sw $fp, #{@frame_size - 3 * @WORDSIZE}($sp)\n"
387       # Point fp at where sp was before we created the frame
388       addiu "$fp", "$sp", @frame_size
390       # Save parameters 0 .. 3 in the stack space that the caller
391       # should have allocated for them.
392       [@NREGISTER_ARGS, formals.length].min.times do |n|
393         ref = offset_reference(@environment[formals[n]])
394         emit "sw $#{n + @REGISTER_ARG_BASE}, #{ref}\n"
395       end
396     end
398     # Imports labels into the current section.
399     def emit_import *symbols
400       # Record imported labels in @imports
401       symbols.each { |sym| @imports[sym] = sym }
402     end
404     # Emits a label type annotation.
405     def emit_label_type name, type
406       type_map = {
407         :code => "@function",
408         :data => "@object",
409       }
410       emit ".type #{name}, #{type_map[type]}\n"
411     end
413     # Emits a label size annotation.
414     def emit_label_size name
415       emit ".size #{name}, .-#{name}\n"
416     end
418     # Loads a word into a register.
419     def emit_load_word register, base, offset
420       emit "lw #{register}, #{offset * @WORDSIZE}(#{base})\n"
421     end
423     # Stores the value of a register in memory.
424     def emit_store_word register, base, offset
425       emit "sw #{register}, #{offset * @WORDSIZE}(#{base})\n"
426     end
428     # Ends a function body.
429     def end_function
430       if @environment == @top_level
431         raise "Cannot end function when not in a function"
432       end
434       label @function_end_label
435       # Restore saved locals
436       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
437         emit "lw #{local_register n}, #{local_reference n}\n"
438       end
439       @saved_registers = []
440       # Load return address
441       emit "lw $31, #{@RA_OFFSET}($fp)\n"
442       # Restore stack pointer
443       emit "move $sp, $fp\n"
444       # Restore frame pointer
445       emit "lw $fp, #{@FP_OFFSET}($fp)\n"
446       # Return
447       emit "jr $31\n"
448       emit "nop\n"
450       @function_end_label = nil
451       @environment = @top_level
452     end
454     # Ends the current block.
455     def end_block
456       # If we are returning to top level, restore stack pointer
457       if @environment.parent == @top_level
458         grow_stack -@frame_size
459         @saved_registers = []
460       end
462       # Restore old value of @environment
463       @environment = @environment.parent
464     end
466     # Ends a conditional.
467     def end_if
468       label = @if_labels.pop
469       emit "#{label}:\n"
470     end
472     # Evaluates the binary operation expr and store the result in register.
473     def eval_binop expr, register
474       temporaries = @TEMPORARIES.dup
475       x = load_value expr[1], temporaries[0]
476       temporaries.delete x
477       y = load_value expr[2], temporaries[0]
478       temporaries.delete y
480       case expr[0]
481       when :asr
482         emit "srav #{register}, #{x}, #{y}\n"
483       when :bsr
484         emit "srlv #{register}, #{x}, #{y}\n"
485       when :div
486         emit "div $0, #{x}, #{y}\n"
487         emit "mflo #{register}\n"
488       when :mod
489         emit "div $0, #{x}, #{y}\n"
490         emit "mfhi #{register}\n"
491       when :mul
492         emit "mult #{x}, #{y}\n"
493         emit "mflo #{register}\n"
494       when :rol
495         emit "subu #{@TEMPORARY}, $0, #{y}\n"
496         emit "srlv #{@TEMPORARY}, #{x}, #{@TEMPORARY}\n"
497         emit "sllv #{register}, #{x}, #{y}\n"
498         emit "or #{register}, #{register}, #{@TEMPORARY}\n"
499       when :ror
500         emit "subu #{@TEMPORARY}, $0, #{y}\n"
501         emit "sllv #{@TEMPORARY}, #{x}, #{@TEMPORARY}\n"
502         emit "srlv #{register}, #{x}, #{y}\n"
503         emit "or #{register}, #{register}, #{@TEMPORARY}\n"
504       when :shl
505         emit "sllv #{register}, #{x}, #{y}\n"
506       when :shr
507         emit "srlv #{register}, #{x}, #{y}\n"
508       else
509         emit "#{expr[0]} #{register}, #{x}, #{y}\n"
510       end
511     end
513     # Evaluates the expression expr and store the result in register.
514     def eval_expr expr, register
515       if expr.length == 1
516         # Load value
517         load_value_into_register expr[0], register
518       else
519         # Evaluate expression
520         op = expr[0]
521         case op
522         when :'auto-bytes'
523           auto_bytes expr[1], register
524         when :'auto-words'
525           auto_words expr[1], register
526         when :call
527           call *expr[1..-1]
528           emit "move #{register}, #{@RETURN}\n" if register != @RETURN
529         when :'get-byte'
530           get_byte expr[1], expr[2], register
531         when :'get-word'
532           get_word expr[1], expr[2], register
533         when :not
534             eval_binop [:nor, 0, expr[1]], register
535         else
536           if binop? op
537             eval_binop expr, register
538           else
539             raise "Not a magic word: #{op}"
540           end
541         end
542       end
543     end
545     # Loads byte from _base_ + _offset_ into _register_.
546     def get_byte base, offset, register
547       # If base is an integer, but offset isn't, swap them
548       if !integer?(offset) && integer?(base)
549         base, offset = [offset, base]
550       end
552       if integer? offset
553         base_reg = load_value base
554         emit "lb #{register}, #{offset}(#{base_reg})\n"
555       else
556         eval_binop [:add, base, offset], @TEMPORARY
557         emit "lb #{register}, 0(#{@TEMPORARY})\n"
558       end
559     end
561     # Loads word from _base_ + _offset_ * _@WORDSIZE_ into _register_.
562     def get_word base, offset, register
563       if integer? offset
564         base_reg = load_value base
565         emit "lw #{register}, #{offset * @WORDSIZE}(#{base_reg})\n"
566       else
567         offset_reg = @TEMPORARIES.pop
568         begin
569           load_value_into_register offset, offset_reg
570           base_reg = load_value base
571           emit "sll #{offset_reg}, #{offset_reg}, 2\n" # multiply by @WORDSIZE
572           emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
573           emit "lw #{register}, 0(#{@TEMPORARY})\n"
574         ensure
575           @TEMPORARIES.push offset_reg
576         end
577       end
578     end
580     # Jumps to an address.
581     def goto address
582       if global? address
583         emit "j #{address}\n"
584       else
585         register = load_value address, @TEMPORARY
586         emit "jr #{register}\n"
587       end
588       emit "nop\n"
589     end
591     # Grows the stack by n bytes.
592     def grow_stack n
593       addiu "$sp", "$sp", -n
594     end
596     # Starts the false path of a conditional.
597     def ifelse
598       newlabel = @environment.gensym
599       emit "j #{newlabel}\n"
600       emit "nop\n"
601       label = @if_labels.pop
602       emit "#{label}:\n"
603       @if_labels.push newlabel
604     end
606     # Tests if x is equal to y
607     def ifeq x, y
608       common_if :ifeq, x, y
609     end
611     # Tests if x is greater than or equal to y
612     def ifge x, y
613       common_if :ifge, x, y
614     end
616     # Tests if x is strictly greater than y
617     def ifgt x, y
618       common_if :ifgt, x, y
619     end
621     # Tests if x is less than or equal to y
622     def ifle x, y
623       common_if :ifle, x, y
624     end
626     # Tests if x is strictly less than y
627     def iflt x, y
628       common_if :iflt, x, y
629     end
631     # Tests if x different from y
632     def ifne x, y
633       common_if :ifne, x, y
634     end
636     # Introduces a new local variable.
637     def let symbol, *expr
638       n = @environment.locals
639       register = local_register n
640       ref = local_reference n
641       if register
642         # We will use a register to store the value
643         @environment.add_local symbol, register
644         # Save current value of register
645         emit "sw #{register}, #{ref}\n"
646         @saved_registers << register
647         # Set new value
648         eval_expr expr, register
649       else
650         # We will use the stack to store the value
651         @environment.add_local symbol, local_offset(n)
652         eval_expr expr, @TEMPORARY
653         emit "sw #{@TEMPORARY}, #{ref}\n"
654       end
655     end
657     # Loads the value at the given address.
658     def load_at address, register = @TEMPORARY
659       load_value_into_register address, register
660       emit "lw #{register}, 0(#{register})\n"
661       register
662     end
664     # Loads a value into a register.
665     # Returns the name of the register.
666     # If the value was already in a register, the name of that
667     # register is returned.
668     # Else, the value is loaded into a register and the name of
669     # that register is returned. The register to use in that case
670     # may be specified using the optional second argument.
671     def load_value x, register = @TEMPORARY
672       if substitution? x
673         x = substitute_number x[1]
674       end
676       if x == 0
677         return "$0"
678       elsif integer? x
679         addiu register, "$0", x
680         return register
681       elsif symbol? x
682         binding = @environment[x]
683         if register? binding
684           # Value is already in a register. Return register name.
685           return binding
686         elsif binding.kind_of? Integer
687           # Load value from memory.
688           emit "lw #{register}, #{offset_reference binding}\n"
689           return register
690         else
691           # Assume global
692           if @relocated_symbols.include? x
693             emit "lw #{register}, %got(#{x})(#{@GOT})\n"
694           else
695             emit "lui #{register}, %hi(#{x})\n"
696             emit "addiu #{register}, %lo(#{x})\n"
697           end
698           return register
699         end
700       elsif at_expr? x
701         load_at x[1], register
702       else
703         raise "Don't know how to load #{x.inspect}"
704       end
705     end
707     # Loads a value into a specific register.
708     def load_value_into_register x, register
709       reg = load_value x, register
710       if reg != register
711         emit "move #{register}, #{reg}\n"
712       end
713     end
715     # Returns the offset from the frame base at which the nth local is stored.
716     # For register locals this is the offset at which the saved
717     # value (from the calling function) is stored.
718     def local_offset n
719       -(n + 4) * @WORDSIZE
720     end
722     # Returns an $sp-relative reference for the nth (0-based) local.
723     def local_reference n
724       offset_reference(local_offset(n))
725     end
727     # Returns the register in which the nth local (0-based) is stored, or
728     # nil if not stored in a register.
729     def local_register n
730       @LOCAL_REGISTERS[n]
731     end
733     # Computes the maximum number of locals that would fit in the current
734     # frame size.
735     def max_locals
736       # + 1, because the initial frame size has room for 1 local
737       (@frame_size - @INITIAL_FRAME_SIZE) / @WORDSIZE + 1
738     end
740     # Given an offset relative to the base of the frame, returns
741     # an reference to that memory location.
742     def offset_reference offset
743       "#{offset}($fp)"
744     end
746     # Returns true if the nth (0-based) local is stored in a register.
747     def register_local? n
748       n < @NREGISTER_LOCALS
749     end
751     # Returns from a function.
752     # 
753     # _words_ may contain an expression to be evaluated. The result
754     # of the evaluation is returned from the function.
755     def ret *words
756       # Compute return value and store it in @RETURN
757       eval_expr(words, @RETURN) unless words.empty?
758       # Go to epilogue
759       goto @function_end_label
760     end
762     # Saves the current frame at the given location.
763     def save_frame location
764       load_value_into_register location, @TEMPORARY
765       @SAVE_FRAME_REGISTERS.each_with_index do |register,i|
766         emit "sw #{register}, #{i * @WORDSIZE}(#{@TEMPORARY})\n"
767       end
768     end
770     # Sets a variable to the result of evaluating an expression.
771     def set symbol, *expr
772       if at_expr? symbol
773         eval_expr expr, @RETURN
774         load_value_into_register symbol.to_s[1..-1].to_sym, @TEMPORARY
775         emit "sw #{@RETURN}, 0(#{@TEMPORARY})\n"
776       else
777         x = @environment[symbol]
778         if x == nil
779           raise "Cannot change value of constant #{symbol}"
780         elsif register? x
781           eval_expr expr, x
782         else
783           # Should be an integer.
784           eval_expr expr, @TEMPORARY
785           emit "sw #{@TEMPORARY}, #{offset_reference x}\n"
786         end
787       end
788     end
790     # Sets the byte at _base_ + _offset_ to _value_.
791     def set_byte base, offset, value
792       # If base is an integer, but offset isn't, swap them
793       if !integer?(offset) && integer?(base)
794         base, offset = [offset, base]
795       end
797       value_reg = @TEMPORARIES.pop
798       load_value_into_register value, value_reg
799       begin
800         if integer? offset
801           base_reg = load_value base
802           emit "sb #{value_reg}, #{offset}(#{base_reg})\n"
803         else
804           eval_binop [:add, base, offset], @TEMPORARY
805           emit "sb #{value_reg}, 0(#{@TEMPORARY})\n"
806         end
807       ensure
808         @TEMPORARIES.push value_reg
809       end
810     end
812     # Sets the word at _base_ + _offset_ * +@WORDSIZE+ to _value_.
813     def set_word base, offset, value
814       value_reg = @TEMPORARIES.pop
815       load_value_into_register value, value_reg
816       begin
817         if integer? offset
818           base_reg = load_value base
819           emit "sw #{value_reg}, #{offset * @WORDSIZE}(#{base_reg})\n"
820         else
821           offset_reg = @TEMPORARIES.pop
822           begin
823             load_value_into_register offset, offset_reg
824             base_reg = load_value base
825             emit "sll #{offset_reg}, #{offset_reg}, 2\n"
826             emit "add #{@TEMPORARY}, #{base_reg}, #{offset_reg}\n"
827             emit "sw #{value_reg}, 0(#{@TEMPORARY})\n"
828           ensure
829             @TEMPORARIES.push offset_reg
830           end
831         end
832       ensure
833         @TEMPORARIES.push value_reg
834       end
835     end
837     # Defines a string with the given value.
838     def string value
839       code = ''
840       value.each_byte do |b|
841         if b == 92
842           code << "\\\\"
843         elsif b >= 32 && b < 127 && b != 34
844           code << b.chr
845         else
846           code << sprintf("\\%03o", b)
847         end
848       end
849       emit ".ascii \"#{code}\"\n"
850     end
852     # Calls a function, re-using the current call frame if possible.
853     def tail_call func, *args
854       # Compute number of stack arguments
855       nstackargs = number_of_stack_arguments args.length
856       # If we need more stack arguments than we have now,
857       # perform a normal call and return
858       if nstackargs > number_of_stack_arguments(@environment.args)
859         emit "# Not enough space for proper tail call; using regular call\n"
860         ret :call, func, *args
861       end
863       # Back up any stack arguments we will need after we overwrite them
864       temporaries = @TEMPORARIES.dup
865       nlocals = @environment.locals
866       (@NREGISTER_ARGS...args.length).each do |i|
867         x = @environment[args[i]]
868         if integer?(x) && x < arg_offset(i)
869           # args[i] is in a location that will have been overwritten by the
870           # time we get around to passing argument i to the called function.
871           # Make a backup of the value before we overwrite it.
872           if temporaries.empty?
873             # Oh dear, we're out of temporaries.
874             # Store the value in the current stack frame, extending it
875             # as necessary.
876             if nlocals >= max_locals
877               grow_stack 8
878             end
879             reg = load_value args[i]
880             emit "sw #{reg}, #{local_reference nlocals}\n"
881             args[i] = [:local, nlocals]
882             nlocals = nlocals + 1
883           else
884             # Load the argument into a temporary
885             reg = temporaries.shift
886             load_value_into_register args[i], reg
887             # Update args[i] so we know how to get to it later
888             args[i] = [:reg, reg]
889           end
890         end
891       end
893       # Set stack arguments
894       (@NREGISTER_ARGS...args.length).each do |i|
895         arg = args[i]
896         reg = @TEMPORARY
898         # Load value
899         if arg.kind_of? Array
900           # Special cases, created above
901           case arg[0]
902           when :reg
903             reg = arg[1]
904           when :local
905             emit "lw #{reg}, #{local_reference arg[1]}\n"
906           end
907         else
908           load_value_into_register arg, reg
909         end
911         # Store value in designated place
912         emit "sw #{reg}, #{arg_reference i}\n"
913       end
915       # Set register arguments
916       [@NREGISTER_ARGS,args.length].min.times do |i|
917         reg = arg_register i
918         load_value_into_register args[i], reg
919       end
921       # Load function address
922       if global? func
923         if @imports.has_key? func
924           # Load address from global offset table
925           emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
926         else
927           # Assume label defined in this module
928           emit "lui #{@FUNCTION}, %hi(#{func})\n"
929           emit "addiu #{@FUNCTION}, %lo(#{func})\n"
930         end
931       else
932         # Load address
933         load_value_into_register func, "#{@FUNCTION}"
934       end
936       # Restore saved registers
937       [@NREGISTER_LOCALS, @environment.locals].min.times do |n|
938         emit "lw #{local_register n}, #{local_reference n}\n"
939       end
941       # Restore return address
942       emit "lw $31, #{@RA_OFFSET}($fp)\n"
944       # Restore stack pointer
945       emit "move $sp, $fp\n"
947       # Restore frame pointer
948       emit "lw $fp, #{@FP_OFFSET}($fp)\n"
950       # Perform call
951       emit "jr #{@FUNCTION}\n"
952       # brach delay slot
953       emit "nop\n"
954     end
956     # Defines a word with the given value
957     def word value
958       emit ".int #{value}\n"
959     end
961     # Write generated code to the given IO object.
962     def write io
963       io.puts ".set noat"
964       @sections.each do |section,code|
965         unless code.empty?
966           io.puts ".section #{section.to_s}"
967           io.puts code
968           io.puts
969         end
970       end
971     end
973   end
975   # Register class for big endian MIPS
976   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
977                                            :architecture => :mips,
978                                            :format => :gas
981   # Register class for little endian MIPS
982   Voodoo::CodeGenerator.register_generator MIPSGasGenerator,
983                                            :architecture => :mipsel,
984                                            :format => :gas