parsec supports post increment/decrement with used result
This commit is contained in:
parent
4c2cdf6f4d
commit
012ce1481e
@ -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;
|
||||
|
107
test/parsec.zig
107
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
|
||||
\\ };
|
||||
\\}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user