## simplify-assign-ops.pkg
# Compiled by:
#
src/lib/c-kit/src/ast/ast.sublib# Main Function: simplifyAssignOp { lookUpAid, getCoreType, wrapEXPR, getLoc, top_level, bindSym }
# (processBinop, opn, { preOp }, expr1, expr2)
#
# processBinop -- function to call for typechecking and building binop expressions
# opn -- an raw_syntax binary operation
# { preOp } -- TRUE if operation should be performed before result
# e.g. ++x becomes simplifyAssignOp(+, { preOp=TRUE }, x, 1)
# e.g. x+=e becomes simplifyAssignOp(+, { preOp=TRUE }, x, e)
# -- FALSE if operation should be done after result
# e.g. x++ becomes simplifyAssignOp(+, { preOp=FALSE }, x, 1)
# expr1, expr2 -- expressions
# function returns an equivalent simplified expr.
#
# Issues:
# 1. copying must maintain unique pid invariant.
# 2. copying of rvals (simpleDup) versus lvals (duplicateLval) versus (duplicateRval)
# 3. must be careful with types of new variables (bug #1)
# e.g.
# struct { int count[3]; } *p;
# ....
# p->count[i]++;
# generates
# int tmp1[3], tmp2; tmp1=p->count, tmp2=tmp1[i], tmp1[i]=tmp2, tmp2;
#
# AUTHORS: Nevin Heintze (nch@research.bell-labs.com)
#
# TBD: More testing...
package simplify_assign_ops {
# Note: lvals are either
# raw_syntax::Id
# raw_syntax::Sub
# raw_syntax::Arrow
# raw_syntax::Deref
# raw_syntax::Dot where first arg is an lval
fun simplify_assign_ops { get_aid, get_core_type, wrap_expr, get_loc, top_level, bind_sym, push_tmp_vars }
=
simplify_ass
where
fun wrap_expr' x
=
{ my (type, expr) = wrap_expr x;
expr;
};
fun combine_exprs' (x1, x2 as raw_syntax::EXPRESSION (_, adorn, _))
=
wrap_expr' (get_core_type (get_aid adorn), raw_syntax::COMMA (x1, x2));
fun combine_exprs (NULL, x) => x;
combine_exprs (THE x1, x2) => combine_exprs'(x1, x2);
end;
fun combine_exprs_opt (NULL, x) => x;
combine_exprs_opt (x, NULL) => x;
combine_exprs_opt (THE x1, THE x2) => THE (combine_exprs'(x1, x2));
end;
fun get_expr_type (raw_syntax::EXPRESSION(_, adorn, _))
=
get_core_type (get_aid adorn);
# Can't just introduce id of type type: may not be legal to do assignment (e.g. for arrays).
# So, first convert arrays to pointers, functions to pointers, and eliminate qualifiers.
# Potential problem: elimination of volatile qualifiers on temporary variables?
fun nice_type type
=
case (get_core_type type)
raw_syntax::ARRAY (_, array_tp) => raw_syntax::POINTER array_tp;
raw_syntax::FUNCTION x => raw_syntax::POINTER type;
_ => type;
esac;
fun simple_dup expr # given e, return: (tmp = e, tmp, tmp)
=
{ type = get_expr_type expr;
symbol = symbol::chunk "tmp";
id = { name=>symbol, uid => pid::new(), location => get_loc(),
ctype => nice_type type, st_ilk => raw_syntax::DEFAULT, status => raw_syntax::DECLARED,
kind => raw_syntax::NONFUN, global => top_level() };
push_tmp_vars id;
bind_sym (symbol, namings::ID id);
expr_new_variable = wrap_expr'(type, raw_syntax::ID id);
{ assigns=>THE (wrap_expr'(type, raw_syntax::ASSIGN (expr_new_variable, expr))),
var1=>wrap_expr'(type, raw_syntax::ID id),
var2=>wrap_expr'(type, raw_syntax::ID id) };
};
fun duplicate_rval (expr as raw_syntax::EXPRESSION (raw_syntax::ID _, _, _)) => { assigns=>NULL, var1=>expr, var2=>expr };
duplicate_rval expr => simple_dup expr;
end;
fun duplicate_lval expr # Copy lval, factoring out side-effecting expressions
=
{ fun dup (mk_expression, expr)
=
{ my { assigns, var1, var2 } = duplicate_rval expr;
{ assigns,
copy1=> mk_expression var1,
copy2=> mk_expression var2
};
};
fun dup2 (mk_expression, expr1, expr2)
=
{
my { assigns=>assigns1, var1=>var1a, var2=>var1b } = duplicate_rval expr1;
my { assigns=>assigns2, var1=>var2a, var2=>var2b } = duplicate_rval expr2;
assigns = combine_exprs_opt (assigns1, assigns2);
{ assigns,
copy1=>mk_expression (var1a, var2a),
copy2=>mk_expression (var1b, var2b) };
};
case expr
raw_syntax::EXPRESSION (raw_syntax::ID pid, _, _)
=>
{ assigns=>NULL,
copy1=>expr,
copy2=>wrap_expr'(get_expr_type expr, raw_syntax::ID pid) };
raw_syntax::EXPRESSION (raw_syntax::ARROW (expr1, member), adorn, loc)
=>
dup (\\ e => wrap_expr'(get_aid adorn, raw_syntax::ARROW (e, member)); end, expr1);
raw_syntax::EXPRESSION (raw_syntax::DEREF (expr1), adorn, loc)
=>
dup (\\ e => wrap_expr'(get_aid adorn, raw_syntax::DEREF e); end, expr1);
raw_syntax::EXPRESSION (raw_syntax::SUB (expr1, expr2), adorn, loc)
=>
dup2 (\\ e => wrap_expr'(get_aid adorn, raw_syntax::SUB e); end, expr1, expr2);
raw_syntax::EXPRESSION (raw_syntax::MEMBER (expr1, member), _, _)
=>
{ type = get_expr_type expr;
my { assigns, copy1, copy2 } = duplicate_lval (expr1);
{ assigns,
copy1 => wrap_expr'(type, raw_syntax::MEMBER (copy1, member)),
copy2 => wrap_expr'(type, raw_syntax::MEMBER (copy2, member))
};
};
raw_syntax::EXPRESSION (_, adorn, loc)
=>
# not an lval --> just use simple duplication (should never occur, unless error)
{ my { assigns, var1, var2 } = duplicate_rval expr;
{ assigns, copy1=>var1, copy2=>var2 };
};
esac;
};
fun simplify_ass (process_binop, opn, { pre_op=>TRUE }, expr1, expr2) # e.g. ++x; ++( *p ); x += 5; *p += 5;
=>
{ my { assigns, copy1, copy2 } = duplicate_lval expr1;
fun proc_binop x = { my (type, expr) = process_binop x; expr; };
new_expr = raw_syntax::ASSIGN (copy1, proc_binop (get_expr_type copy2, copy2, get_expr_type expr2, expr2, opn));
new_expr = wrap_expr'(get_expr_type expr1, new_expr);
final_expr = combine_exprs (assigns, new_expr);
(get_expr_type final_expr, final_expr);
};
simplify_ass (process_binop, opn, { pre_op=>FALSE }, expr1, expr2) # e.g. x++; ( *p )++;
=>
{ my { assigns, copy1, copy2 } = duplicate_lval expr1;
my { assigns=>assigns2, var1, var2 } = simple_dup copy1;
fun proc_binop x = { my (type, expr) = process_binop x; expr; };
new_expr = raw_syntax::ASSIGN (copy2, proc_binop (get_expr_type var1, var1, get_expr_type expr2, expr2, opn));
new_expr = wrap_expr'(get_expr_type expr1, new_expr);
final_expr = combine_exprs (assigns, combine_exprs (assigns2, combine_exprs'(new_expr, var2)));
(get_expr_type final_expr, final_expr);
};
end;
end;
};