exprtree* make_for (scanner_ident_t *counter_name_ident, exprtree *counter_init, exprtree *start, exprtree *end, exprtree *body) { scanner_region_t region = counter_name_ident->region; if (start->result.length != 1 || end->result.length != 1 || start->result.number != end->result.number) { sprintf(error_string, _("The start and end of a for loop interval must be tuples of the same tag and length 1.")); error_region = region; JUMP(1); } else { char end_name_buf[MAX_GENSYM_LEN]; char *end_name = gensym(end_name_buf); scanner_ident_t *end_name_ident = scanner_make_ident(scanner_null_region, end_name); exprtree *end_init = make_assignment(end_name_ident, end); exprtree *init = make_sequence(counter_init, end_init); exprtree *inc = make_assignment(counter_name_ident, make_function_from_string("__add", exprlist_append(make_var(counter_name_ident), make_int_number(1, scanner_null_region)), scanner_null_region)); exprtree *invariant = make_function_from_string("__lessequal", exprlist_append(make_var(counter_name_ident), make_var(end_name_ident)), scanner_null_region); free(end_name_ident); return make_sequence(init, make_while(invariant, make_sequence(body, inc))); } }
/** * For binary operations, there are two cases that need special treatment: * a = k # a * a = b # a * If # is commutable then these can be reversed. Otherwise they will be * translated to t = a; a = k/b # t. * After the first phase there are three cases that are already in i386 form: * a = a # a * a = a # b * a = a # k * There are five cases that need processing: * a = k # k (should really be handled by constant optimisation) * a = k # b * a = b # k * a = b # b * a = b # c * All are translated to a = (k/b); a = a # (k/b/c) */ static int i386ify_binary_operation(MODULE *module, FUNCTION *func, NODE *vertex) { GRAPH *graph = func->graph; VARIABLE *dest = tree_get_child(vertex, 0); EXPRESSION *expr = tree_get_child(vertex, 1); EXPRESSION *arg0 = tree_get_child(expr, 0); EXPRESSION *arg1 = tree_get_child(expr, 1); int source_line = CAST_TO_AST(vertex)->source_line; /* First deal with special cases, where the first argument is not the destination but the second argument is. */ if (!is_same_var(CAST_TO_EXPRESSION(dest), arg0) && is_same_var(CAST_TO_EXPRESSION(dest), arg1)) { if (is_commutable_op(expr)) { tree_get_child(expr, 0) = arg1; tree_get_child(expr, 1) = arg0; } else { TYPE *new_temp_type = arg1->type; EXPRESSION *new_temp = make_new_temp(module, func, new_temp_type, source_line); STATEMENT *new_assign = make_assignment(new_temp, arg1, source_line); tree_get_child(expr, 1) = tree_copy(new_temp); add_vertex(graph, CAST_TO_NODE(new_assign)); replace_backward(graph, vertex, CAST_TO_NODE(new_assign), 0); add_edge(graph, CAST_TO_NODE(new_assign), vertex, 0); } /* Reset these as the above operations may have changed them, */ arg0 = tree_get_child(expr, 0); arg1 = tree_get_child(expr, 1); } /* If instruction is already in i386 form, we don't need to process it. */ if (is_same_var(CAST_TO_EXPRESSION(dest), arg0)) return 0; /* Otherwise, translate a = b # c to a = b; a = a # c. */ STATEMENT *new_assign = make_assignment(CAST_TO_EXPRESSION(tree_copy(dest)), arg0, source_line); tree_get_child(expr, 0) = tree_copy(dest); add_vertex(graph, CAST_TO_NODE(new_assign)); replace_backward(graph, vertex, CAST_TO_NODE(new_assign), 0); add_edge(graph, CAST_TO_NODE(new_assign), vertex, 0); return 1; }
EXPRESSION *atomise_expression(MODULE *module, FUNCTION *func, BLOCK *block, EXPRESSION *expr, STATEMENT *before) { if (is_atomic(expr)) return expr; if (tree_is_type(expr, EXPR_TUPLE)) { EXPRESSION *new_temp = make_empty_tuple(CAST_TO_AST(expr)->source_line); int i; for (i = 0; i < tree_num_children(expr); i++) tree_add_child(new_temp, atomise_expression(module, func, block, tree_get_child(expr, i), before)); return new_temp; } EXPRESSION *new_temp = make_new_temp(module, func, expr->type, CAST_TO_AST(expr)->source_line); STATEMENT *new_assign = make_assignment(new_temp, expr, CAST_TO_AST(expr)->source_line); if (has_graph(func)) { GRAPH *graph = func->graph; add_vertex(graph, CAST_TO_NODE(new_assign)); inject_before(graph, CAST_TO_NODE(new_assign), CAST_TO_NODE(before), 0); } else tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); return new_temp; }
static STATEMENT *reduce_statement(MODULE *module, FUNCTION *func, BLOCK *block, STATEMENT *stmt) { if (stmt == NULL) return stmt; if (tree_is_type(stmt, STMT_ASSIGN)) { EXPRESSION *expr = tree_get_child(stmt, 1); expr = simplify_expression(module, func, block, expr, stmt); tree_get_child(stmt, 1) = expr; } else if (tree_is_type(stmt, STMT_IF)) { EXPRESSION *cond = tree_get_child(stmt, 0); cond = simplify_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; reduce_block(module, func, tree_get_child(stmt, 1)); reduce_block(module, func, tree_get_child(stmt, 2)); } else if (tree_is_type(stmt, STMT_WHILE)) { EXPRESSION *cond = tree_get_child(stmt, 0); BLOCK *body = tree_get_child(stmt, 1); if (!is_atomic(cond)) { EXPRESSION *old_cond = cond; cond = atomise_expression(module, func, block, cond, stmt); tree_get_child(stmt, 0) = cond; STATEMENT *new_assign = make_assignment(cond, CAST_TO_EXPRESSION(tree_copy(old_cond)), CAST_TO_AST(cond)->source_line); tree_add_child(body, new_assign); } reduce_block(module, func, body); } else if (tree_is_type(stmt, STMT_RETURN)) { EXPRESSION *expr = tree_get_child(stmt, 0); expr = atomise_expression(module, func, block, expr, stmt); tree_get_child(stmt, 0) = expr; } else if (tree_is_type(stmt, STMT_RESTART)) { /* Do nothing. */ } else error("Not sure how to reduce statement of type %d\n", tree_type(stmt)); return stmt; }
/** * For unary operations, one case is already in i386 form: * a = #a * There are two cases which need processing: * a = #k (should really be handled by constant optimisation) * a = #b * These are both translated to a = k/b; a = #a */ static int i386ify_unary_operation(MODULE *module, FUNCTION *func, NODE *vertex) { GRAPH *graph = func->graph; VARIABLE *dest = tree_get_child(vertex, 0); EXPRESSION *expr = tree_get_child(vertex, 1); EXPRESSION *arg0 = tree_get_child(expr, 0); if (is_same_var(CAST_TO_EXPRESSION(dest), arg0)) return 0; STATEMENT *new_assign = make_assignment(CAST_TO_EXPRESSION(tree_copy(dest)), arg0, CAST_TO_AST(vertex)->source_line); tree_get_child(expr, 0) = tree_copy(dest); add_vertex(graph, CAST_TO_NODE(new_assign)); replace_backward(graph, vertex, CAST_TO_NODE(new_assign), 0); add_edge(graph, CAST_TO_NODE(new_assign), vertex, 0); return 1; }
static int i386ify_assignment(MODULE *module, FUNCTION *func, NODE *vertex) { int changed = 0; GRAPH *graph = func->graph; VARIABLE *dest = tree_get_child(vertex, 0); EXPRESSION *expr = tree_get_child(vertex, 1); int source_line = CAST_TO_AST(vertex)->source_line; if (is_unary_op(expr)) changed |= i386ify_unary_operation(module, func, vertex); if (is_binary_op(expr)) changed |= i386ify_binary_operation(module, func, vertex); /* Expand tuple assignments. */ if (tree_is_type(dest, EXPR_TUPLE) && tree_num_children(dest) >= 1) { int i; NODE *last = NULL; if (tree_num_children(dest) != tree_num_children(expr)) error("Source and destinations have different cardinality!"); for (i = 0; i < tree_num_children(dest); i++) { VARIABLE *dest2 = tree_get_child(dest, i); VARIABLE *src2 = tree_get_child(expr, i); STATEMENT *new_assign = make_assignment(CAST_TO_EXPRESSION(dest2), CAST_TO_EXPRESSION(src2), source_line); add_vertex(graph, CAST_TO_NODE(new_assign)); if (last) add_edge(graph, last, CAST_TO_NODE(new_assign), 0); else replace_backward(graph, vertex, CAST_TO_NODE(new_assign), 0); last = CAST_TO_NODE(new_assign); } replace_forward(graph, vertex, last, 0); remove_vertex(graph, vertex); changed |= 1; } return changed; }
static EXPRESSION *simplify_expression(MODULE *module, FUNCTION *func, BLOCK *block, EXPRESSION *expr, STATEMENT *before) { int i; int source_line = CAST_TO_AST(expr)->source_line; if (!has_graph(func) && is_short_circuit(expr)) { TYPE *new_temp_type = CAST_TO_EXPRESSION(tree_get_child(expr, 0))->type; EXPRESSION *new_temp = make_new_temp(module, func, new_temp_type, source_line); STATEMENT *new_assign = make_assignment(new_temp, tree_get_child(expr, 0), source_line); tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); STATEMENT *new_assign2 = make_assignment(new_temp, tree_get_child(expr, 1), source_line); EXPRESSION *new_cond = new_temp; if (tree_is_type(expr, EXPR_OR)) new_cond = make_unary_expression(EXPR_NOT, new_cond, source_line); STATEMENT *new_if = make_if(new_cond, make_block(NULL, new_assign2, 0), NULL, 0); tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_if), CAST_TO_NODE(before)); return new_temp; } if (has_graph(func) && is_short_circuit(expr)) { GRAPH *graph = func->graph; EXPRESSION *sub0 = tree_get_child(expr, 0); EXPRESSION *sub1 = tree_get_child(expr, 1); STATEMENT *new_test = make_test(sub0, source_line); EDGE_TYPE inner_type = tree_is_type(expr, EXPR_OR) ? EDGE_NO : EDGE_YES; EDGE_TYPE outer_type = tree_is_type(expr, EXPR_OR) ? EDGE_YES : EDGE_NO; add_vertex(graph, CAST_TO_NODE(new_test)); HASH *subhash = get_from_hash(graph->forward, before, sizeof(void *)); HASH_ITERATOR iter; for (hash_iterator(subhash, &iter); hash_iterator_valid(&iter); hash_iterator_next(&iter)) { EDGE_TYPE type = (EDGE_TYPE) iter.entry->data; if (outer_type & type) add_edge(graph, CAST_TO_NODE(new_test), iter.entry->key, type); if (inner_type & type) inner_type = type; } inject_before(graph, CAST_TO_NODE(new_test), CAST_TO_NODE(before), inner_type); return sub1; } if (is_simple(expr)) return expr; if (tree_is_type(expr, EXPR_CALL)) { EXPRESSION *args = CAST_TO_EXPRESSION(tree_get_child(expr, 1)); args = atomise_expression(module, func, block, args, before); tree_get_child(expr, 1) = args; return expr; } for (i = 0; i < tree_num_children(expr); i++) { EXPRESSION *child = tree_get_child(expr, i); if (!is_atomic(child)) { TYPE *new_temp_type = CAST_TO_EXPRESSION(child)->type; EXPRESSION *new_temp = make_new_temp(module, func, new_temp_type, CAST_TO_AST(child)->source_line); STATEMENT *new_assign = make_assignment(new_temp, child, CAST_TO_AST(child)->source_line); if (has_graph(func)) { GRAPH *graph = func->graph; add_vertex(graph, CAST_TO_NODE(new_assign)); inject_before(graph, CAST_TO_NODE(new_assign), CAST_TO_NODE(before), 0); } else tree_add_before(CAST_TO_NODE(block), CAST_TO_NODE(new_assign), CAST_TO_NODE(before)); tree_get_child(expr, i) = new_temp; } } return expr; }