authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-11-13 22:19:51-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-11-13 22:19:51-07:00
log012ce1481e003b25e49934fce17f5e1b4aff218a
tree9d2928e6662a59c172dac26e488b82d89014dde8
parent4c2cdf6f4da09e2986aa7a574455995168bcab8f

parsec supports post increment/decrement with used result


2 files changed, 170 insertions(+), 29 deletions(-)

src/parsec.cpp+63-29
......@@ -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
1502static 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
15021556static 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
......@@ -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