voodoo 1.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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.0.2
4
+ version: 1.1.1
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: 2012-11-15 00:00:00.000000000 Z
12
+ date: 2013-07-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'The Voodoo compiler is an implementation of the Voodoo programming
15
15
 
@@ -30,26 +30,26 @@ extensions: []
30
30
  extra_rdoc_files: []
31
31
  files:
32
32
  - bin/voodooc
33
- - lib/voodoo/config.rb
33
+ - lib/voodoo.rb
34
34
  - lib/voodoo/parser.rb
35
- - lib/voodoo/validator.rb
36
- - lib/voodoo/generators/arm_gas_generator.rb~
37
- - lib/voodoo/generators/common_code_generator.rb
38
35
  - lib/voodoo/generators/mips_elf_generator.rb
39
- - lib/voodoo/generators/command_postprocessor.rb
40
- - lib/voodoo/generators/nasm_generator.rb
36
+ - lib/voodoo/generators/common_code_generator.rb
41
37
  - lib/voodoo/generators/nasm_elf_generator.rb
42
- - lib/voodoo/generators/amd64_elf_generator.rb
43
- - lib/voodoo/generators/arm_elf_generator.rb
44
- - lib/voodoo/generators/arm_gas_generator.rb
38
+ - lib/voodoo/generators/amd64_nasm_generator.rb
39
+ - lib/voodoo/generators/gas_elf_generator.rb
45
40
  - lib/voodoo/generators/i386_nasm_generator.rb
41
+ - lib/voodoo/generators/arm_gas_generator.rb
42
+ - lib/voodoo/generators/nasm_generator.rb
46
43
  - lib/voodoo/generators/mips_gas_generator.rb
47
- - lib/voodoo/generators/gas_elf_generator.rb
44
+ - lib/voodoo/generators/dummy_generator.rb
45
+ - lib/voodoo/generators/arm_elf_generator.rb
46
+ - lib/voodoo/generators/amd64_elf_generator.rb
48
47
  - lib/voodoo/generators/i386_elf_generator.rb
49
- - lib/voodoo/generators/amd64_nasm_generator.rb
48
+ - lib/voodoo/generators/command_postprocessor.rb
50
49
  - lib/voodoo/code_generator.rb
51
50
  - lib/voodoo/compiler.rb
52
- - lib/voodoo.rb
51
+ - lib/voodoo/validator.rb
52
+ - lib/voodoo/config.rb
53
53
  homepage: http://inglorion.net/software/voodoo/
54
54
  licenses: []
55
55
  post_install_message:
@@ -1,957 +0,0 @@
1
- require 'voodoo/generators/common_code_generator'
2
-
3
- module Voodoo
4
- # = ARM GNU Assembler Code Generator
5
- #
6
- # The ARM code generator generates assembly code for use with
7
- # the GNU assembler.
8
- #
9
- # == Calling Convention
10
- #
11
- # The first four arguments are passed in the registers r0 through r3.
12
- # Any additional arguments are passed on the stack, starting at
13
- # r13. r13 will always be a multiple of 8.
14
- #
15
- # The return address for the called function is passed in r14.
16
- #
17
- # The called function will store its return value in r0.
18
- #
19
- # The called function is required to preserve the values of registers
20
- # r4 through r11 and register r13.
21
- #
22
- # This calling convention is compatible with the Procedure Call
23
- # Standard for the ARM Architecture (AAPCS).
24
- #
25
- # == Call Frames
26
- #
27
- # Call frames have the following layout:
28
- #
29
- # When a function is called, it receives a stack frame that looks like
30
- # the following:
31
- #
32
- # :
33
- # old frame
34
- # padding
35
- # argn
36
- # :
37
- # arg4 <-- r13 points here
38
- #
39
- # The function prologue of functions generated by this code generator
40
- # creates activation frames that look as follows:
41
- #
42
- # :
43
- # old frame
44
- # padding
45
- # argn
46
- # :
47
- # arg4 <-- r11 points here
48
- # saved r14
49
- # saved r11
50
- # :
51
- # saved r4 <-- r13 points here
52
- #
53
- # == Register Usage
54
- #
55
- # Inside a function, registers r4..r8 and r10 are used for local variables
56
- # and function arguments, whereas r11 is used as a frame pointer.
57
- #
58
- # r12 is used as a temporary, and r3 is used when another temporary
59
- # is needed.
60
- #
61
- class ARMGasGenerator < CommonCodeGenerator
62
- def initialize params
63
- @WORDSIZE_BITS = 2
64
- @WORDSIZE = 1 << @WORDSIZE_BITS
65
- @CODE_ALIGNMENT = 4
66
- @DATA_ALIGNMENT = @WORDSIZE
67
- @FUNCTION_ALIGNMENT = @WORDSIZE
68
- @STACK_ALIGNMENT_BITS = 3
69
- @STACK_ALIGNMENT = 1 << @STACK_ALIGNMENT_BITS
70
-
71
- @INITIAL_FRAME_SIZE = 2 * @WORDSIZE
72
- @NREGISTER_ARGS = 4
73
- @NREGISTER_LOCALS = 6
74
- @FP = :r11
75
- @RETURN = :r0
76
- @TEMPORARY = :r12
77
- @constants = []
78
- @frame_offset = 0
79
- @frame_size = 0
80
- @function_end_label = nil
81
- @imports = {}
82
- @if_labels = []
83
- @saved_registers = []
84
- super params
85
- @output_file_suffix = '.s'
86
- @features.merge! \
87
- :'bits-per-word' => '32',
88
- :'byte-order' => 'little-endian',
89
- :'bytes-per-word' => 4
90
- end
91
-
92
- # Create an entry in the constants table,
93
- # returning the label that will refer to the constant.
94
- # The value may be an integer or a label.
95
- def add_constant value
96
- label = gensym
97
- @constants << [label, value]
98
- label
99
- end
100
-
101
- def align alignment = nil
102
- unless alignment
103
- # Get default alignment
104
- case @section
105
- when :code
106
- alignment = @CODE_ALIGNMENT
107
- when :data
108
- alignment = @DATA_ALIGNMENT
109
- when :function
110
- alignment = @FUNCTION_ALIGNMENT
111
- else
112
- # Use data alignment as default
113
- alignment = @DATA_ALIGNMENT
114
- end
115
- end
116
- emit ".align #{alignment}\n" unless alignment == 0
117
- end
118
-
119
- # Returns the fp-relative offset for the nth (0-based) argument.
120
- def arg_offset n
121
- (n - @NREGISTER_ARGS) * @WORDSIZE
122
- end
123
-
124
- # Returns an fp-relative reference for the nth (0-based) argument.
125
- def arg_reference n
126
- offset_reference arg_offset(n)
127
- end
128
-
129
- # Return the register in which the nth (0-based) argument is stored, or
130
- # nil if not stored in a register
131
- def arg_register n
132
- # The first @NREGISTER_ARGS arguments are in the v registers,
133
- # the rest are on the stack.
134
- if register_arg? n
135
- "v#{n + 1}"
136
- else
137
- nil
138
- end
139
- end
140
-
141
- # Test if op is a binary operation
142
- def assymetric_binop? op
143
- [:asr, :bsr, :div, :mod, :rol, :ror, :shl, :shr, :sub].member?(op)
144
- end
145
-
146
- # Test if a value is an at-expression
147
- def at_expr? value
148
- value.respond_to?(:[]) && value[0] == :'@'
149
- end
150
-
151
- def auto_bytes value, register
152
- if value.kind_of? Integer
153
- grow_frame value
154
- else
155
- temporary = register == :sp ? @TEMPORARY : register
156
- load_value_into_register value, temporary
157
- auto_bytes_register temporary
158
- end
159
- emit "cpy #{register}, sp\n" unless register == :sp
160
- end
161
-
162
- # auto-bytes where the value is supplied in a register and the return
163
- # value will be in sp. register must not be sp.
164
- def auto_bytes_register register
165
- temporary = register == @TEMPORARY ? :r3 : @TEMPORARY
166
- emit "add #{register}, #{register}, \##{@STACK_ALIGNMENT - 1}\n"
167
- emit "mvn #{temporary}, \##{@STACK_ALIGNMENT - 1}\n"
168
- emit "and #{register}, #{register}, #{temporary}\n"
169
- emit "sub sp, #{temp1}\n"
170
- end
171
-
172
- def auto_words value, register
173
- if value.kind_of? Integer
174
- auto_bytes(value * @WORDSIZE, register)
175
- else
176
- temporary = register == :sp ? @TEMPORARY : register
177
- load_value_into_register value, temporary
178
- emit "lsl #{temporary}, #{temporary}, \##{@WORDSIZE_BITS}\n"
179
- auto_bytes_register temporary
180
- emit "cpy #{register}, sp\n" unless register == :sp
181
- end
182
- end
183
-
184
- # Begins a new block.
185
- def begin_block *code
186
- emit "# begin block\n"
187
- # If we are starting a block at top level, create a frame
188
- if @environment == @top_level
189
- nlocals = count_locals code
190
- create_frame nlocals, false
191
- end
192
- @environment = Environment.new @environment
193
- end
194
-
195
- # Emit function prologue and declare _formals_ as function arguments
196
- def begin_function formals, nlocals
197
- if @environment != @top_level
198
- raise "Can only begin a function at top level"
199
- end
200
-
201
- @function_end_label = gensym
202
- emit "# function #{formals.join ' '}\n"
203
- environment = Environment.new @environment
204
- formals.each_with_index do |formal, i|
205
- if i < @NREGISTER_ARGS
206
- environment.add_arg formal, arg_register(i)
207
- else
208
- environment.add_arg formal, arg_offset(i)
209
- end
210
- end
211
- @environment = environment
212
- emit_function_prologue formals, nlocals
213
- end
214
-
215
- # Test if op is a binary operation
216
- def binop? op
217
- assymetric_binop?(op) || symmetric_binop?(op)
218
- end
219
-
220
- # Define a byte with the given value
221
- def byte value
222
- emit ".byte #{value}\n"
223
- end
224
-
225
- # Call a function.
226
- def call func, *args
227
- emit "# call #{func} #{args.join ' '}\n"
228
-
229
- # Calculate how many arguments need to be pushed on
230
- # the stack, and allocate space for them.
231
- nstack_args = number_of_stack_arguments args.length
232
- old_frame_offset = @frame_offset
233
- old_frame_size = @frame_size
234
- grow_frame nstack_args if nstack_args > 0
235
-
236
- # Put stack arguments on the stack
237
- (@NREGISTER_ARGS...args.length).each do |n|
238
- load_value_into_register args[n], @TEMPORARY
239
- emit "str #{@TEMPORARY}, " +
240
- "[sp , \##{(n - @NREGISTER_ARGS) * @WORDSIZE}]\n"
241
- end
242
-
243
- # Put register arguments in the right registers
244
- nregister_args = number_of_register_arguments args.length
245
- nregister_args.times do |n|
246
- load_value_into_register args[n], :"a#{n + 1}"
247
- end
248
-
249
- # Call function
250
- if global? func
251
- emit "bl #{func}\n"
252
- else
253
- func_reg = load_value func
254
- emit "blx #{func_reg}\n"
255
- end
256
-
257
- # Restore original stack frame
258
- if old_frame_size != @frame_size
259
- emit "add sp, sp, \##{@frame_size - old_frame_size}\n"
260
- @frame_offset = old_frame_offset
261
- @frame_size = old_frame_size
262
- end
263
- end
264
-
265
- # Creates a stack frame for the given number of arguments
266
- # and local variables.
267
- def create_frame nvars, save_lr = true
268
- # Calculate how many variables we will store in registers,
269
- # and how many on the stack.
270
- nregister_vars = [nvars, @NREGISTER_LOCALS].min
271
- nstack_vars = nvars - nregister_vars
272
-
273
- # Save the registers we will clobber to the stack.
274
- clobbered = []
275
- nregister_vars.times do |i|
276
- clobbered << :"v#{i < 5 ? i + 1 : i + 2}"
277
- end
278
- clobbered << @FP
279
- clobbered << :lr if save_lr
280
- @saved_registers = clobbered
281
- emit "stmfd sp!, {#{clobbered.join ', '}}\n"
282
- emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
283
-
284
- # Calculate frame size so that the stack pointer will
285
- # be properly aligned at the end of emit_function_prologue.
286
- @frame_size = stack_align((clobbered.length + nstack_vars) * @WORDSIZE)
287
- extra_space = @frame_size - clobbered.length * @WORDSIZE
288
- if extra_space > 0
289
- emit "sub sp, sp, \##{extra_space}\n"
290
- end
291
- @frame_offset = 0
292
- end
293
-
294
- # Start a conditional using the specified branch instruction
295
- # after the comparison.
296
- def common_if comp, x, y = nil
297
- emit "# #{comp} #{x} #{y}\n"
298
-
299
- xreg = load_value x, @TEMPORARY
300
- yreg = load_value y, :a4
301
-
302
- falselabel = @environment.gensym
303
- @if_labels.push falselabel
304
-
305
- emit "cmp #{xreg}, #{yreg}\n"
306
-
307
- lut = { :ifeq => "bne", :ifge => "blt", :ifgt => "ble",
308
- :ifle => "bgt", :iflt => "bge", :ifne => "beq" }
309
- emit "#{lut[comp]} #{falselabel}\n"
310
- end
311
-
312
- # Counts the number of local variables created in
313
- # a sequence of statements.
314
- def count_locals statements
315
- count = 0
316
- each_statement(statements) do |statement|
317
- if statement[0] == :let
318
- # let introduces a single local
319
- count = count + 1
320
- end
321
- end
322
- count
323
- end
324
-
325
- # Destroys the current stack frame.
326
- # If ret is true, loads the saved value of lr into pc.
327
- def destroy_frame ret = false
328
- # Set sp back to where saved registers were stored
329
- saved = @saved_registers
330
- emit "sub sp, #{@FP}, \##{saved.length * @WORDSIZE}\n"
331
-
332
- if ret
333
- index = saved.index :lr
334
- if index
335
- saved[index] = :pc
336
- else
337
- raise "Request to load saved lr into pc, but lr has not been saved"
338
- end
339
- end
340
- emit "ldmfd sp!, {#{saved.join ', '}}\n"
341
-
342
- emit_constants if ret
343
- end
344
-
345
- # Writes any constants that need to be written to the instruction
346
- # stream, and clears the list of constants that need to be written.
347
- def emit_constants
348
- @constants.each do |x|
349
- label x[0]
350
- word x[1]
351
- end
352
- @constants = []
353
- end
354
-
355
- # Emit function prologue.
356
- def emit_function_prologue formals = [], nlocals = 0
357
- # Calculate the number of arguments we were passed in
358
- # registers, the total number of values we need to save
359
- # on the stack, then create a stack frame and save
360
- # the v registers we will be using.
361
- nregister_args = [formals.length, @NREGISTER_ARGS].min
362
- nvars = nregister_args + nlocals
363
- create_frame nvars, true
364
-
365
- # Move arguments that were passed in registers into
366
- # callee-save registers.
367
- nregister_args.times do |i|
368
- emit "cpy v#{i + 1}, a#{i + 1}\n"
369
- end
370
- end
371
-
372
- # Ends the current block.
373
- def end_block
374
- emit "# end block\n"
375
-
376
- # If we are returning to top level, restore stack pointer
377
- # and saved registers.
378
- if @environment.parent == @top_level
379
- offset = @frame_size - @saved_registers.length * @WORDSIZE
380
- if offset > 0
381
- emit "add sp, sp, \##{offset}\n"
382
- end
383
- emit "ldmfd sp!, {#{@saved_registers.join ', '}}\n"
384
- @frame_size = 0
385
- @frame_offset = 0
386
- @saved_registers = []
387
-
388
- # If we need to emit constants, do so now
389
- unless @constants.empty?
390
- lbl = gensym
391
- goto lbl
392
- label lbl
393
- end
394
- end
395
-
396
- # Restore old value of @environment
397
- @environment = @environment.parent
398
- end
399
-
400
- # Ends a function body.
401
- def end_function
402
- if @environment == @top_level
403
- raise "Cannot end function when not in a function"
404
- end
405
-
406
- emit "# function epilogue\n"
407
- label @function_end_label
408
-
409
- destroy_frame true
410
- @frame_size = 0
411
- @frame_offset = 0
412
- @saved_registers = []
413
- emit "# end function\n\n"
414
- @environment = @top_level
415
- end
416
-
417
- # Ends a conditional.
418
- def end_if
419
- label @if_labels.pop
420
- end
421
-
422
- # Evaluate the binary operation expr and store the result in register
423
- def eval_binop expr, register
424
- op = expr[0]
425
-
426
- # Emulation for div and mod, which ARM does not have instructions for
427
- case op
428
- when :div
429
- func = :"__aeabi_idiv"
430
- import func unless @imports.has_key? func
431
- call func, expr[1], expr[2]
432
- emit "cpy #{register}, r0\n" if register != :r0
433
- return
434
- when :mod
435
- func = :"__aeabi_idivmod"
436
- import func unless @imports.has_key? func
437
- call func, expr[1], expr[2]
438
- emit "cpy #{register}, r1\n" if register != :r1
439
- return
440
- end
441
-
442
- x = load_value expr[1], :a4
443
- y = load_value expr[2], @TEMPORARY
444
-
445
- case op
446
- when :bsr
447
- emit "lsr #{register}, #{x}, #{y}\n"
448
- when :or
449
- emit "orr #{register}, #{x}, #{y}\n"
450
- when :rol
451
- emit "rsb #{y}, #{y}, #32\n"
452
- emit "ror #{register}, #{x}, #{y}\n"
453
- when :shl
454
- emit "lsl #{register}, #{x}, #{y}\n"
455
- when :shr
456
- emit "lsr #{register}, #{x}, #{y}\n"
457
- when :xor
458
- emit "eor #{register}, #{x}, #{y}\n"
459
- else
460
- emit "#{expr[0]} #{register}, #{x}, #{y}\n"
461
- end
462
- end
463
-
464
- # Evaluates the expression +expr+ and stores the result in +register+.
465
- def eval_expr expr, register
466
- if expr.length == 1
467
- # Load value
468
- load_value_into_register expr[0], register
469
- else
470
- # Evaluate expression
471
- op = expr[0]
472
- case op
473
- when :'auto-bytes'
474
- auto_bytes expr[1], register
475
- when :'auto-words'
476
- auto_words expr[1], register
477
- when :call
478
- call *expr[1..-1]
479
- emit "cpy #{register}, #{@RETURN}\n" if register != @RETURN
480
- when :'get-byte'
481
- get_byte expr[1], expr[2], register
482
- when :'get-word'
483
- get_word expr[1], expr[2], register
484
- when :not
485
- load_value_into_register expr[1], register
486
- emit "mvn #{@TEMPORARY}, #0\n"
487
- emit "eor #{register}, #{register}, #{@TEMPORARY}\n"
488
- else
489
- if binop? op
490
- eval_binop expr, register
491
- else
492
- raise "Not a magic word: #{op}"
493
- end
494
- end
495
- end
496
- end
497
-
498
- # Export symbols from the current section
499
- def export *symbols
500
- symbols.each { |sym| emit ".globl #{sym}\n" }
501
- end
502
-
503
- # Add a function to the current section
504
- def function formals, *code
505
- nlocals = count_locals code
506
- begin_function formals, nlocals
507
- code.each { |action| add section, action }
508
- end_function
509
- end
510
-
511
- # Load byte from _base_ + _offset_ into _register_
512
- def get_byte base, offset, register
513
- # If base is an integer, but offset isn't, swap them
514
- if !integer?(offset) && integer?(base)
515
- base, offset = [offset, base]
516
- end
517
-
518
- if integer? offset
519
- base_reg = load_value base
520
- if offset == 0
521
- emit "ldrb #{register}, [#{base_reg}]\n"
522
- else
523
- emit "ldrb #{register}, [#{base_reg}, \##{offset}]\n"
524
- end
525
- else
526
- base_reg = load_value base
527
- offset_reg = load_value offset, :a4
528
- emit "ldrb #{register}, [#{base_reg}, #{offset_reg}]\n"
529
- end
530
- end
531
-
532
- # Load word from _base_ + _offset_ * _@WORDSIZE_ into _register_
533
- def get_word base, offset, register
534
- if integer? offset
535
- base_reg = load_value base
536
- if offset == 0
537
- emit "ldr #{register}, [#{base_reg}]\n"
538
- else
539
- emit "ldr #{register}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
540
- end
541
- else
542
- base_reg = load_value base
543
- offset_reg = load_value offset, :a4
544
- emit "ldr #{register}, [#{base_reg}, #{offset_reg}, LSL #2]\n"
545
- end
546
- end
547
-
548
- # Test if a symbol refers to a global
549
- def global? symbol
550
- symbol?(symbol) && @environment[symbol] == nil
551
- end
552
-
553
- # Jump to a label.
554
- def goto label
555
- emit "b #{label}\n"
556
-
557
- # If we have constants that need to be emitted, do so now
558
- emit_constants
559
- end
560
-
561
- # Grows the current frame by n words, plus padding to
562
- # respect alignment rules.
563
- def grow_frame nwords
564
- increment = stack_align(nwords * @WORDSIZE)
565
- emit "sub sp, sp, \##{increment}\n"
566
- @frame_size = @frame_size + increment
567
- @frame_offset = @frame_offset + increment
568
- end
569
-
570
- # Start the false path of a conditional.
571
- def ifelse
572
- emit "# else\n"
573
- newlabel = @environment.gensym
574
- goto newlabel
575
- lbl = @if_labels.pop
576
- label lbl
577
- @if_labels.push newlabel
578
- end
579
-
580
- # Test if x is equal to y
581
- def ifeq x, y
582
- common_if :ifeq, x, y
583
- end
584
-
585
- # Test if x is greater than or equal to y
586
- def ifge x, y
587
- common_if :ifge, x, y
588
- end
589
-
590
- # Test if x is strictly greater than y
591
- def ifgt x, y
592
- common_if :ifgt, x, y
593
- end
594
-
595
- # Test if x is less than or equal to y
596
- def ifle x, y
597
- common_if :ifle, x, y
598
- end
599
-
600
- # Test if x is strictly less than y
601
- def iflt x, y
602
- common_if :iflt, x, y
603
- end
604
-
605
- # Test if x different from y
606
- def ifne x, y
607
- common_if :ifne, x, y
608
- end
609
-
610
- # Import labels into the current section
611
- def import *symbols
612
- # Record imported labels in @imports
613
- symbols.each { |sym| @imports[sym] = sym }
614
- end
615
-
616
- # Test if a value is an integer
617
- def integer? value
618
- value.kind_of? Integer
619
- end
620
-
621
- # Emit a label
622
- def label name
623
- emit "#{name}:\n"
624
- end
625
-
626
- # Introduce a new local variable
627
- def let symbol, *expr
628
- n = @environment.locals
629
- register = local_register n
630
-
631
- if register
632
- # We will use a register to store the value
633
- @environment.add_local symbol, register
634
- eval_expr expr, register
635
- else
636
- # We will use the stack to store the value
637
- offset = local_offset n
638
- @environment.add_local symbol, offset
639
- eval_expr expr, @TEMPORARY
640
- emit "str #{@TEMPORARY}, #{offset_reference offset}\n"
641
- end
642
- end
643
-
644
- # Load the value at the given address.
645
- def load_at address, register = @TEMPORARY
646
- load_value_into_register address, register
647
- emit "ldr #{register}, [#{register}]\n"
648
- register
649
- end
650
-
651
- # Load a value into a register.
652
- # Returns the name of the register.
653
- # If the value was already in a register, the name of that
654
- # register is returned.
655
- # Else, the value is loaded into a register and the name of
656
- # that register is returned. The register to use in that case
657
- # may be specified using the optional second argument.
658
- def load_value x, register = @TEMPORARY
659
- if integer? x
660
- if x >= 0 && x <= 255
661
- emit "mov #{register}, \##{x}\n"
662
- return register
663
- elsif x >= -255 && x < 0
664
- emit "mvn #{register}, \##{-(x + 1)}\n"
665
- return register
666
- else
667
- lbl = add_constant x
668
- emit "ldr #{register}, #{lbl}\n"
669
- return register
670
- end
671
- elsif symbol? x
672
- binding = @environment[x]
673
- if binding.kind_of? String
674
- # Value is already in a register. Return register name.
675
- return binding
676
- elsif binding.kind_of? Integer
677
- # Value is on the stack. Load from the stack.
678
- emit "ldr #{register}, #{offset_reference binding}\n"
679
- return register
680
- else
681
- # Assume global
682
- lbl = add_constant x
683
- emit "ldr #{register}, #{lbl}\n"
684
- return register
685
- end
686
- elsif at_expr? x
687
- load_at x[1], register
688
- else
689
- raise "Don't know how to load #{x.inspect}"
690
- end
691
- end
692
-
693
- # Load a value into a specific register
694
- def load_value_into_register x, register
695
- reg = load_value x, register
696
- if reg != register
697
- emit "cpy #{register}, #{reg}\n"
698
- end
699
- end
700
-
701
- # Returns the fp-relative reference for the nth (0-based) local.
702
- def local_offset n
703
- -@INITIAL_FRAME_SIZE - (n * @WORDSIZE)
704
- end
705
-
706
- # Return the register in which the nth local (0-based) is stored, or
707
- # nil if not stored in a register
708
- def local_register n
709
- if register_local? n
710
- n = n + number_of_register_arguments
711
- if n < 5
712
- "v#{n + 1}"
713
- else
714
- "v#{n + 2}"
715
- end
716
- else
717
- nil
718
- end
719
- end
720
-
721
- # Calculate the number of register arguments,
722
- # given the total number of arguments.
723
- def number_of_register_arguments n = @environment.args
724
- [n, @NREGISTER_ARGS].min
725
- end
726
-
727
- # Calculate the number of stack arguments,
728
- # given the total number of arguments.
729
- def number_of_stack_arguments n = @environment.args
730
- [0, n - @NREGISTER_ARGS].max
731
- end
732
-
733
- # Given an offset, returns an fp-relative reference.
734
- def offset_reference offset
735
- "[#{@FP}, \##{offset}]"
736
- end
737
-
738
- # Returns true if the nth (0-based) argument is stored in a register
739
- def register_arg? n
740
- n < @NREGISTER_ARGS
741
- end
742
-
743
- # Returns true if the nth (0-based) local is stored in a register
744
- def register_local? n
745
- (n + number_of_register_arguments) < @NREGISTER_LOCALS
746
- end
747
-
748
- # Returns from a function.
749
- #
750
- # _words_ may contain an expression to be evaluated. The result
751
- # of the evaluation is returned from the function.
752
- def ret *words
753
- emit "# return #{words.join ' '}\n"
754
- # Compute return value and store it in @RETURN
755
- eval_expr(words, @RETURN) unless words.empty?
756
- # Go to epilogue
757
- goto @function_end_label
758
- end
759
-
760
- # Set a variable to the result of evaluating an expression
761
- def set symbol, *expr
762
- if at_expr? symbol
763
- eval_expr expr, :r3
764
- register = load_value symbol[1]
765
- emit "str r3, [#{register}]\n"
766
- else
767
- x = @environment[symbol]
768
- if x == nil
769
- raise "Cannot change value of constant #{symbol}"
770
- elsif x.kind_of? String
771
- eval_expr expr, x
772
- else
773
- eval_expr expr, @TEMPORARY
774
- emit "str #{@TEMPORARY}, #{offset_reference x}\n"
775
- end
776
- end
777
- end
778
-
779
- # Set the byte at _base_ + _offset_ to _value_
780
- def set_byte base, offset, value
781
- emit "# set-byte #{base} #{offset} #{value}\n"
782
- # If base is an integer, but offset isn't, swap them
783
- if !integer?(offset) && integer?(base)
784
- base, offset = [offset, base]
785
- end
786
-
787
- if integer? offset
788
- base_reg = load_value base, :a4
789
- load_value_into_register value, @TEMPORARY
790
- if offset == 0
791
- emit "strb #{@TEMPORARY}, [#{base_reg}]\n"
792
- else
793
- emit "strb #{@TEMPORARY}, [#{base_reg}, \##{offset}]\n"
794
- end
795
- else
796
- eval_binop [:add, base, offset], :a4
797
- load_value_into_register value, @TEMPORARY
798
- emit "strb #{@TEMPORARY}, [a4]\n"
799
- end
800
- end
801
-
802
- # Set the word at _base_ + _offset_ * +@WORDSIZE+ to _value_
803
- def set_word base, offset, value
804
- emit "# set-word #{base} #{offset} #{value}\n"
805
- # If base is an integer, but offset isn't, swap them
806
- if !integer?(offset) && integer?(base)
807
- base, offset = [offset, base]
808
- end
809
-
810
- if integer? offset
811
- base_reg = load_value base, :a4
812
- load_value_into_register value, @TEMPORARY
813
- if offset == 0
814
- emit "str #{@TEMPORARY}, [#{base_reg}]\n"
815
- else
816
- emit "str #{@TEMPORARY}, [#{base_reg}, \##{offset * @WORDSIZE}]\n"
817
- end
818
- else
819
- load_value_into_register base, :a4
820
- load_value_into_register offset, @TEMPORARY
821
- emit "add a4, a4, #{@TEMPORARY}, LSL #2\n"
822
- load_value_into_register value, @TEMPORARY
823
- emit "str #{@TEMPORARY}, [a4]\n"
824
- end
825
- end
826
-
827
- # Given n, returns the nearest multiple of @STACK_ALIGNMENT
828
- # that is >= n.
829
- def stack_align n
830
- (n + @STACK_ALIGNMENT - 1) / @STACK_ALIGNMENT * @STACK_ALIGNMENT
831
- end
832
-
833
- # Define a string with the given value
834
- def string value
835
- code = ''
836
- value.each_byte do |b|
837
- if b == 92
838
- code << "\\\\"
839
- elsif b >= 32 && b < 127 && b != 34
840
- code << b.chr
841
- else
842
- code << sprintf("\\%03o", b)
843
- end
844
- end
845
- emit ".ascii \"#{code}\"\n"
846
- end
847
-
848
- # Test if a value is a symbol
849
- def symbol? value
850
- value.kind_of? Symbol
851
- end
852
-
853
- # Test if op is a symmetric binary operation (i.e. it will yield the
854
- # same result if the order of its source operands is changed).
855
- def symmetric_binop? op
856
- [:add, :and, :mul, :or, :xor].member? op
857
- end
858
-
859
- # Call a function, re-using the current call frame if possible.
860
- def tail_call func, *args
861
- emit "# tail-call #{func} #{args.join ' '}\n"
862
-
863
- # Compute number of stack arguments
864
- nstackargs = number_of_stack_arguments args.length
865
- # If we need more stack arguments than we have now,
866
- # perform a normal call and return
867
- if nstackargs > number_of_stack_arguments(@environment.args)
868
- emit "# Not enough space for proper tail call; using regular call\n"
869
- ret :call, func, *args
870
- end
871
-
872
- # We will assign arguments from left to right.
873
- # Find places that we will overwrite before we read them,
874
- # and store their values in some newly allocated stack space.
875
- old_frame_offset = @frame_offset
876
- old_frame_size = @frame_size
877
- overwritten = {}
878
- (@NREGISTER_ARGS...args.length).each do |i|
879
- arg = args[i]
880
- arg = arg[1] if at_expr? arg
881
- if symbol?(arg)
882
- binding = @environment[arg]
883
- if binding[0] == :arg && binding[1] >= @NREGISTER_ARGS &&
884
- binding[1] < i
885
- # Argument i is a stack argument, but the value we will assign
886
- # it is a stack argument that comes before it, so we will
887
- # have overwritten it by the time we get to it.
888
- overwritten[arg] = nil
889
- end
890
- end
891
- end
892
-
893
- unless overwritten.empty?
894
- # Allocate space for arguments to be saved
895
- grow_frame overwritten.length
896
- # Save values
897
- offset = 0
898
- overwritten.each_key do |key|
899
- reg = load_value key
900
- emit "str #{reg}, [sp, \##{offset}]\n"
901
- overwritten[key] = offset
902
- offset = offset + @WORDSIZE
903
- end
904
- end
905
-
906
- # Assign arguments
907
- args.each_index do |i|
908
- arg = args[i]
909
- if register_arg? i
910
- load_value_into_register arg, "a#{i + 1}"
911
- else
912
- # Test if this is a value we saved
913
- sym = at_expr?(arg) ? arg[1] : arg
914
- saved = overwritten[sym]
915
- if saved
916
- # Saved value, load from stack
917
- reg = @TEMPORARY
918
- emit "ldr #{reg}, [sp, \##{saved}]\n"
919
- else
920
- # Regular value, use load_value
921
- reg = load_value arg
922
- end
923
- emit "str #{reg}, #{arg_reference i}\n"
924
- end
925
- end
926
-
927
- # Load address of function to be called into @TEMPORARY
928
- load_value_into_register func, @TEMPORARY
929
-
930
- # Destroy current activation frame and enter func
931
- destroy_frame false
932
- emit "bx #{@TEMPORARY}\n"
933
- emit_constants
934
- end
935
-
936
- # Define a word with the given value
937
- def word value
938
- emit ".int #{value}\n"
939
- end
940
-
941
- # Write generated code to the given IO object.
942
- def write io
943
- @sections.each do |section,code|
944
- unless code.empty?
945
- io.puts ".section #{section.to_s}"
946
- io.puts code
947
- io.puts
948
- end
949
- end
950
- end
951
- end
952
-
953
- # Register class for little endian ARM
954
- Voodoo::CodeGenerator.register_generator ARMGasGenerator,
955
- :architecture => :arm,
956
- :format => :gas
957
- end