#ruby <<END
V = :value
L = :label_ptr
B = :label
N = :nint
T = :type_t
_ = :void
def incoming_args(arg_types)
num_args = arg_types.length
return (1..num_args).map { |n| ", VALUE arg#{n}" }.join
end
def declaration(name, type)
case type
when V then return "jit_value_t #{name};"
when L then return "jit_label_t * #{name};"
when B then return "jit_label_t * #{name};"
when N then return "jit_nint #{name};"
when T then return "jit_type_t #{name};"
when :void then nil
else raise "Invalid type #{type}"
end
end
def write_declaration(name, type, indent)
d = declaration(name, type)
if d then
puts "#{' '*indent}#{d}"
end
end
def ruby_type(type)
case type
when V then return "rb_cValue"
when L then return "rb_cLabel"
when B then return "rb_cLabel"
when N then return "rb_cFixnum"
when T then return "rb_cType"
else raise "Invalid type #{type}"
end
end
def jit_type(type)
case type
when V then return "struct _jit_value"
when L then return "jit_label_t"
when B then return "jit_label_t"
when T then return "struct _jit_type"
else raise "Invalid type #{type}"
end
end
def get_value(type, arg, j_arg)
case type
when N then
return "#{j_arg} = NUM2INT(#{arg})"
else
return "Data_Get_Struct(#{arg}, #{jit_type(type)}, #{j_arg})"
end
end
def jit_insn_args(arg_types)
num_args = arg_types.length
arg_list = (1..num_args).map do |n|
case arg_types[n-1]
when B then ", *j_arg#{n}"
else ", j_arg#{n}"
end
end
return arg_list.join
end
def write_insn(name, retval_type, arg_types)
num_args = arg_types.length
an = [?a, ?e, ?i, ?o, ?u].include?(name[0])
puts "/* Generate a#{an} #{name} instruction (see the libjit documentation for more"
puts " * details. */"
puts "static VALUE function_insn_#{name}(VALUE self#{incoming_args(arg_types)})"
puts "{"
puts " jit_function_t function;"
write_declaration('retval', retval_type, 2)
arg_types.each_with_index do |type, n|
write_declaration("j_arg#{n+1}", type, 2)
end
puts
arg_types.each_with_index do |type, n|
puts " check_type(\"arg#{n+1}\", #{ruby_type(type)}, arg#{n+1});"
end
puts
puts " Data_Get_Struct(self, struct _jit_function, function);"
arg_types.each_with_index do |type, n|
puts " " + get_value(type, "arg#{n+1}", "j_arg#{n+1}") + ";"
end
puts
if retval_type == V then
puts " retval = jit_insn_#{name}(function#{jit_insn_args(arg_types)});"
puts " return Data_Wrap_Struct(rb_cValue, 0, 0, retval);"
elsif retval_type == :void then
puts " jit_insn_#{name}(function#{jit_insn_args(arg_types)});"
puts " return Qnil;"
else
raise "Invalid retval type #{retval_type}"
end
puts "}"
end
insns = [
[ 'load' , V, V ] ,
[ 'store' , _, V, V ] ,
[ 'dup' , V, V ] ,
[ 'add' , V, V, V ] ,
[ 'add_ovf' , V, V, V ] ,
[ 'sub' , V, V, V ] ,
[ 'sub_ovf' , V, V, V ] ,
[ 'mul' , V, V, V ] ,
[ 'mul_ovf' , V, V, V ] ,
[ 'div' , V, V, V ] ,
[ 'rem' , V, V, V ] ,
[ 'rem_ieee' , V, V, V ] ,
[ 'neg' , V, V ] ,
[ 'and' , V, V, V ] ,
[ 'or' , V, V, V ] ,
[ 'xor' , V, V, V ] ,
[ 'not' , V, V ] ,
[ 'shl' , V, V, V ] ,
[ 'shr' , V, V, V ] ,
[ 'ushr' , V, V, V ] ,
[ 'sshr' , V, V, V ] ,
[ 'eq' , V, V, V ] ,
[ 'ne' , V, V, V ] ,
[ 'lt' , V, V, V ] ,
[ 'le' , V, V, V ] ,
[ 'gt' , V, V, V ] ,
[ 'ge' , V, V, V ] ,
[ 'cmpl' , V, V, V ] ,
[ 'cmpg' , V, V, V ] ,
[ 'to_bool' , V, V ] ,
[ 'to_not_bool' , V, V ] ,
[ 'acos' , V, V ] ,
[ 'asin' , V, V ] ,
[ 'atan' , V, V ] ,
[ 'atan2' , V, V, V ] ,
[ 'ceil' , V, V ] ,
[ 'cos' , V, V ] ,
[ 'cosh' , V, V ] ,
[ 'exp' , V, V ] ,
[ 'floor' , V, V ] ,
[ 'log' , V, V ] ,
[ 'log10' , V, V ] ,
[ 'pow' , V, V, V ] ,
[ 'rint' , V, V ] ,
[ 'round' , V, V ] ,
[ 'sin' , V, V ] ,
[ 'sinh' , V, V ] ,
[ 'sqrt' , V, V ] ,
[ 'tan' , V, V ] ,
[ 'tanh' , V, V ] ,
[ 'is_nan' , V, V ] ,
[ 'is_finite' , V, V ] ,
[ 'is_inf' , V, V ] ,
[ 'abs' , V, V ] ,
[ 'min' , V, V, V ] ,
[ 'max' , V, V, V ] ,
[ 'sign' , V, V ] ,
[ 'branch' , _, L ] ,
[ 'branch_if' , _, V, L ] ,
[ 'branch_if_not' , _, V, L ] ,
[ 'label' , _, L ] ,
[ 'address_of' , V, V ] ,
[ 'address_of_label' , V, L ] ,
[ 'store_relative' , _, V, N, V ] ,
[ 'load_relative' , V, V, N, T ] ,
[ 'add_relative' , V ,V, N ] ,
[ 'memcpy' , _, V, V, V ] ,
[ 'memmove' , _, V, V, V ] ,
[ 'memset' , _, V, V, V ] ,
[ 'alloca' , V, V ] ,
[ 'load_elem' , V, V, V, T ] ,
[ 'store_elem' , _, V, V, V ] ,
[ 'move_blocks_to_end' , _, B, B ] ,
[ 'move_blocks_to_start' , _, B, B ] ,
[ 'push' , _, V ] ,
[ 'push_ptr' , _, V, T ] ,
[ 'pop_stack' , _, N ] ,
]
insns.each do |name, retval_type, *arg_types|
write_insn(name, retval_type, arg_types)
puts
end
puts "static void init_insns()"
puts "{"
insns.each do |name, retval_type, *arg_types|
num_args = arg_types.length
puts " rb_define_method(rb_cFunction, \"insn_#{name}\", function_insn_#{name}, #{num_args});"
end
puts "}"
END