voodoo 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: