Skip to content

Commit

Permalink
parsec supports post increment/decrement with used result
Browse files Browse the repository at this point in the history
  • Loading branch information
thejoshwolfe committed Nov 14, 2017
1 parent 4c2cdf6 commit 012ce14
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 29 deletions.
92 changes: 63 additions & 29 deletions src/parsec.cpp
Expand Up @@ -1499,38 +1499,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue
return trans_create_node_symbol(c, symbol_name);
}

static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
Expr *op_expr = stmt->getSubExpr();

if (!result_used) {
// common case
// c: expr++
// zig: expr += 1
return trans_create_node_bin_op(c,
trans_expr(c, true, block, op_expr, TransLValue),
assign_op,
trans_create_node_unsigned(c, 1));
} else {
// worst case
// c: expr++
// zig: {
// zig: const _ref = &expr;
// zig: const _tmp = *_ref;
// zig: *_ref += 1;
// zig: _tmp
// zig: }
AstNode *child_block = trans_create_node(c, NodeTypeBlock);

// const _ref = &expr;
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
if (expr == nullptr) return nullptr;
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
// TODO: avoid name collisions with generated variable names
Buf* ref_var_name = buf_create_from_str("_ref");
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
child_block->data.block.statements.append(ref_var_decl);

// const _tmp = *_ref;
Buf* tmp_var_name = buf_create_from_str("_tmp");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, ref_var_name)));
child_block->data.block.statements.append(tmp_var_decl);

// *_ref += 1;
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, ref_var_name)),
assign_op,
trans_create_node_unsigned(c, 1));
child_block->data.block.statements.append(assign_statement);

// _tmp
child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
child_block->data.block.last_statement_is_result_expression = true;

return child_block;
}
}

static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
switch (stmt->getOpcode()) {
case UO_PostInc: {
Expr *op_expr = stmt->getSubExpr();
BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType())
? BinOpTypeAssignPlusWrap
: BinOpTypeAssignPlus;

if (!result_used) {
// common case
// c: expr++
// zig: expr += 1
return trans_create_node_bin_op(c,
trans_expr(c, true, block, op_expr, TransLValue),
bin_op,
trans_create_node_unsigned(c, 1));
} else {
// worst case
// c: expr++
// zig: {
// zig: const _ref = &expr;
// zig: const _tmp = *_ref;
// zig: *_ref += 1;
// zig: _tmp
// zig: }
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used");
return nullptr;
}
}
case UO_PostInc:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
else
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
case UO_PostDec:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec");
return nullptr;
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
else
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
case UO_PreInc:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
return nullptr;
Expand Down
107 changes: 107 additions & 0 deletions test/parsec.zig
Expand Up @@ -687,6 +687,65 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ });
\\}
);

cases.addC("compound assignment operators unsigned",
\\void foo(void) {
\\ unsigned a = 0;
\\ a += (a += 1);
\\ a -= (a -= 1);
\\ a *= (a *= 1);
\\ a &= (a &= 1);
\\ a |= (a |= 1);
\\ a ^= (a ^= 1);
\\ a >>= (a >>= 1);
\\ a <<= (a <<= 1);
\\}
,
\\export fn foo() {
\\ var a: c_uint = c_uint(0);
\\ a +%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) +% c_uint(1));
\\ *_ref
\\ };
\\ a -%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) -% c_uint(1));
\\ *_ref
\\ };
\\ a *%= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) *% c_uint(1));
\\ *_ref
\\ };
\\ a &= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) & c_uint(1));
\\ *_ref
\\ };
\\ a |= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) | c_uint(1));
\\ *_ref
\\ };
\\ a ^= {
\\ const _ref = &a;
\\ (*_ref) = ((*_ref) ^ c_uint(1));
\\ *_ref
\\ };
\\ a >>= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
\\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\ a <<= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
\\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\}
);

cases.addC("duplicate typedef",
\\typedef long foo;
\\typedef int bar;
Expand All @@ -697,6 +756,54 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\pub const bar = c_int;
\\pub const baz = c_int;
);

cases.addC("post increment/decrement",
\\void foo(void) {
\\ int i = 0;
\\ unsigned u = 0;
\\ i++;
\\ i--;
\\ u++;
\\ u--;
\\ i = i++;
\\ i = i--;
\\ u = u++;
\\ u = u--;
\\}
,
\\export fn foo() {
\\ var i: c_int = 0;
\\ var u: c_uint = c_uint(0);
\\ i += 1;
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = {
\\ const _ref = &i;
\\ const _tmp = *_ref;
\\ (*_ref) += 1;
\\ _tmp
\\ };
\\ i = {
\\ const _ref = &i;
\\ const _tmp = *_ref;
\\ (*_ref) -= 1;
\\ _tmp
\\ };
\\ u = {
\\ const _ref = &u;
\\ const _tmp = *_ref;
\\ (*_ref) +%= 1;
\\ _tmp
\\ };
\\ u = {
\\ const _ref = &u;
\\ const _tmp = *_ref;
\\ (*_ref) -%= 1;
\\ _tmp
\\ };
\\}
);
}


Expand Down

0 comments on commit 012ce14

Please sign in to comment.