1 require 'voodoo/generators/common_code_generator'
4 # = i386 NASM Code Generator
6 # The i386 NASM code generator generates i386 assembly code for use with
7 # the {Netwide Assembler}[http://www.nasm.us/].
11 # Call frames have the following layout:
23 class I386NasmGenerator < NasmGenerator
27 # Number of bytes in a word
29 # Word name in NASM lingo
31 # Default alignment for code
33 # Default alignment for data
34 @DATA_ALIGNMENT = @WORDSIZE
35 # Default alignment for functions
36 @FUNCTION_ALIGNMENT = 16
37 # Register used for return values
39 # Register used as scratch register
54 emit "; call #{func} #{args.join ' '}\n"
55 revargs = args.reverse
56 revargs.each { |arg| push arg }
57 use_value "call", func
59 emit "add esp, #{WORDSIZE * args.length}\n"
63 # Emit function prologue.
64 def emit_function_prologue formals = []
65 emit "push ebp\nmov ebp, esp\n"
68 # Load the value of the nth argument
69 def load_arg n, reg = @SCRATCH_REG
70 "[ebp + #{n * @WORDSIZE + 8}]"
73 # Load the value of the nth local variable
74 def load_local n, reg = @SCRATCH_REG
75 "[ebp - #{(n + 1) * @WORDSIZE}]"
78 # Introduce a new local variable
79 def let symbol, *words
80 emit "; let #{symbol} #{words.join ' '}\n"
81 @environment.add_local symbol
86 # Push a word on the stack
88 #emit "; push #{value}\n"
89 value_ref = load_value value, "ebx"
90 emit "push dword #{value_ref}\n"
93 # Call a function, re-using the current call fram if possible
94 def tail_call fun, *args
95 emit "; tail-call #{fun} #{args.join ' '}\n"
96 if args.length > @environment.args
97 # Not enough space to do proper tail call; do normal call instead
98 emit "; not enough space for proper tail call; changed to regular call\n"
101 # Any value in the current frame that is passed to the called
102 # function must be copied to a local variable if it would otherwise
103 # be overwritten before it is used
106 arg = (i >= 0) ? args[i] : fun
109 x = @environment[arg]
110 if x && x[0] == :arg && x[1] < args.length && x[1] > i &&
111 (i >= 0 || fun != args[x[1]])
113 newsym = @environment.gensym
128 (args.length - 1 .. 0).each do |i|
131 value_ref = load_value arg, "eax"
132 newarg_ref = "[ebp + #{(i + 2) * WORDSIZE}]"
133 # Elide code if source is same as destination
134 unless value_ref == newarg_ref
135 emit "mov [ebp + #{(i + 2) * WORDSIZE}], #{value_ref}\n"
141 emit "mov esp, ebp\npop ebp\n"
146 def use_value operation, value
147 value_ref = load_value value, "eax"
148 emit "#{operation} #{value_ref}\n"
151 # Define a machine word with the given value
159 Voodoo::CodeGenerator.register_generator I386NasmGenerator,
160 :architecture => :i386,