voodoo 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ module Voodoo
2
2
  # Methods to get and set configuration parameters
3
3
  module Config
4
4
  IMPLEMENTATION_NAME = 'Voodoo Compiler'
5
- IMPLEMENTATION_VERSION = '1.1.3'
5
+ IMPLEMENTATION_VERSION = '1.1.4'
6
6
 
7
7
  # Class that holds configuration parameters
8
8
  class Configuration
@@ -162,13 +162,14 @@ module Voodoo
162
162
  end
163
163
  # Call function
164
164
  with_temporary do |temporary|
165
- value_ref = load_value func, temporary
166
- emit "xor rax, rax\n"
167
- # If value_ref is a symbol, use PLT-relative addressing
165
+ # If func is a global, use PLT-relative addressing
168
166
  if global?(func)
169
167
  @symbol_tracker.use func
168
+ emit "xor rax, rax\n"
170
169
  emit "call #{func} wrt ..plt\n"
171
170
  else
171
+ value_ref = load_value func, temporary
172
+ emit "xor rax, rax\n"
172
173
  emit "call #{value_ref}\n"
173
174
  end
174
175
  end
@@ -181,14 +182,8 @@ module Voodoo
181
182
  # Ends a function body.
182
183
  def end_function
183
184
  label @function_end_label
184
- # Restore saved registers
185
- @saved_registers.each_with_index do |register,i|
186
- ref = offset_reference saved_local_offset(i)
187
- emit "mov #{register}, #{ref}\n"
188
- end
189
- # Destroy frame.
185
+ restore_saved_registers
190
186
  emit "leave\n"
191
- # Return.
192
187
  emit "ret\n"
193
188
  if @environment == @top_level
194
189
  raise "Cannot end function when not in a function"
@@ -197,6 +192,14 @@ module Voodoo
197
192
  end
198
193
  end
199
194
 
195
+ # Restores saved registers.
196
+ def restore_saved_registers
197
+ @saved_registers.each_with_index do |register,i|
198
+ ref = offset_reference saved_local_offset(i)
199
+ emit "mov #{register}, #{ref}\n"
200
+ end
201
+ end
202
+
200
203
  # Returns from a function.
201
204
  def ret *words
202
205
  eval_expr words, @AX unless words.empty?
@@ -266,13 +269,16 @@ module Voodoo
266
269
  end
267
270
 
268
271
  # Tail call
269
- func_ref = load_value func, @BX
270
- emit "leave\n"
271
- set_register @AX, 0
272
- # If func_ref is a symbol, use PLT-relative addressing
273
- if global?(func)
274
- emit "jmp #{func_ref} wrt ..plt\n"
275
- else
272
+ with_temporary do |temporary|
273
+ # If func is a global, use PLT-relative addressing
274
+ if global?(func)
275
+ func_ref = "#{func} wrt ..plt\n"
276
+ else
277
+ func_ref = load_value func, temporary
278
+ end
279
+ restore_saved_registers
280
+ emit "leave\n"
281
+ set_register @AX, 0
276
282
  emit "jmp #{func_ref}\n"
277
283
  end
278
284
  end
@@ -72,6 +72,7 @@ module Voodoo
72
72
  #
73
73
  class ARMGasGenerator < CommonCodeGenerator
74
74
  def initialize params
75
+ @BYTES_PER_INSTRUCTION = 4
75
76
  @WORDSIZE_BITS = 2
76
77
  @WORDSIZE = 1 << @WORDSIZE_BITS
77
78
  @CODE_ALIGNMENT = 4
@@ -90,12 +91,15 @@ module Voodoo
90
91
  @SAVED_FRAME_LAYOUT = {}
91
92
  @SAVE_FRAME_REGISTERS.each_with_index { |r,i| @SAVED_FRAME_LAYOUT[r] = i }
92
93
  @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
94
+ @MAX_CONSTANT_POOL_OFFSET = 4096
93
95
  @NREGISTER_ARGS = 4
94
96
  @NREGISTER_LOCALS = @LOCAL_REGISTERS.length
95
97
  @FP = :r11
96
98
  @RETURN = :r0
97
99
  @TEMPORARIES = [:r12, :r3, :r2, :r1]
98
- @constants = []
100
+ @bytes_emitted_since_constants = 0
101
+ @constants = {}
102
+ @emitting_constants = false
99
103
  @frame_offset = 0
100
104
  @frame_size = 0
101
105
  @function_end_label = nil
@@ -114,9 +118,13 @@ module Voodoo
114
118
  # returning the label that will refer to the constant.
115
119
  # The value may be an integer or a label.
116
120
  def add_constant value
117
- label = gensym
118
- @constants << [label, value]
119
- label
121
+ # If the value is already in the constant pool, return its label.
122
+ # Else, add it to the pool with a new label and return that label.
123
+ @constants.fetch(value) do |value|
124
+ label = gensym
125
+ @constants[value] = label
126
+ label
127
+ end
120
128
  end
121
129
 
122
130
  # Returns the fp-relative offset for the nth (0-based) argument.
@@ -322,6 +330,22 @@ module Voodoo
322
330
  emit_constants if ret
323
331
  end
324
332
 
333
+ alias :_common_emit :emit
334
+
335
+ # Adds code to the current section.
336
+ def emit code
337
+ _common_emit code
338
+ if real_section_name(@section) == '.text'
339
+ @bytes_emitted_since_constants = @bytes_emitted_since_constants +
340
+ @BYTES_PER_INSTRUCTION
341
+ if !@emitting_constants &&
342
+ (@bytes_emitted_since_constants + @WORDSIZE * @constants.length) >
343
+ @MAX_CONSTANT_POOL_OFFSET - 2 * @BYTES_PER_INSTRUCTION
344
+ emit_constants_with_goto
345
+ end
346
+ end
347
+ end
348
+
325
349
  # Aligns on the next multiple of +n+ bytes.
326
350
  def emit_align n
327
351
  emit ".align #{n}\n"
@@ -330,11 +354,31 @@ module Voodoo
330
354
  # Writes any constants that need to be written to the instruction
331
355
  # stream, and clears the list of constants that need to be written.
332
356
  def emit_constants
333
- @constants.each do |x|
334
- label x[0]
335
- word x[1]
357
+ old_emitting_constants = @emitting_constants
358
+ begin
359
+ @emitting_constants = true
360
+ @constants.each do |value,l|
361
+ label l
362
+ word value
363
+ end
364
+ @constants = {}
365
+ @bytes_emitted_since_constants = 0
366
+ ensure
367
+ @emitting_constants = old_emitting_constants
368
+ end
369
+ end
370
+
371
+ # Emits constants, and code that jumps over the constants pool.
372
+ def emit_constants_with_goto
373
+ old_emitting_constants = @emitting_constants
374
+ begin
375
+ @emitting_constants = true
376
+ lbl = gensym
377
+ goto lbl
378
+ label lbl
379
+ ensure
380
+ @emitting_constants = old_emitting_constants
336
381
  end
337
- @constants = []
338
382
  end
339
383
 
340
384
  # Declares symbols to be exported.
@@ -408,9 +452,7 @@ module Voodoo
408
452
 
409
453
  # If we need to emit constants, do so now
410
454
  unless @constants.empty?
411
- lbl = gensym
412
- goto lbl
413
- label lbl
455
+ emit_constants_with_goto
414
456
  end
415
457
  end
416
458
 
@@ -686,7 +686,7 @@ module Voodoo
686
686
  if @relocated_symbols.include? x
687
687
  emit "lw #{register}, %got(#{x})(#{@GOT})\n"
688
688
  else
689
- emit "lui #{register}, %hi(#{x})\n"
689
+ emit "lw #{register}, %got(#{x})(#{@GOT})\n"
690
690
  emit "addiu #{register}, %lo(#{x})\n"
691
691
  end
692
692
  return register
@@ -281,60 +281,60 @@ module Voodoo
281
281
  end
282
282
 
283
283
  # Create a value reference to an address.
284
- # Invoking this code may clobber @BX and/or @CX
284
+ # Invoking this code may use a temporary and/or clobber @CX
285
285
  def load_address base, offset, scale
286
- base_ref = load_value base, @BX
287
- offset_ref = load_value offset, @CX
286
+ with_temporary do |temporary|
287
+ base_ref = load_value base, temporary
288
+ offset_ref = load_value offset, @CX
288
289
 
289
- if offset_ref == 0
290
- if integer? base_ref
291
- # Only an integer base
292
- "[#{base_ref}]"
293
- else
294
- # Some complex base; load in @BX
295
- emit "mov #{@BX}, #{base_ref}\n"
296
- "[#{@BX}]"
297
- end
298
- elsif base_ref == 0
299
- if integer? offset_ref
300
- # Only a scaled offset
301
- "[#{offset_ref.to_i * scale}]"
302
- else
303
- # Some complex offset; load in @CX
304
- emit "mov #{@CX}, #{offset_ref}\n"
305
- "[#{@CX} * #{scale}]"
306
- end
307
- elsif integer? base_ref
308
- if integer? offset_ref
309
- # All integers, combine them together
310
- "[#{base_ref.to_i + (offset_ref.to_i * scale)}]"
290
+ if offset_ref == 0
291
+ if integer? base_ref
292
+ # Only an integer base
293
+ "[#{base_ref}]"
294
+ else
295
+ # Some complex base; load in temporary
296
+ emit "mov #{temporary}, #{base_ref}\n"
297
+ "[#{temporary}]"
298
+ end
299
+ elsif base_ref == 0
300
+ if integer? offset_ref
301
+ # Only a scaled offset
302
+ "[#{offset_ref.to_i * scale}]"
303
+ else
304
+ # Some complex offset; load in @CX
305
+ emit "mov #{@CX}, #{offset_ref}\n"
306
+ "[#{@CX} * #{scale}]"
307
+ end
308
+ elsif integer? base_ref
309
+ if integer? offset_ref
310
+ # All integers, combine them together
311
+ "[#{base_ref.to_i + (offset_ref.to_i * scale)}]"
312
+ else
313
+ # Complex offset; use @CX
314
+ emit "mov #{@CX}, #{offset_ref}\n"
315
+ "[#{base_ref} + #{@CX} * #{scale}]"
316
+ end
317
+ elsif integer? offset_ref
318
+ # Complex base, integer offset; use temporary
319
+ emit "mov #{temporary}, #{base_ref}\n"
320
+ "[#{temporary} + #{offset_ref.to_i * scale}]"
311
321
  else
312
- # Complex offset; use @CX
322
+ # Both base and offset are complex
323
+ # Use both temporary and @CX
324
+ emit "mov #{temporary}, #{base_ref}\n"
313
325
  emit "mov #{@CX}, #{offset_ref}\n"
314
- "[#{base_ref} + #{@CX} * #{scale}]"
326
+ "[#{temporary} + #{@CX} * #{scale}]"
315
327
  end
316
- elsif integer? offset_ref
317
- # Complex base, integer offset; use @BX
318
- emit "mov #{@BX}, #{base_ref}\n"
319
- "[#{@BX} + #{offset_ref.to_i * scale}]"
320
- else
321
- # Both base and offset are complex
322
- # Use both @BX and @CX
323
- emit "mov #{@BX}, #{base_ref}\n"
324
- emit "mov #{@CX}, #{offset_ref}\n"
325
- "[#{@BX} + #{@CX} * #{scale}]"
326
328
  end
327
329
  end
328
330
 
329
331
  # Load the value at the given address.
330
- # Invoking this code may clobber @BX.
331
332
  def load_at address, reg
332
- if integer?(address) || (global?(address) &&
333
- !@relocated_symbols.include?(address))
333
+ if integer?(address)
334
334
  "[#{address}]"
335
335
  else
336
- load_value_into_register address, @BX
337
- "[#{@BX}]"
336
+ load_value_into_register address, reg
337
+ "[#{reg}]"
338
338
  end
339
339
  end
340
340
 
@@ -415,8 +415,10 @@ module Voodoo
415
415
  eval_expr words, @environment[target]
416
416
  else
417
417
  eval_expr words, @RETURN_REG
418
- target_ref = load_value target, @BX
419
- emit "mov #{target_ref}, #{@RETURN_REG}\n"
418
+ with_temporary do |temporary|
419
+ target_ref = load_value target, temporary
420
+ emit "mov #{target_ref}, #{@RETURN_REG}\n"
421
+ end
420
422
  end
421
423
  end
422
424
  end
@@ -448,8 +450,10 @@ module Voodoo
448
450
  # Divide x by y and store the quotient in target
449
451
  def div target, x, y
450
452
  eval_div x, y
451
- target_ref = load_value target, @BX
452
- emit "mov #{target_ref}, #{@AX}\n"
453
+ with_temporary do |temporary|
454
+ target_ref = load_value target, temporary
455
+ emit "mov #{target_ref}, #{@AX}\n"
456
+ end
453
457
  end
454
458
 
455
459
  # Divide target by x and store the quotient in target
@@ -460,8 +464,10 @@ module Voodoo
460
464
  # Divide x by y and store the remainder in target
461
465
  def mod target, x, y
462
466
  eval_div x, y
463
- target_ref = load_value target, @BX
464
- emit "mov #{target_ref}, #{@DX}\n"
467
+ with_temporary do |temporary|
468
+ target_ref = load_value target, temporary
469
+ emit "mov #{target_ref}, #{@DX}\n"
470
+ end
465
471
  end
466
472
 
467
473
  # Divide target by x and store the remainder in target
@@ -472,8 +478,10 @@ module Voodoo
472
478
  # Multiply x by y and store the result in target
473
479
  def mul target, x, y
474
480
  eval_mul x, y
475
- target_ref = load_value target, @BX
476
- emit "mov #{target_ref}, #{@RETURN_REG}\n"
481
+ with_temporary do |temporary|
482
+ target_ref = load_value target, temporary
483
+ emit "mov #{target_ref}, #{@RETURN_REG}\n"
484
+ end
477
485
  end
478
486
 
479
487
  # Multiply target by x and store the result in target
@@ -494,8 +502,8 @@ module Voodoo
494
502
  emit "mov #{@DX}, #{@AX}\n"
495
503
  emit "sar #{@DX}, #{@WORDSIZE * 8 - 1}\n"
496
504
  if immediate_operand?(y_ref)
497
- set_register @BX, y_ref
498
- emit "idiv #{@BX}\n"
505
+ set_register temporary, y_ref
506
+ emit "idiv #{temporary}\n"
499
507
  else
500
508
  emit "idiv #{@WORD_NAME} #{y_ref}\n"
501
509
  end
@@ -504,7 +512,7 @@ module Voodoo
504
512
 
505
513
  # Evaluate an expression.
506
514
  # The result is stored in _register_ (@RETURN_REG by default).
507
- # The following registers may be clobbered: @AX, @BX, @CX, @DX
515
+ # The following registers may be clobbered: @AX, @CX, @DX
508
516
  def eval_expr words, register = @RETURN_REG
509
517
  if words.length == 1
510
518
  if words[0] == 0
@@ -569,10 +577,18 @@ module Voodoo
569
577
  emit "not #{register}\n"
570
578
  else
571
579
  if binop?(op)
572
- x_ref = load_value words[1], @DX
573
- y_ref = load_value words[2], @BX
574
- emit "mov #{register}, #{x_ref}\n" unless register == x_ref
575
- emit "#{op} #{register}, #{y_ref}\n"
580
+ with_temporary do |t1|
581
+ x_ref = load_value words[1], @DX
582
+ y_ref = load_value words[2], t1
583
+ if register == y_ref
584
+ emit "mov #{@DX}, #{x_ref}\n"
585
+ emit "#{op} #{@DX}, #{y_ref}\n"
586
+ emit "mov #{register}, #{@DX}\n"
587
+ else
588
+ emit "mov #{register}, #{x_ref}\n" unless register == x_ref
589
+ emit "#{op} #{register}, #{y_ref}\n"
590
+ end
591
+ end
576
592
  else
577
593
  raise "Not a magic word: #{words[0]}"
578
594
  end
@@ -585,22 +601,24 @@ module Voodoo
585
601
  # a different register can be specified by passing
586
602
  # a third argument.
587
603
  def eval_mul x, y, register = @AX
588
- x_ref = load_value x, @DX
589
- y_ref = load_value y, @BX
604
+ with_temporary do |t1|
605
+ x_ref = load_value x, @DX
606
+ y_ref = load_value y, t1
590
607
 
591
- if immediate_operand? x_ref
592
- if immediate_operand? y_ref
593
- set_register register, x_ref * y_ref
608
+ if immediate_operand? x_ref
609
+ if immediate_operand? y_ref
610
+ set_register register, x_ref * y_ref
611
+ else
612
+ emit "imul #{register}, #{y_ref}, #{x_ref}\n"
613
+ end
614
+ elsif immediate_operand? y_ref
615
+ emit "imul #{register}, #{x_ref}, #{y_ref}\n"
616
+ elsif y_ref != register
617
+ emit "mov #{register}, #{x_ref}\n" unless x_ref == register
618
+ emit "imul #{register}, #{y_ref}\n"
594
619
  else
595
- emit "imul #{register}, #{y_ref}, #{x_ref}\n"
620
+ emit "imul #{register}, #{x_ref}\n"
596
621
  end
597
- elsif immediate_operand? y_ref
598
- emit "imul #{register}, #{x_ref}, #{y_ref}\n"
599
- elsif y_ref != register
600
- emit "mov #{register}, #{x_ref}\n" unless x_ref == register
601
- emit "imul #{register}, #{y_ref}\n"
602
- else
603
- emit "imul #{register}, #{x_ref}\n"
604
622
  end
605
623
  end
606
624
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voodoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.3
4
+ version: 1.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-01 00:00:00.000000000 Z
12
+ date: 2014-11-10 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'The Voodoo compiler is an implementation of the Voodoo programming
15
15
 
@@ -30,28 +30,28 @@ extensions: []
30
30
  extra_rdoc_files: []
31
31
  files:
32
32
  - bin/voodooc
33
+ - lib/voodoo.rb
34
+ - lib/voodoo/config.rb
35
+ - lib/voodoo/error.rb
36
+ - lib/voodoo/code_generator.rb
37
+ - lib/voodoo/parser.rb
33
38
  - lib/voodoo/symbol_tracker.rb
34
- - lib/voodoo/generators/arm_gas_generator.rb
35
- - lib/voodoo/generators/mips_gas_generator.rb
36
- - lib/voodoo/generators/common_code_generator.rb
37
- - lib/voodoo/generators/mips_elf_generator.rb
39
+ - lib/voodoo/validator.rb
40
+ - lib/voodoo/compiler.rb
41
+ - lib/voodoo/generators/nasm_generator.rb
38
42
  - lib/voodoo/generators/dummy_generator.rb
39
- - lib/voodoo/generators/amd64_elf_generator.rb
43
+ - lib/voodoo/generators/i386_nasm_generator.rb
40
44
  - lib/voodoo/generators/arm_elf_generator.rb
45
+ - lib/voodoo/generators/nasm_elf_generator.rb
46
+ - lib/voodoo/generators/gas_elf_generator.rb
41
47
  - lib/voodoo/generators/i386_elf_generator.rb
42
- - lib/voodoo/generators/i386_nasm_generator.rb
43
48
  - lib/voodoo/generators/amd64_nasm_generator.rb
44
- - lib/voodoo/generators/nasm_generator.rb
49
+ - lib/voodoo/generators/common_code_generator.rb
50
+ - lib/voodoo/generators/mips_gas_generator.rb
51
+ - lib/voodoo/generators/arm_gas_generator.rb
52
+ - lib/voodoo/generators/mips_elf_generator.rb
53
+ - lib/voodoo/generators/amd64_elf_generator.rb
45
54
  - lib/voodoo/generators/command_postprocessor.rb
46
- - lib/voodoo/generators/gas_elf_generator.rb
47
- - lib/voodoo/generators/nasm_elf_generator.rb
48
- - lib/voodoo/parser.rb
49
- - lib/voodoo/config.rb
50
- - lib/voodoo/error.rb
51
- - lib/voodoo/validator.rb
52
- - lib/voodoo/code_generator.rb
53
- - lib/voodoo/compiler.rb
54
- - lib/voodoo.rb
55
55
  homepage: http://inglorion.net/software/voodoo/
56
56
  licenses: []
57
57
  post_install_message: