Open zacky1972 opened 5 years ago
I'll change the specification of ZEAM IR according to IR or ASTs using tuples and lists. However, it's troublesome so I'll implement #71, change the specification of ZEAM IR, and implement #70.
@zacky1972 I designed ZEAM IR using Elixir Map .
original code:
const int fail = 0;
#define loop_vectorize_width 4
static ERL_NIF_TERM
map_plus_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
size_t vec_l;
double *vec_double;
if (__builtin_expect((enif_get_double_vec_from_list(env, argv[0], &vec_double, &vec_l) == fail), false)) {
return enif_make_badarg(env);
}
#pragma clang loop vectorize_width(loop_vectorize_width)
for(size_t i = 0; i < vec_l; i++) {
vec_double[i] = vec_double[i] + 1;
}
return enif_make_list_from_double_vec(env, vec_double, vec_l);
}
ZEAM IR:
global_vars = %{
fail: {:fail, [type: ["const", "int"]], 0}
},
macros = %{
loop_vectorization: 4
}
nif_vars = %{
env: {:env, [type: "ERL_NIF_ENV"], nil},
argc: {:argc, [type: "int"], nil},
argv: {:argv, [type: ["const", "ERL_NIF_TERM*"]], nil}
}
%{
fucntions: "map_plus_1",
arguments: [
nif_vars[env],
nif_vars[argc],
nif_vars[argv]
],
return_type: static_ERL_NIF_TERM
do: %{
vars: %{
vec_l: {:vec_l, [type: "size_t"], nil},
vec_double: {:vec_double, [type: "double*"], nil}
},
fucntion_calls: %{
enif_get_double_vec_from_list_1: %{
function: "enif_get_double_vec_from_list",
arguments: [
nif_vars[env],
nif_vars[argv, 0],
vars[vec_double],
vars[vec_l]
],
return_type: "int",
},
enif_make_list_from_double_vec_1: %{
funtion: "enif_make_list_from_double_vec",
arguments: arguments: [
nif_vars[env],
vars[vec_double],
vars[vec_l]
]
}
},
controll: %{
if1: %{
expect: false,
cond: %{
function: "==",
arguments: [
fail,
function_calls[:enif_get_double_vec_from_list_1]
],
return_type: :bool
},
do: %{
return: %{
functions: enif_make_bad_arg,
arguments: nif_vars[env]
}
}
},
for1: %{
options: %{
compiler: "clang",
object: "loop",
vectorize_width: loop_vectorize_width
},
increment: 1,
count: vars[vec_l],
do: %{
fucntion: "=",
arguments: [ vars[vec_double], %{
fucntion: "+",
arguments: [ vars[vec_double], 1],
return_type: "double"
}],
return_type: "double"
}
},
return: function_calls[:enif_make_list_from_double_vec_1]
},
flow: [ if1 |> for1 |> return ]
}
}
Single-map version:
%{
global_vars: %{
fail: {:fail, [type: ["const", "int"]], 0}
},
macros: %{
loop_vectorization: 4
},
nif_vars: %{
env: {:env, [type: "ERL_NIF_ENV"], nil},
argc: {:argc, [type: "int"], nil},
argv: {:argv, [type: ["const", "ERL_NIF_TERM*"]], nil}
},
func_map_plus_1: %{
fucntions: "map_plus_1",
arguments: [
"nif_vars[env]",
"nif_vars[argc]",
"nif_vars[argv]"
],
return_type: :static_ERL_NIF_TERM,
do: %{
vars: %{
vec_l: {:vec_l, [type: "size_t"], nil},
vec_double: {:vec_double, [type: "double*"], nil}
},
fucntion_calls: %{
enif_get_double_vec_from_list_1: %{
function: "enif_get_double_vec_from_list",
arguments: [
"nif_vars[env]",
"nif_vars[argv, 0]",
"vars[vec_double]",
"vars[vec_l]"
],
return_type: "int",
},
enif_make_list_from_double_vec_1: %{
funtion: "enif_make_list_from_double_vec",
arguments: [
"nif_vars[env]",
"vars[vec_double]",
"vars[vec_l]"
]
}
},
controll: %{
if1: %{
expect: false,
cond: %{
function: "==",
arguments: [
"fail",
"function_calls[enif_get_double_vec_from_list_1]"
],
return_type: :bool
},
do: %{
return: %{
functions: "enif_make_bad_arg",
arguments: "nif_vars[env]"
}
}
},
for1: %{
options: %{
compiler: "clang",
object: "loop",
vectorize_width: "loop_vectorize_width"
},
increment: 1,
count: "vars[vec_l]",
do: %{
fucntion: "=",
arguments: [ "vars[vec_double]", %{
fucntion: "+",
arguments: [ "vars[vec_double]", 1],
return_type: "double"
}],
return_type: "double"
}
},
return: "function_calls[enif_make_list_from_double_vec_1]"
},
flow: [ "if1 |> for1 |> return" ]
}
}
}
It needs to replace some maps into keyword lists because the order of them is important.
%{
global_vars: [
fail: {:fail, [type: ["const", "int"]], 0}
],
macros: [
loop_vectorization: 4
],
nif_vars: %{
env: {:env, [type: "ERL_NIF_ENV"], nil},
argc: {:argc, [type: "int"], nil},
argv: {:argv, [type: ["const", "ERL_NIF_TERM*"]], nil}
},
func_map_plus_1: %{
fucntions: "map_plus_1",
arguments: [
"nif_vars[env]",
"nif_vars[argc]",
"nif_vars[argv]"
],
return_type: :static_ERL_NIF_TERM,
do: %{
vars: %{
vec_l: {:vec_l, [type: "size_t"], nil},
vec_double: {:vec_double, [type: "double*"], nil}
},
fucntion_calls: %{
enif_get_double_vec_from_list_1: %{
function: "enif_get_double_vec_from_list",
arguments: [
"nif_vars[env]",
"nif_vars[argv, 0]",
"vars[vec_double]",
"vars[vec_l]"
],
return_type: "int",
},
enif_make_list_from_double_vec_1: %{
funtion: "enif_make_list_from_double_vec",
arguments: [
"nif_vars[env]",
"vars[vec_double]",
"vars[vec_l]"
]
}
},
controll: %{
if1: %{
expect: false,
cond: %{
function: "==",
arguments: [
"fail",
"function_calls[enif_get_double_vec_from_list_1]"
],
return_type: :bool
},
do: %{
return: %{
functions: "enif_make_bad_arg",
arguments: "nif_vars[env]"
}
}
},
for1: %{
options: %{
compiler: "clang",
object: "loop",
vectorize_width: "loop_vectorize_width"
},
increment: 1,
count: "vars[vec_l]",
do: %{
fucntion: "=",
arguments: [ "vars[vec_double]", %{
fucntion: "+",
arguments: [ "vars[vec_double]", 1],
return_type: "double"
}],
return_type: "double"
}
},
return: "function_calls[enif_make_list_from_double_vec_1]"
},
flow: {:">|", [], [:if1, {:">|", [], [:for1, :return]}]}
}
}
}
Suppose the following ZEAM IR is given:
It will be converted into the following C code: