Skip to content

Commit 012ce14

Browse files
committedNov 14, 2017
parsec supports post increment/decrement with used result
1 parent 4c2cdf6 commit 012ce14

File tree

2 files changed

+170
-29
lines changed

2 files changed

+170
-29
lines changed
 

‎src/parsec.cpp

+63-29
Original file line numberDiff line numberDiff line change
@@ -1499,38 +1499,72 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue
14991499
return trans_create_node_symbol(c, symbol_name);
15001500
}
15011501

1502+
static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
1503+
Expr *op_expr = stmt->getSubExpr();
1504+
1505+
if (!result_used) {
1506+
// common case
1507+
// c: expr++
1508+
// zig: expr += 1
1509+
return trans_create_node_bin_op(c,
1510+
trans_expr(c, true, block, op_expr, TransLValue),
1511+
assign_op,
1512+
trans_create_node_unsigned(c, 1));
1513+
} else {
1514+
// worst case
1515+
// c: expr++
1516+
// zig: {
1517+
// zig: const _ref = &expr;
1518+
// zig: const _tmp = *_ref;
1519+
// zig: *_ref += 1;
1520+
// zig: _tmp
1521+
// zig: }
1522+
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
1523+
1524+
// const _ref = &expr;
1525+
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
1526+
if (expr == nullptr) return nullptr;
1527+
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
1528+
// TODO: avoid name collisions with generated variable names
1529+
Buf* ref_var_name = buf_create_from_str("_ref");
1530+
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
1531+
child_block->data.block.statements.append(ref_var_decl);
1532+
1533+
// const _tmp = *_ref;
1534+
Buf* tmp_var_name = buf_create_from_str("_tmp");
1535+
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
1536+
trans_create_node_prefix_op(c, PrefixOpDereference,
1537+
trans_create_node_symbol(c, ref_var_name)));
1538+
child_block->data.block.statements.append(tmp_var_decl);
1539+
1540+
// *_ref += 1;
1541+
AstNode *assign_statement = trans_create_node_bin_op(c,
1542+
trans_create_node_prefix_op(c, PrefixOpDereference,
1543+
trans_create_node_symbol(c, ref_var_name)),
1544+
assign_op,
1545+
trans_create_node_unsigned(c, 1));
1546+
child_block->data.block.statements.append(assign_statement);
1547+
1548+
// _tmp
1549+
child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
1550+
child_block->data.block.last_statement_is_result_expression = true;
1551+
1552+
return child_block;
1553+
}
1554+
}
1555+
15021556
static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
15031557
switch (stmt->getOpcode()) {
1504-
case UO_PostInc: {
1505-
Expr *op_expr = stmt->getSubExpr();
1506-
BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType())
1507-
? BinOpTypeAssignPlusWrap
1508-
: BinOpTypeAssignPlus;
1509-
1510-
if (!result_used) {
1511-
// common case
1512-
// c: expr++
1513-
// zig: expr += 1
1514-
return trans_create_node_bin_op(c,
1515-
trans_expr(c, true, block, op_expr, TransLValue),
1516-
bin_op,
1517-
trans_create_node_unsigned(c, 1));
1518-
} else {
1519-
// worst case
1520-
// c: expr++
1521-
// zig: {
1522-
// zig: const _ref = &expr;
1523-
// zig: const _tmp = *_ref;
1524-
// zig: *_ref += 1;
1525-
// zig: _tmp
1526-
// zig: }
1527-
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used");
1528-
return nullptr;
1529-
}
1530-
}
1558+
case UO_PostInc:
1559+
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1560+
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
1561+
else
1562+
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
15311563
case UO_PostDec:
1532-
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec");
1533-
return nullptr;
1564+
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1565+
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
1566+
else
1567+
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
15341568
case UO_PreInc:
15351569
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
15361570
return nullptr;

‎test/parsec.zig

+107
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,65 @@ pub fn addCases(cases: &tests.ParseCContext) {
687687
\\ });
688688
\\}
689689
);
690+
691+
cases.addC("compound assignment operators unsigned",
692+
\\void foo(void) {
693+
\\ unsigned a = 0;
694+
\\ a += (a += 1);
695+
\\ a -= (a -= 1);
696+
\\ a *= (a *= 1);
697+
\\ a &= (a &= 1);
698+
\\ a |= (a |= 1);
699+
\\ a ^= (a ^= 1);
700+
\\ a >>= (a >>= 1);
701+
\\ a <<= (a <<= 1);
702+
\\}
703+
,
704+
\\export fn foo() {
705+
\\ var a: c_uint = c_uint(0);
706+
\\ a +%= {
707+
\\ const _ref = &a;
708+
\\ (*_ref) = ((*_ref) +% c_uint(1));
709+
\\ *_ref
710+
\\ };
711+
\\ a -%= {
712+
\\ const _ref = &a;
713+
\\ (*_ref) = ((*_ref) -% c_uint(1));
714+
\\ *_ref
715+
\\ };
716+
\\ a *%= {
717+
\\ const _ref = &a;
718+
\\ (*_ref) = ((*_ref) *% c_uint(1));
719+
\\ *_ref
720+
\\ };
721+
\\ a &= {
722+
\\ const _ref = &a;
723+
\\ (*_ref) = ((*_ref) & c_uint(1));
724+
\\ *_ref
725+
\\ };
726+
\\ a |= {
727+
\\ const _ref = &a;
728+
\\ (*_ref) = ((*_ref) | c_uint(1));
729+
\\ *_ref
730+
\\ };
731+
\\ a ^= {
732+
\\ const _ref = &a;
733+
\\ (*_ref) = ((*_ref) ^ c_uint(1));
734+
\\ *_ref
735+
\\ };
736+
\\ a >>= @import("std").math.Log2Int(c_uint)({
737+
\\ const _ref = &a;
738+
\\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
739+
\\ *_ref
740+
\\ });
741+
\\ a <<= @import("std").math.Log2Int(c_uint)({
742+
\\ const _ref = &a;
743+
\\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
744+
\\ *_ref
745+
\\ });
746+
\\}
747+
);
748+
690749
cases.addC("duplicate typedef",
691750
\\typedef long foo;
692751
\\typedef int bar;
@@ -697,6 +756,54 @@ pub fn addCases(cases: &tests.ParseCContext) {
697756
\\pub const bar = c_int;
698757
\\pub const baz = c_int;
699758
);
759+
760+
cases.addC("post increment/decrement",
761+
\\void foo(void) {
762+
\\ int i = 0;
763+
\\ unsigned u = 0;
764+
\\ i++;
765+
\\ i--;
766+
\\ u++;
767+
\\ u--;
768+
\\ i = i++;
769+
\\ i = i--;
770+
\\ u = u++;
771+
\\ u = u--;
772+
\\}
773+
,
774+
\\export fn foo() {
775+
\\ var i: c_int = 0;
776+
\\ var u: c_uint = c_uint(0);
777+
\\ i += 1;
778+
\\ i -= 1;
779+
\\ u +%= 1;
780+
\\ u -%= 1;
781+
\\ i = {
782+
\\ const _ref = &i;
783+
\\ const _tmp = *_ref;
784+
\\ (*_ref) += 1;
785+
\\ _tmp
786+
\\ };
787+
\\ i = {
788+
\\ const _ref = &i;
789+
\\ const _tmp = *_ref;
790+
\\ (*_ref) -= 1;
791+
\\ _tmp
792+
\\ };
793+
\\ u = {
794+
\\ const _ref = &u;
795+
\\ const _tmp = *_ref;
796+
\\ (*_ref) +%= 1;
797+
\\ _tmp
798+
\\ };
799+
\\ u = {
800+
\\ const _ref = &u;
801+
\\ const _tmp = *_ref;
802+
\\ (*_ref) -%= 1;
803+
\\ _tmp
804+
\\ };
805+
\\}
806+
);
700807
}
701808

702809

0 commit comments

Comments
 (0)
Please sign in to comment.