Commit 012ce1481e

Josh Wolfe <thejoshwolfe@gmail.com>
2017-11-14 06:19:51
parsec supports post increment/decrement with used result
1 parent 4c2cdf6
Changed files (2)
src/parsec.cpp
@@ -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;
test/parsec.zig
@@ -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;
@@ -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
+        \\    };
+        \\}
+    );
 }