'generate parfor from arrayexpr node, which is essentially a
map with recursive tree.'

def _arrayexpr_to_parfor(self, lhs, arrayexpr, avail_vars):

    scope = lhs.scope
    loc = lhs.loc
    expr = arrayexpr.expr
    arr_typ = self.typemap[lhs.name]
    el_typ = arr_typ.dtype
    loopnests = []
    size_vars = []
    index_vars = []
    for this_dim in range(arr_typ.ndim):
        corr = self.array_analysis.array_shape_classes[lhs.name][this_dim]
        size_var = self.array_analysis.array_size_vars[lhs.name][this_dim]
        size_vars.append(size_var)
        index_var = ir.Var(scope, mk_unique_var('parfor_index'), loc)
        index_vars.append(index_var)
        self.typemap[index_var.name] = types.intp
        loopnests.append(LoopNest(index_var, 0, size_var, 1, corr))
    init_block = ir.Block(scope, loc)
    init_block.body = mk_alloc(self.typemap, self.calltypes, lhs, tuple(size_vars), el_typ, scope, loc)
    body_label = next_label()
    body_block = ir.Block(scope, loc)
    expr_out_var = ir.Var(scope, mk_unique_var('$expr_out_var'), loc)
    self.typemap[expr_out_var.name] = el_typ
    (index_var, index_var_typ) = self._make_index_var(scope, index_vars, body_block)
    body_block.body.extend(_arrayexpr_tree_to_ir(self.typemap, self.calltypes, expr_out_var, expr, index_var, index_vars, self.array_analysis.array_shape_classes, avail_vars))
    parfor = Parfor(loopnests, init_block, {}, loc, self.array_analysis, index_var)
    setitem_node = ir.SetItem(lhs, index_var, expr_out_var, loc)
    self.calltypes[setitem_node] = signature(types.none, self.typemap[lhs.name], index_var_typ, el_typ)
    body_block.body.append(setitem_node)
    parfor.loop_body = {body_label: body_block}
    if (config.DEBUG_ARRAY_OPT == 1):
        print('generated    parfor    for    arrayexpr:')
        parfor.dump()
    return parfor
