voodoo 1.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Voodoo
2
4
  # Common base class for code generators.
3
5
  #
@@ -11,7 +13,7 @@ module Voodoo
11
13
  # - #has_feature?
12
14
  # - #output_file_name
13
15
  # - #output_file_suffix
14
- # - #write
16
+ # - #saved_frame_size
15
17
  #
16
18
  # This class contains base implementations of some of these methods,
17
19
  # which can be used and/or overridden by subclasses.
@@ -20,11 +22,16 @@ module Voodoo
20
22
  # is provided on the main page of the documentation of the Voodoo module.
21
23
  #
22
24
  class CommonCodeGenerator
25
+ # == Public Interface
26
+ #
27
+ # These methods implement the public interface of code generators.
28
+
23
29
  # Initializes the code generator.
24
- # _params_ shall be a hash containing parameters to the code generator,
25
- # and shall at least contain the keys <tt>:architecture</tt> and
26
- # <tt>:format</tt>, specifying the target architecture and output
27
- # format, respectively.
30
+ # _params_ is a hash of key-value pairs, and can be used to pass additional
31
+ # parameters to the generator.
32
+ # Standard parameters are :architecture and :format, which indicate the
33
+ # architecture and the output format. If these are not supplied, default
34
+ # values will be used. Subclasses may define additional parameters.
28
35
  def initialize params = {}
29
36
  @architecture = params[:architecture] || Config.default_architecture
30
37
  @format = params[:format] || Config.default_format
@@ -39,8 +46,10 @@ module Voodoo
39
46
  @top_level = Environment.initial_environment
40
47
  @environment = @top_level
41
48
  @output_file_suffix = '.o'
49
+ @open_labels = [] # Labels for which we must emit size annotations
50
+ @relocated_symbols = Set.new
42
51
  @features = {
43
- :voodoo => "1.0" # Voodoo language version
52
+ :voodoo => "1.1" # Voodoo language version
44
53
  }
45
54
  end
46
55
 
@@ -51,35 +60,41 @@ module Voodoo
51
60
  # add :data, [:align], [:label, :xyzzy], [:word, 42]
52
61
  #
53
62
  # This method implements the required functionality in terms
54
- # of the following methods, which must be implemented by subclasses:
63
+ # of a number of methods for individual incantations. These
64
+ # must be implemented by subclasses, although default implementations
65
+ # may be provided by CommonCodeGenerator. The following list contains
66
+ # the methods that the add method relies on. Methods that are provided
67
+ # by this class have been marked with a star. In general, these methods
68
+ # will require some functionality to be implemented by subclasses.
55
69
  #
56
- # - #align
57
- # - #asr
58
- # - #bsr
70
+ # - #align (*)
71
+ # - #block (*)
59
72
  # - #byte
60
73
  # - #call
74
+ # - #comment
75
+ # - #emit_label_size
61
76
  # - #end_if
62
- # - #export
63
- # - #begin_function
64
- # - #block
65
- # - #ifelse
77
+ # - #export (*)
78
+ # - #function (*)
79
+ # - #goto
80
+ # - #group
66
81
  # - #ifeq
67
82
  # - #ifge
68
83
  # - #ifgt
69
84
  # - #ifle
70
85
  # - #iflt
71
86
  # - #ifne
72
- # - #import
73
- # - #label
87
+ # - #import (*)
88
+ # - #label (*)
74
89
  # - #let
90
+ # - #restore_frame (*)
91
+ # - #restore_locals (*)
75
92
  # - #ret
76
- # - #rol
77
- # - #ror
93
+ # - #save_frame (*)
94
+ # - #save_locals (*)
78
95
  # - #set
79
96
  # - #set_byte
80
97
  # - #set_word
81
- # - #shl
82
- # - #shr
83
98
  # - #string
84
99
  # - #word
85
100
  #
@@ -89,35 +104,60 @@ module Voodoo
89
104
  keyword, args = action[0], action[1..-1]
90
105
  case keyword
91
106
  when :block
107
+ emit_voodoo :block
92
108
  block *args
109
+ emit_voodoo :end, :block
93
110
  when :function
111
+ emit_voodoo :function, *args[0]
94
112
  function args[0], *args[1..-1]
113
+ emit_voodoo :end, :function
114
+ when :group
115
+ emit_voodoo :group
116
+ old_open_labels = @open_labels
117
+ begin
118
+ @open_labels = []
119
+ args.each { |statement| add section, statement }
120
+ ensure
121
+ @open_labels = old_open_labels
122
+ end
123
+ emit_voodoo :end, :group
95
124
  when :ifeq, :ifge, :ifgt, :ifle, :iflt, :ifne
125
+ emit_voodoo keyword, *args[0]
96
126
  truebody = action[2]
97
127
  falsebody = action[3]
98
128
  send keyword, action[1][0], action[1][1]
99
129
  add section, *truebody
100
130
  if falsebody && !falsebody.empty?
131
+ emit_voodoo :else
101
132
  ifelse
102
133
  add section, *falsebody
103
134
  end
135
+ emit_voodoo :end, :if
104
136
  end_if
137
+ when :label, :string, :word
138
+ send *action
105
139
  when :return
140
+ emit_voodoo *action
106
141
  send :ret, *args
107
- when :'set-word'
108
- send :set_word, *args
109
- when :'set-byte'
110
- send :set_byte, *args
111
- when :'tail-call'
112
- send :tail_call, *args
113
142
  else
114
- send *action
143
+ emit_voodoo *action
144
+ underscored = keyword.to_s.gsub('-', '_').to_sym
145
+ send underscored, *args
146
+ end
147
+
148
+ # If we are on top-level and we have open labels and we just
149
+ # emitted something that isn't a label, emit size annotations
150
+ # for all open labels.
151
+ if !@open_labels.empty? && keyword != :label &&
152
+ @environment == @top_level
153
+ @open_labels.each { |name| emit_label_size name }
154
+ @open_labels.clear
115
155
  end
116
156
  end
117
157
  end
118
158
  end
119
159
 
120
- # Add function.
160
+ # Adds a function.
121
161
  #
122
162
  # Parameters:
123
163
  # [formals] an Array of formal parameter names
@@ -129,15 +169,106 @@ module Voodoo
129
169
  add :functions, [:function, formals] + code
130
170
  end
131
171
 
172
+ # Returns a hash describing the features supported by this code generator.
173
+ # The keys in this hash are the names of the supported features.
174
+ # The associated values are strings providing additional information about
175
+ # the feature, such as a version number.
176
+ def features
177
+ @features
178
+ end
179
+
180
+ # Returns a new, unused symbol.
181
+ def gensym
182
+ Environment.gensym
183
+ end
184
+
185
+ # Returns true if a feature is supported by this generator,
186
+ # false otherwise.
187
+ def has_feature? name
188
+ @features.has_key? name
189
+ end
190
+
191
+ # Given an input file name, returns the canonical output file name
192
+ # for this code generator.
193
+ def output_file_name input_name
194
+ input_name.sub(/\.voo$/, '') + @output_file_suffix
195
+ end
196
+
197
+ # Returns the canonical output file suffix for this code generator.
198
+ def output_file_suffix
199
+ @output_file_suffix
200
+ end
201
+
202
+ # == Helper Methods
203
+ #
204
+ # These methods are intended to be used by subclasses.
205
+
206
+ # Emits a directive to align the code or data following this
207
+ # statement. If _alignment_ is given, aligns on the next multiple
208
+ # of _alignment_ bytes. Else, uses the default alignment for the
209
+ # current section.
210
+ #
211
+ # This method requires the presence of a default_alignment method
212
+ # to calculate the default alignment for a given section, and an
213
+ # emit_align method to actually emit the target-specific code to
214
+ # align to a multiple of a given number of bytes. An implementation
215
+ # of default_alignment is provided in this class.
216
+ def align alignment = nil
217
+ alignment = default_alignment if alignment == nil
218
+ emit_align alignment unless alignment == 0
219
+ end
220
+
221
+ # Tests if op is a binary operation.
222
+ def assymetric_binop? op
223
+ [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op)
224
+ end
225
+
226
+ # Tests if a value is an at-expression.
227
+ def at_expr? value
228
+ value.respond_to?(:[]) && value[0] == :'@'
229
+ end
230
+
231
+ # Tests if op is a binary operation.
232
+ def binop? op
233
+ assymetric_binop?(op) || symmetric_binop?(op)
234
+ end
235
+
132
236
  # Processes code in its own block. Local variables can be
133
237
  # introduced inside the block. They will be deleted at the
134
238
  # end of the block.
239
+ #
240
+ # This method requires subclasses to implement begin_block and
241
+ # end_block.
135
242
  def block *code
136
243
  begin_block *code
137
244
  code.each { |action| add section, action }
138
245
  end_block
139
246
  end
140
247
 
248
+ # Returns the number of local variable slots required by
249
+ # a sequence of statements.
250
+ def count_locals statements
251
+ count_locals_helper statements, 0, 0
252
+ end
253
+
254
+ # Returns the default alignment for the given section.
255
+ # If no section is specified, returns the alignment for the current
256
+ # section.
257
+ def default_alignment section = @section
258
+ # Get default alignment
259
+ case section
260
+ when :code
261
+ @CODE_ALIGNMENT
262
+ when :data
263
+ @DATA_ALIGNMENT
264
+ when :function
265
+ @FUNCTION_ALIGNMENT
266
+ else
267
+ # Use data alignment as default
268
+ @DATA_ALIGNMENT
269
+ end
270
+ end
271
+
141
272
  # Invokes block with each statement in the given list of statements.
142
273
  # This iterator also descends into nested statements, calling
143
274
  # block first with the outer statement, and then for each inner
@@ -157,38 +288,108 @@ module Voodoo
157
288
  end
158
289
  end
159
290
 
160
- # Returns a hash describing the features supported by this code generator.
161
- # The keys in this hash are the names of the supported features.
162
- # The associated values are strings providing additional information about
163
- # the feature, such as a version number.
164
- def features
165
- @features
291
+ # Adds code to the current section.
292
+ def emit code
293
+ @sections[real_section_name(@section)] << code
166
294
  end
167
295
 
168
- # Add a function to the current section
296
+ # Emits a label.
297
+ def emit_label name
298
+ emit "#{name}:\n"
299
+ end
300
+
301
+ # Emits a comment with the given Voodoo code.
302
+ def emit_voodoo *code
303
+ comment code.join(' ')
304
+ end
305
+
306
+ # Declares that the given symbols are to be externally visible.
307
+ # Requires subclasses to implement emit_export.
308
+ def export *symbols
309
+ if real_section_name(section) == ".data"
310
+ @relocated_symbols.merge symbols
311
+ end
312
+ emit_export *symbols
313
+ end
314
+
315
+ # Adds a function to the current section.
316
+ # Requires subclasses to implement begin_function and end_function.
169
317
  def function formals, *code
170
- begin_function *formals
318
+ nlocals = count_locals code
319
+ begin_function formals, nlocals
171
320
  code.each { |action| add section, action }
172
321
  end_function
173
322
  end
174
323
 
175
- # Generate a new, unused symbol
176
- def gensym
177
- Environment.gensym
324
+ # Tests if a symbol refers to a global.
325
+ def global? symbol
326
+ symbol?(symbol) && @environment[symbol] == nil
178
327
  end
179
328
 
180
- # Add code to the current section
181
- def emit code
182
- @sections[real_section_name(@section)] << code
329
+ # Declares that the given symbols are imported from an external object.
330
+ # Requires subclasses to implement emit_import.
331
+ def import *symbols
332
+ if real_section_name(section) == ".data"
333
+ @relocated_symbols.merge symbols
334
+ end
335
+ emit_import *symbols
183
336
  end
184
337
 
185
- # Returns true if a feature is supported by this generator,
186
- # false otherwise.
187
- def has_feature? name
188
- @features.has_key? name
338
+ # Executes a block of code using the given section as the current section.
339
+ def in_section name, &block
340
+ oldsection = @section
341
+ self.section = name
342
+ begin
343
+ yield
344
+ ensure
345
+ self.section = oldsection
346
+ end
347
+ end
348
+
349
+ # Tests if a value is an integer.
350
+ def integer? value
351
+ value.kind_of? Integer
352
+ end
353
+
354
+ # Creates a label.
355
+ # Besides emitting the label name, this also annotates top-level
356
+ # objects with type and size as required for ELF shared libraries.
357
+ # Requires subclasses to emit emit_label and emit_label_type.
358
+ def label name
359
+ # If we are at top level, emit type directive and arrange to
360
+ # emit size directive.
361
+ if @environment == @top_level
362
+ case real_section_name(section)
363
+ when ".text"
364
+ type = :code
365
+ else
366
+ type = :data
367
+ end
368
+ emit_label_type name, type
369
+ @open_labels << name
370
+ end
371
+ emit_label name
372
+ end
373
+
374
+ # Returns the register in which the nth local (0-based) is stored, or
375
+ # nil if not stored in a register.
376
+ def local_register n
377
+ @LOCAL_REGISTERS[n + number_of_register_arguments]
189
378
  end
190
379
 
191
- # Get the real name of a section.
380
+ # Calculates the number of register arguments,
381
+ # given the total number of arguments.
382
+ def number_of_register_arguments n = @environment.args
383
+ [n, @NREGISTER_ARGS].min
384
+ end
385
+
386
+ # Calculate the number of stack arguments,
387
+ # given the total number of arguments.
388
+ def number_of_stack_arguments n = @environment.args
389
+ [0, n - @NREGISTER_ARGS].max
390
+ end
391
+
392
+ # Gets the real name of a section.
192
393
  # Given a section name which may be an alias, this method returns the
193
394
  # real name of the section.
194
395
  def real_section_name name
@@ -204,7 +405,114 @@ module Voodoo
204
405
  name
205
406
  end
206
407
 
207
- # Set the current section
408
+ # Returns true if operand is a register, false otherwise.
409
+ def register? x
410
+ x.kind_of? Symbol
411
+ end
412
+
413
+ # Returns true if the nth (0-based) argument is stored in a register.
414
+ def register_arg? n
415
+ n < @NREGISTER_ARGS
416
+ end
417
+
418
+ # Given some local variable names, returns the registers those variables
419
+ # are stored in. If no variable names are given, returns all registers
420
+ # used to store local variables.
421
+ #
422
+ # Requires @LOCAL_REGISTERS_SET, a set of registers that are used to
423
+ # store local variables.
424
+ def registers_for_locals locals = []
425
+ locals = @environment.symbols.keys if locals.empty?
426
+ registers = []
427
+ locals.each do |sym|
428
+ reg = @environment[sym]
429
+ registers << reg if @LOCAL_REGISTERS_SET.include? @environment[sym]
430
+ end
431
+ registers
432
+ end
433
+
434
+ # Restores the frame saved at the given location.
435
+ # Requires @SAVE_FRAME_REGISTERS, an array of register names that
436
+ # must be restored.
437
+ def restore_frame frame
438
+ restore_registers_from_frame frame, @SAVE_FRAME_REGISTERS
439
+ end
440
+
441
+ # Restores local variables from a saved frame.
442
+ def restore_locals frame, *locals
443
+ restore_registers_from_frame frame, registers_for_locals(locals)
444
+ end
445
+
446
+ # Helper function for restore_frame and restore_locals.
447
+ #
448
+ # Requires @SAVED_FRAME_LAYOUT, a map from register names to positions
449
+ # in a saved frame, emit_load_word to load registers from memory, and
450
+ # load_value_into_register to load a Voodoo value into a CPU register.
451
+ def restore_registers_from_frame frame, registers
452
+ with_temporary do |temporary|
453
+ load_value_into_register frame, temporary
454
+ registers.each do |register|
455
+ i = @SAVED_FRAME_LAYOUT[register]
456
+ emit_load_word register, temporary, i
457
+ end
458
+ end
459
+ end
460
+
461
+ # Saves the current frame to the given location.
462
+ #
463
+ # Requires @SAVE_FRAME_REGISTERS, an array of names of registers
464
+ # that must be saved, and @LOCAL_REGISTERS, the list of registers
465
+ # that are used to store values of local variables.
466
+ def save_frame frame
467
+ registers_to_save = @SAVE_FRAME_REGISTERS -
468
+ (@saved_registers & @LOCAL_REGISTERS)
469
+ save_registers_to_frame frame, registers_to_save
470
+ end
471
+
472
+ # Saves the current frame to the given location.
473
+ # If locals are given, saves those locals to the
474
+ # frame, too. If no locals are given, saves all
475
+ # locals.
476
+ #
477
+ # Requires @SAVE_FRAME_REGISTERS, an array of names of registers
478
+ # that must be saved, and @LOCAL_REGISTERS, the list of registers
479
+ # that are used to store values of local variables.
480
+ def save_frame_and_locals frame, *locals
481
+ registers_to_save = (@SAVE_FRAME_REGISTERS -
482
+ (@saved_registers & @LOCAL_REGISTERS)) |
483
+ registers_for_locals(locals)
484
+ save_registers_to_frame frame, registers_to_save
485
+ end
486
+
487
+ # Saves local variables to the given frame.
488
+ # If no locals are specified, saves all locals.
489
+ # If locals are specified, saves only the specified ones.
490
+ def save_locals frame, *locals
491
+ save_registers_to_frame frame, registers_for_locals(locals)
492
+ end
493
+
494
+ # Helper function for save_frame and save_locals.
495
+ #
496
+ # Requires @SAVED_FRAME_LAYOUT, a map from register names to positions
497
+ # in a saved frame, emit_store_word to store registers in memory, and
498
+ # load_value_into_register to load a Voodoo value into a CPU register.
499
+ def save_registers_to_frame frame, registers
500
+ return if registers.empty?
501
+ with_temporary do |temporary|
502
+ load_value_into_register frame, temporary
503
+ registers.each do |register|
504
+ i = @SAVED_FRAME_LAYOUT[register]
505
+ emit_store_word register, temporary, i
506
+ end
507
+ end
508
+ end
509
+
510
+ # Returns the number of bytes necessary to save the current frame.
511
+ def saved_frame_size
512
+ @SAVED_FRAME_LAYOUT.length * @WORDSIZE
513
+ end
514
+
515
+ # Sets the current section.
208
516
  def section= name
209
517
  real_name = real_section_name name
210
518
  @section = name
@@ -213,40 +521,90 @@ module Voodoo
213
521
  end
214
522
  end
215
523
 
524
+ # Returns the name of the current section.
525
+ # If a name is given, sets the name of the current section first.
216
526
  def section name = nil
217
527
  self.section = name if name
218
528
  @section
219
529
  end
220
530
 
221
- # Set up +alias_name+ to refer to the same section as +original_name+.
531
+ # Sets up _alias_name_ to refer to the same section as _original_name_.
222
532
  def section_alias alias_name, original_name
223
533
  @section_aliases[alias_name] = original_name
224
534
  end
225
535
 
226
- def in_section name, &block
227
- oldsection = @section
228
- self.section = name
229
- begin
230
- yield
231
- ensure
232
- self.section = oldsection
536
+ # Given n, returns the nearest multiple of @STACK_ALIGNMENT
537
+ # that is >= n.
538
+ def stack_align n
539
+ (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
540
+ end
541
+
542
+ # Tests if a value is a substitution.
543
+ def substitution? x
544
+ x.respond_to?(:[]) && x[0] == :'%'
545
+ end
546
+
547
+ # Substitutes a numeric value for a given substitution key.
548
+ def substitute_number key
549
+ case key
550
+ when :'saved-frame-size'
551
+ saved_frame_size
552
+ else
553
+ @features[key].to_i
233
554
  end
234
555
  end
556
+
557
+ # Tests if a value is a symbol.
558
+ def symbol? value
559
+ value.kind_of? Symbol
560
+ end
235
561
 
236
- # Given an input file name, returns the canonical output file name
237
- # for this code generator.
238
- def output_file_name input_name
239
- input_name.sub(/\.voo$/, '') + @output_file_suffix
562
+ # Test if op is a symmetric binary operation (i.e. it will yield the
563
+ # same result if the order of its source operands is changed).
564
+ def symmetric_binop? op
565
+ [:add, :and, :mul, :or, :xor].member? op
240
566
  end
241
567
 
242
- # Returns the canonical output file suffix for this code generator
243
- def output_file_suffix
244
- @output_file_suffix
568
+ # Executes a block of code, passing the block the name of +n+
569
+ # unused temporary registers.
570
+ #
571
+ # Requires @TEMPORARIES, an array of temporary registers.
572
+ def with_temporaries n, &block
573
+ if @TEMPORARIES.length < n
574
+ raise "Out of temporary registers"
575
+ else
576
+ temporaries = @TEMPORARIES.shift n
577
+ begin
578
+ yield *temporaries
579
+ ensure
580
+ @TEMPORARIES.unshift *temporaries
581
+ end
582
+ end
583
+ end
584
+
585
+ # Executes a block of code, passing the block the name of an unused
586
+ # temporary register as its first argument.
587
+ def with_temporary &block
588
+ with_temporaries 1, &block
589
+ end
590
+
591
+ # Writes generated code to the given IO object.
592
+ def write io
593
+ @sections.each do |section,code|
594
+ unless code.empty?
595
+ io.puts ".section #{section.to_s}"
596
+ io.puts code
597
+ io.puts
598
+ end
599
+ end
245
600
  end
246
601
 
602
+ # Used for scoping. Maintains a symbol table and keeps track of the number
603
+ # of bytes that have been allocated on the stack.
247
604
  class Environment
248
605
  @@gensym_counter = 0
249
606
 
607
+ attr_accessor :bytes, :offset
250
608
  attr_reader :args, :locals, :parent, :symbols
251
609
 
252
610
  # Creates a new environment.
@@ -261,30 +619,54 @@ module Voodoo
261
619
  @args = parent ? parent.args : 0
262
620
  ## Number of local variables
263
621
  @locals = parent ? parent.locals : 0
622
+ ## Offset between base pointer and end of frame.
623
+ @offset = parent ? parent.offset : 0
624
+ ## Number of bytes allocated in this environment.
625
+ @bytes = 0
264
626
  end
265
627
 
266
628
  # Adds symbol as an argument in this environment.
267
- def add_arg symbol
268
- @symbols[symbol] = [:arg, @args]
629
+ # +info+ can be used by the code generator to store information it needs
630
+ # about the symbol.
631
+ def add_arg symbol, info = nil
632
+ @symbols[symbol] = info
269
633
  @args = @args + 1
270
634
  end
271
635
 
272
636
  # Adds each of symbols to the arguments in
273
637
  # this environment.
638
+ # Each entry in +symbols+ can be either a symbol,
639
+ # or an array where the first element is the symbol and the second
640
+ # element is extra information to be stored with the symbol.
274
641
  def add_args symbols
275
- symbols.each { |sym| add_arg sym }
642
+ symbols.each do |sym|
643
+ if sym.respond_to? :[]
644
+ add_arg *sym
645
+ else
646
+ add_arg sym
647
+ end
648
+ end
276
649
  end
277
650
 
278
651
  # Adds symbol as a local variable in this environment.
279
- def add_local symbol
280
- @symbols[symbol] = [:local, @locals]
652
+ def add_local symbol, info = nil
653
+ @symbols[symbol] = info
281
654
  @locals = @locals + 1
282
655
  end
283
656
 
284
657
  # Adds each of symbols to the local variables in
285
658
  # this environment.
659
+ # Each entry in +symbols+ can be either a symbol,
660
+ # or an array where the first element is the symbol and the second
661
+ # element is extra information to be stored with the symbol.
286
662
  def add_locals symbols
287
- symbols.each { |sym| add_local sym }
663
+ symbols.each do |sym|
664
+ if sym.respond_to? :[]
665
+ add_local *sym
666
+ else
667
+ add_local sym
668
+ end
669
+ end
288
670
  end
289
671
 
290
672
  # Generates a new, unique symbol.
@@ -309,5 +691,21 @@ module Voodoo
309
691
  end
310
692
  end
311
693
 
694
+ private
695
+
696
+ # Returns the number of local variable slots required for the given
697
+ # statements, given the current count and required number of slots.
698
+ def count_locals_helper statements, count, max
699
+ statements.each do |statement|
700
+ case statement[0]
701
+ when :block
702
+ max = count_locals_helper statement[1..-1], count, max
703
+ when :let
704
+ count = count + 1
705
+ max = count if count > max
706
+ end
707
+ end
708
+ max
709
+ end
312
710
  end
313
711
  end