2 require 'voodoo/symbol_tracker'
5 # Common base class for code generators.
7 # Code generators are expected to implement the following methods:
16 # - #output_file_suffix
19 # This class contains base implementations of some of these methods,
20 # which can be used and/or overridden by subclasses.
22 # An example of how to use the code generators provided by this module
23 # is provided on the main page of the documentation of the Voodoo module.
25 class CommonCodeGenerator
28 # These methods implement the public interface of code generators.
30 # Initializes the code generator.
31 # _params_ is a hash of key-value pairs, and can be used to pass additional
32 # parameters to the generator.
33 # Standard parameters are :architecture and :format, which indicate the
34 # architecture and the output format. If these are not supplied, default
35 # values will be used. Subclasses may define additional parameters.
36 def initialize params = {}
37 @architecture = params[:architecture] || Config.default_architecture
38 @format = params[:format] || Config.default_format
41 # Default section aliases. Subclasses can start from scratch by
42 # doing @section_aliases = {}
43 section_alias :code, ".text"
44 section_alias :functions, :code
45 section_alias :data, ".data"
47 @top_level = Environment.initial_environment
48 @environment = @top_level
49 @output_file_suffix = '.o'
50 @open_labels = [] # Labels for which we must emit size annotations
51 @relocated_symbols = Set.new
52 @symbol_tracker = SymbolTracker.new
54 :voodoo => "1.1" # Voodoo language version
58 # Adds code to the given section.
61 # add :code, [:return, 0]
62 # add :data, [:align], [:label, :xyzzy], [:word, 42]
64 # This method implements the required functionality in terms
65 # of a number of methods for individual incantations. These
66 # must be implemented by subclasses, although default implementations
67 # may be provided by CommonCodeGenerator. The following list contains
68 # the methods that the add method relies on. Methods that are provided
69 # by this class have been marked with a star. In general, these methods
70 # will require some functionality to be implemented by subclasses.
92 # - #restore_frame (*)
93 # - #restore_locals (*)
103 def add section, *code
104 in_section section do
105 code.each do |action|
106 keyword, args = action[0], action[1..-1]
111 emit_voodoo :end, :block
113 emit_voodoo :function, *args[0]
114 function args[0], *args[1..-1]
115 emit_voodoo :end, :function
118 old_open_labels = @open_labels
121 args.each { |statement| add section, statement }
123 @open_labels = old_open_labels
125 emit_voodoo :end, :group
126 when :ifeq, :ifge, :ifgt, :ifle, :iflt, :ifne
127 emit_voodoo keyword, *args[0]
129 falsebody = action[3]
130 send keyword, action[1][0], action[1][1]
131 add section, *truebody
132 if falsebody && !falsebody.empty?
135 add section, *falsebody
137 emit_voodoo :end, :if
139 when :label, :string, :word
146 underscored = keyword.to_s.gsub('-', '_').to_sym
147 send underscored, *args
150 # If we are on top-level and we have open labels and we just
151 # emitted something that isn't a label, emit size annotations
152 # for all open labels.
153 if !@open_labels.empty? && keyword != :label &&
154 @environment == @top_level
155 @open_labels.each { |name| emit_label_size name }
165 # [formals] an Array of formal parameter names
166 # [code] an Array of actions to be used as the function's body
169 # add_function [:n], [:return, :add, :n, 1]
170 def add_function formals, *code
171 add :functions, [:function, formals] + code
174 # Returns a hash describing the features supported by this code generator.
175 # The keys in this hash are the names of the supported features.
176 # The associated values are strings providing additional information about
177 # the feature, such as a version number.
182 # Returns a new, unused symbol.
187 # Returns true if a feature is supported by this generator,
189 def has_feature? name
190 @features.has_key? name
193 # Given an input file name, returns the canonical output file name
194 # for this code generator.
195 def output_file_name input_name
196 input_name.sub(/\.voo$/, '') + @output_file_suffix
199 # Returns the canonical output file suffix for this code generator.
200 def output_file_suffix
206 # These methods are intended to be used by subclasses.
208 # Emits a directive to align the code or data following this
209 # statement. If _alignment_ is given, aligns on the next multiple
210 # of _alignment_ bytes. Else, uses the default alignment for the
213 # This method requires the presence of a default_alignment method
214 # to calculate the default alignment for a given section, and an
215 # emit_align method to actually emit the target-specific code to
216 # align to a multiple of a given number of bytes. An implementation
217 # of default_alignment is provided in this class.
218 def align alignment = nil
219 alignment = default_alignment if alignment == nil
220 emit_align alignment unless alignment == 0
223 # Tests if op is a binary operation.
224 def assymetric_binop? op
225 [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op)
228 # Tests if a value is an at-expression.
230 value.respond_to?(:[]) && value[0] == :'@'
233 # Tests if op is a binary operation.
235 assymetric_binop?(op) || symmetric_binop?(op)
238 # Processes code in its own block. Local variables can be
239 # introduced inside the block. They will be deleted at the
242 # This method requires subclasses to implement begin_block and
246 code.each { |action| add section, action }
250 # Returns the number of local variable slots required by
251 # a sequence of statements.
252 def count_locals statements
253 count_locals_helper statements, 0, 0
256 # Returns the default alignment for the given section.
257 # If no section is specified, returns the alignment for the current
259 def default_alignment section = @section
260 # Get default alignment
269 # Use data alignment as default
274 # Invokes block with each statement in the given list of statements.
275 # This iterator also descends into nested statements, calling
276 # block first with the outer statement, and then for each inner
278 def each_statement statements, &block
279 statements.each do |statement|
283 each_statement statement[1..-1], &block
285 each_statement statement[2..-1], &block
286 when :ifeq, :ifle, :iflt, :ifge, :ifgt, :ifne
287 each_statement statement[2], &block
288 each_statement(statement[3], &block) if statement.length > 3
293 # Adds code to the current section.
295 @sections[real_section_name(@section)] << code
298 # Emits code for an import incantation. For some targets, no code actually
299 # need be emitted, so the default implementation of this method does
301 def emit_import *symbols
302 # No need to emit anything.
310 # Emits a comment with the given Voodoo code.
311 def emit_voodoo *code
312 comment code.join(' ')
315 # Declares that the given symbols are to be externally visible.
316 # Requires subclasses to implement emit_export.
318 used_earlier = symbols_used_unrelocated symbols
319 # Exporting symbols after they have been used is not allowed.
321 unless used_earlier.empty?
322 error = CodeGenerator::SymbolsExportedAfterUseError.new(used_earlier)
325 if real_section_name(section) == ".data"
326 @relocated_symbols.merge symbols
328 @symbol_tracker.use *symbols
331 raise error unless error == nil
335 # Adds a function to the current section.
336 # Requires subclasses to implement begin_function and end_function.
337 def function formals, *code
338 nlocals = count_locals code
339 begin_function formals, nlocals
340 code.each { |action| add section, action }
344 # Tests if a symbol refers to a global.
346 symbol?(symbol) && @environment[symbol] == nil
349 # Declares that the given symbols are imported from an external object.
350 # This function calls emit_import to actually emit code for the import
351 # statements. The default implementation of emit_import does nothing,
352 # so targets where code is required for imports will want to override
355 used_earlier = symbols_used_unrelocated symbols
356 # Importing symbols after they have been used is not allowed.
358 unless used_earlier.empty?
359 error = CodeGenerator::SymbolsImportedAfterUseError.new(used_earlier)
362 @relocated_symbols.merge symbols
363 @symbol_tracker.define *symbols
366 raise error unless error == nil
370 # Executes a block of code using the given section as the current section.
371 def in_section name, &block
372 oldsection = @section
377 self.section = oldsection
381 # Tests if a value is an integer.
383 value.kind_of? Integer
387 # Besides emitting the label name, this also annotates top-level
388 # objects with type and size as required for ELF shared libraries.
389 # Requires subclasses to emit emit_label and emit_label_type.
391 # If we are at top level, emit type directive and arrange to
392 # emit size directive.
393 if @environment == @top_level
394 case real_section_name(section)
400 emit_label_type name, type
403 @symbol_tracker.define name
407 # Returns the register in which the nth local (0-based) is stored, or
408 # nil if not stored in a register.
410 @LOCAL_REGISTERS[n + number_of_register_arguments]
413 # Calculates the number of register arguments,
414 # given the total number of arguments.
415 def number_of_register_arguments n = @environment.args
416 [n, @NREGISTER_ARGS].min
419 # Calculate the number of stack arguments,
420 # given the total number of arguments.
421 def number_of_stack_arguments n = @environment.args
422 [0, n - @NREGISTER_ARGS].max
425 # Gets the real name of a section.
426 # Given a section name which may be an alias, this method returns the
427 # real name of the section.
428 def real_section_name name
431 x = @section_aliases[name]
432 break if x == nil # Not an alias, exit loop and return name
434 # If name == given_name, we're back where we started. Continuing
435 # would have us loop forever. Just return what we have now.
436 break if name == given_name
441 # Returns true if operand is a register, false otherwise.
446 # Returns true if the nth (0-based) argument is stored in a register.
451 # Given some local variable names, returns the registers those variables
452 # are stored in. If no variable names are given, returns all registers
453 # used to store local variables.
455 # Requires @LOCAL_REGISTERS_SET, a set of registers that are used to
456 # store local variables.
457 def registers_for_locals locals = []
458 locals = @environment.symbols.keys if locals.empty?
461 reg = @environment[sym]
462 registers << reg if @LOCAL_REGISTERS_SET.include? @environment[sym]
467 # Restores the frame saved at the given location.
468 # Requires @SAVE_FRAME_REGISTERS, an array of register names that
470 def restore_frame frame
471 restore_registers_from_frame frame, @SAVE_FRAME_REGISTERS
474 # Restores local variables from a saved frame.
475 def restore_locals frame, *locals
476 restore_registers_from_frame frame, registers_for_locals(locals)
479 # Helper function for restore_frame and restore_locals.
481 # Requires @SAVED_FRAME_LAYOUT, a map from register names to positions
482 # in a saved frame, emit_load_word to load registers from memory, and
483 # load_value_into_register to load a Voodoo value into a CPU register.
484 def restore_registers_from_frame frame, registers
485 with_temporary do |temporary|
486 load_value_into_register frame, temporary
487 registers.each do |register|
488 i = @SAVED_FRAME_LAYOUT[register]
489 emit_load_word register, temporary, i
494 # Saves the current frame to the given location.
496 # Requires @SAVE_FRAME_REGISTERS, an array of names of registers
497 # that must be saved, and @LOCAL_REGISTERS, the list of registers
498 # that are used to store values of local variables.
500 registers_to_save = @SAVE_FRAME_REGISTERS -
501 (@saved_registers & @LOCAL_REGISTERS)
502 save_registers_to_frame frame, registers_to_save
505 # Saves the current frame to the given location.
506 # If locals are given, saves those locals to the
507 # frame, too. If no locals are given, saves all
510 # Requires @SAVE_FRAME_REGISTERS, an array of names of registers
511 # that must be saved, and @LOCAL_REGISTERS, the list of registers
512 # that are used to store values of local variables.
513 def save_frame_and_locals frame, *locals
514 registers_to_save = (@SAVE_FRAME_REGISTERS -
515 (@saved_registers & @LOCAL_REGISTERS)) |
516 registers_for_locals(locals)
517 save_registers_to_frame frame, registers_to_save
520 # Saves local variables to the given frame.
521 # If no locals are specified, saves all locals.
522 # If locals are specified, saves only the specified ones.
523 def save_locals frame, *locals
524 save_registers_to_frame frame, registers_for_locals(locals)
527 # Helper function for save_frame and save_locals.
529 # Requires @SAVED_FRAME_LAYOUT, a map from register names to positions
530 # in a saved frame, emit_store_word to store registers in memory, and
531 # load_value_into_register to load a Voodoo value into a CPU register.
532 def save_registers_to_frame frame, registers
533 return if registers.empty?
534 with_temporary do |temporary|
535 load_value_into_register frame, temporary
536 registers.each do |register|
537 i = @SAVED_FRAME_LAYOUT[register]
538 emit_store_word register, temporary, i
543 # Returns the number of bytes necessary to save the current frame.
545 @SAVED_FRAME_LAYOUT.length * @WORDSIZE
548 # Sets the current section.
550 real_name = real_section_name name
552 unless @sections.has_key? real_name
553 @sections[real_name] = ''
557 # Returns the name of the current section.
558 # If a name is given, sets the name of the current section first.
559 def section name = nil
560 self.section = name if name
564 # Sets up _alias_name_ to refer to the same section as _original_name_.
565 def section_alias alias_name, original_name
566 @section_aliases[alias_name] = original_name
569 # Given n, returns the nearest multiple of @STACK_ALIGNMENT
572 (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
575 # Tests if a value is a substitution.
577 x.respond_to?(:[]) && x[0] == :'%'
580 # Substitutes a numeric value for a given substitution key.
581 def substitute_number key
583 when :'saved-frame-size'
590 # Tests if a value is a symbol.
592 value.kind_of? Symbol
595 # Test if op is a symmetric binary operation (i.e. it will yield the
596 # same result if the order of its source operands is changed).
597 def symmetric_binop? op
598 [:add, :and, :mul, :or, :xor].member? op
601 # Returns a set of symbols that have been used, but not defined.
602 def undefined_symbols
603 @symbol_tracker.used_but_undefined_symbols
606 # Executes a block of code, passing the block the name of +n+
607 # unused temporary registers.
609 # Requires @TEMPORARIES, an array of temporary registers.
610 def with_temporaries n, &block
611 if @TEMPORARIES.length < n
612 raise "Out of temporary registers"
614 temporaries = @TEMPORARIES.shift n
618 @TEMPORARIES.unshift *temporaries
623 # Executes a block of code, passing the block the name of an unused
624 # temporary register as its first argument.
625 def with_temporary &block
626 with_temporaries 1, &block
629 # Writes generated code to the given IO object.
631 @sections.each do |section,code|
633 io.puts ".section #{section.to_s}"
640 # Used for scoping. Maintains a symbol table and keeps track of the number
641 # of bytes that have been allocated on the stack.
645 attr_accessor :bytes, :offset
646 attr_reader :args, :locals, :parent, :symbols
648 # Creates a new environment.
649 # If parent is specified, it will become the new environment's parent.
650 # The new environment inherits all symbols from the parent environment.
651 def initialize parent = nil
652 ## Parent environment
654 ## Symbol lookup table
655 @symbols = parent ? parent.symbols.dup : {}
656 ## Number of arguments
657 @args = parent ? parent.args : 0
658 ## Number of local variables
659 @locals = parent ? parent.locals : 0
660 ## Offset between base pointer and end of frame.
661 @offset = parent ? parent.offset : 0
662 ## Number of bytes allocated in this environment.
666 # Adds symbol as an argument in this environment.
667 # +info+ can be used by the code generator to store information it needs
669 def add_arg symbol, info = nil
670 @symbols[symbol] = info
674 # Adds each of symbols to the arguments in
676 # Each entry in +symbols+ can be either a symbol,
677 # or an array where the first element is the symbol and the second
678 # element is extra information to be stored with the symbol.
680 symbols.each do |sym|
681 if sym.respond_to? :[]
689 # Adds symbol as a local variable in this environment.
690 def add_local symbol, info = nil
691 @symbols[symbol] = info
692 @locals = @locals + 1
695 # Adds each of symbols to the local variables in
697 # Each entry in +symbols+ can be either a symbol,
698 # or an array where the first element is the symbol and the second
699 # element is extra information to be stored with the symbol.
700 def add_locals symbols
701 symbols.each do |sym|
702 if sym.respond_to? :[]
710 # Generates a new, unique symbol.
715 # Looks up symbol in this environment.
720 # Generates a new, unique symbol.
722 @@gensym_counter = @@gensym_counter + 1
723 "_G#{@@gensym_counter}".to_sym
726 # Returns an initial, top-level environment.
727 def self.initial_environment
734 # Returns the number of local variable slots required for the given
735 # statements, given the current count and required number of slots.
736 def count_locals_helper statements, count, max
737 statements.each do |statement|
739 when :ifeq, :ifge, :ifgt, :ifle, :iflt, :ifne
740 max = count_locals_helper statement[2], count, max
741 if statement.length > 3
742 max = count_locals_helper statement[3], count, max
745 max = count_locals_helper statement[1..-1], count, max
748 max = count if count > max
754 # Given symbols, returns the set of symbols among those that
755 # have been used without relocation.
756 def symbols_used_unrelocated symbols
757 symbols_set = symbols.kind_of?(Set) ? symbols : Set.new(symbols)
758 new_symbols = symbols_set - @relocated_symbols
759 @symbol_tracker.used_symbols & new_symbols