From ed1386eeff0a3d0fbec74bbf775544104874cead Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 11:13:10 +0100 Subject: [PATCH 1/5] Simple translation of UO_LNot --- src/translate_c.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 9bea476352c216544ea9c9a69ae24914eb85cd54..ea3beb3548b593a338625bc19e712d1c102f892f 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1907,17 +1907,23 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc return nullptr; } } + case UO_LNot: case UO_Not: { Expr *op_expr = stmt->getSubExpr(); AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); if (sub_node == nullptr) return nullptr; - return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); + + switch (stmt->getOpcode()) { + case UO_LNot: + return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); + case UO_Not: + return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); + default: + zig_unreachable(); + } } - case UO_LNot: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot"); - return nullptr; case UO_Real: emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); return nullptr; -- 2.54.0 From 61ecc486717944ad652cd9442fe35a4cfb9ae1ec Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 11:15:13 +0100 Subject: [PATCH 2/5] Added appropriate TODO comment to UO_LNot --- src/translate_c.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index ea3beb3548b593a338625bc19e712d1c102f892f..9a1ef7ffd631dcc39972431db505107094c89203 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1917,6 +1917,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc switch (stmt->getOpcode()) { case UO_LNot: + // TODO: Handle int, float, pointer negation return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); case UO_Not: return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); -- 2.54.0 From bf47cf418af785550f298a519b0dbfa2efcdd3cb Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 11:57:51 +0100 Subject: [PATCH 3/5] expr to bool is now it's own function. * Now while and for loops work on ints and floats, like if statements * This fixes the loop problem in #813 --- src/translate_c.cpp | 127 ++++++++++++++++++++++--------------------- test/translate_c.zig | 65 +++++++++++++++++++--- 2 files changed, 122 insertions(+), 70 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 9a1ef7ffd631dcc39972431db505107094c89203..bee867c4ab730e2b5292ba75d9c8d0a4e22f2e93 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -2204,43 +2204,10 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt return ErrorNone; } -static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) { - TransScopeWhile *while_scope = trans_scope_while_create(c, scope); - - while_scope->node->data.while_expr.condition = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); - if (while_scope->node->data.while_expr.condition == nullptr) - return nullptr; - - TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), - &while_scope->node->data.while_expr.body); - if (body_scope == nullptr) - return nullptr; - - return while_scope->node; -} - -static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) { - // if (c) t - // if (c) t else e - AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); - - TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block); - if (then_scope == nullptr) - return nullptr; - - if (stmt->getElse() != nullptr) { - TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node); - if (else_scope == nullptr) - return nullptr; - } - - AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); - if (condition_node == nullptr) - return nullptr; - - switch (condition_node->type) { +static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr) { + switch (expr->type) { case NodeTypeBinOpExpr: - switch (condition_node->data.bin_op_expr.bin_op) { + switch (expr->data.bin_op_expr.bin_op) { case BinOpTypeBoolOr: case BinOpTypeBoolAnd: case BinOpTypeCmpEq: @@ -2249,43 +2216,42 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt * case BinOpTypeCmpGreaterThan: case BinOpTypeCmpLessOrEq: case BinOpTypeCmpGreaterOrEq: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; + return expr; default: goto convert_to_bitcast; } case NodeTypePrefixOpExpr: - switch (condition_node->data.prefix_op_expr.prefix_op) { + switch (expr->data.prefix_op_expr.prefix_op) { case PrefixOpBoolNot: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; + return expr; default: goto convert_to_bitcast; } case NodeTypeBoolLiteral: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; + return expr; default: { - // In Zig, float, int and pointer does not work in if statements. - // To make it work, we bitcast any value we get to an int of the right size - // and comp it to 0 - // TODO: This doesn't work for pointers, as they become nullable on - // translate - // c: if (cond) { } - // zig: { - // zig: const _tmp = cond; - // zig: if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { } - // zig: } - convert_to_bitcast: + // In Zig, float, int and pointer does not implicitly cast to bool. + // To make it work, we bitcast any value we get to an int of the right size + // and comp it to 0 + // TODO: This doesn't work for pointers, as they become nullable on + // translate + // c: expr + // zig: __to_bool_expr: { + // zig: const _tmp = cond; + // zig: break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + // zig: } + convert_to_bitcast: TransScopeBlock *child_scope = trans_scope_block_create(c, scope); + Buf *label_name = buf_create_from_str("__to_bool_expr"); + child_scope->node->data.block.name = label_name; // const _tmp = cond; // TODO: avoid name collisions with generated variable names - 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, condition_node); + 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, expr); child_scope->node->data.block.statements.append(tmp_var_decl); // @sizeOf(@typeOf(_tmp)) * 8 @@ -2294,8 +2260,8 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt * AstNode *sizeof_tmp = trans_create_node_builtin_fn_call_str(c, "sizeOf"); sizeof_tmp->data.fn_call_expr.params.append(typeof_tmp); AstNode *sizeof_tmp_in_bits = trans_create_node_bin_op( - c, sizeof_tmp, BinOpTypeMult, - trans_create_node_unsigned_negative(c, 8, false)); + c, sizeof_tmp, BinOpTypeMult, + trans_create_node_unsigned_negative(c, 8, false)); // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8) AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType"); @@ -2307,16 +2273,53 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt * bit_cast->data.fn_call_expr.params.append(int_type); bit_cast->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name)); - // if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { } + // break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0 AstNode *not_eql_zero = trans_create_node_bin_op(c, bit_cast, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false)); - if_node->data.if_bool_expr.condition = not_eql_zero; - child_scope->node->data.block.statements.append(if_node); + child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, not_eql_zero)); return child_scope->node; } } } +static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) { + TransScopeWhile *while_scope = trans_scope_while_create(c, scope); + + while_scope->node->data.while_expr.condition = trans_to_bool_expr(c, scope, trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue)); + if (while_scope->node->data.while_expr.condition == nullptr) + return nullptr; + + TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), + &while_scope->node->data.while_expr.body); + if (body_scope == nullptr) + return nullptr; + + return while_scope->node; +} + +static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) { + // if (c) t + // if (c) t else e + AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); + + TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block); + if (then_scope == nullptr) + return nullptr; + + if (stmt->getElse() != nullptr) { + TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node); + if (else_scope == nullptr) + return nullptr; + } + + AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); + if (condition_node == nullptr) + return nullptr; + + if_node->data.if_bool_expr.condition = trans_to_bool_expr(c, scope, condition_node); + return if_node; +} + static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) { AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); @@ -2503,6 +2506,8 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt &while_scope->node->data.while_expr.condition); if (end_cond_scope == nullptr) return nullptr; + + while_scope->node->data.while_expr.condition = trans_to_bool_expr(c, cond_scope, while_scope->node->data.while_expr.condition); } const Stmt *inc_stmt = stmt->getInc(); diff --git a/test/translate_c.zig b/test/translate_c.zig index e6270842b1c875ade83b09c4ed8fc0a438057a63..23bb1759c0cf7498452911e827d96c6922b23579 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1124,15 +1124,62 @@ pub fn addCases(cases: &tests.TranslateCContext) void { \\ } \\} , - \\pub fn if_int(i: c_int) c_int { - \\ { - \\ const _tmp = i; - \\ if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { - \\ return 0; - \\ } else { - \\ return 1; - \\ }; - \\ }; + \\pub fn if_int(i: c_int) c_int { + \\ if (__to_bool_expr: { + \\ const _tmp = i; + \\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + \\ }) { + \\ return 0; + \\ } else { + \\ return 1; + \\ }; + \\} + ); + + cases.add("while on int", + \\int while_int(int i) { + \\ while (i) { + \\ return 0; + \\ } \\} + , + \\pub fn while_int(i: c_int) c_int { + \\ while (__to_bool_expr: { + \\ const _tmp = i; + \\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + \\ }) { + \\ return 0; + \\ }; + \\} + ); + + cases.add("for on int", + \\int for_int(int i) { + \\ for (;i;) { + \\ return 0; + \\ } + \\ + \\ for (int j = 4;j;j--) { + \\ return 0; + \\ } + \\} + , + \\pub fn for_int(i: c_int) c_int { + \\ while (__to_bool_expr: { + \\ const _tmp = i; + \\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + \\ }) { + \\ return 0; + \\ }; + \\ { + \\ var j: c_int = 4; + \\ while (__to_bool_expr: { + \\ const _tmp = j; + \\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + \\ }) : (j -= 1) { + \\ return 0; + \\ }; + \\ }; + \\} ); } -- 2.54.0 From 5ab25798e313105bf783934ac3c18b2930c8da5e Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 12:04:14 +0100 Subject: [PATCH 4/5] We now also use trans_to_bool_expr on bool not --- src/translate_c.cpp | 14 +++++++------- test/translate_c.zig | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index bee867c4ab730e2b5292ba75d9c8d0a4e22f2e93..3035a6682d6fef0cd23b333b74aaf527006137a7 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -118,7 +118,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node); static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval); static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); - +static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr); ATTRIBUTE_PRINTF(3, 4) static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { @@ -632,7 +632,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) { case BuiltinType::Int128: case BuiltinType::WChar_S: return true; - default: + default: return false; } } @@ -653,7 +653,7 @@ static bool c_is_unsigned_integer(Context *c, QualType qt) { case BuiltinType::UInt128: case BuiltinType::WChar_U: return true; - default: + default: return false; } } @@ -678,7 +678,7 @@ static bool c_is_float(Context *c, QualType qt) { case BuiltinType::Float128: case BuiltinType::LongDouble: return true; - default: + default: return false; } } @@ -1389,7 +1389,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result if (result_used == ResultUsedYes) { // break :x *_ref child_scope->node->data.block.statements.append( - trans_create_node_break(c, label_name, + trans_create_node_break(c, label_name, trans_create_node_prefix_op(c, PrefixOpDereference, trans_create_node_symbol(c, tmp_var_name)))); } @@ -1918,7 +1918,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc switch (stmt->getOpcode()) { case UO_LNot: // TODO: Handle int, float, pointer negation - return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node); + return trans_create_node_prefix_op(c, PrefixOpBoolNot, trans_to_bool_expr(c, scope, sub_node)); case UO_Not: return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); default: @@ -2291,7 +2291,7 @@ static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), &while_scope->node->data.while_expr.body); - if (body_scope == nullptr) + if (body_scope == nullptr) return nullptr; return while_scope->node; diff --git a/test/translate_c.zig b/test/translate_c.zig index 23bb1759c0cf7498452911e827d96c6922b23579..e1aa648d73ead7b26a7b2150562e34718483d0b0 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -1083,6 +1083,21 @@ pub fn addCases(cases: &tests.TranslateCContext) void { \\} ); + cases.add("bool not", + \\int foo(int x) { + \\ return !(x == 0); + \\ return !x; + \\} + , + \\pub fn foo(x: c_int) c_int { + \\ return !(x == 0); + \\ return !__to_bool_expr: { + \\ const _tmp = x; + \\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0; + \\ }; + \\} + ); + cases.add("primitive types included in defined symbols", \\int foo(int u32) { \\ return u32; @@ -1110,7 +1125,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void { ); cases.add("macro pointer cast", - \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) + \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) , \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE); ); -- 2.54.0 From 1d378d8f261603dde69055646b1806ada393b1e0 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 12:33:09 +0100 Subject: [PATCH 5/5] Removed fixed todo --- src/translate_c.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 3035a6682d6fef0cd23b333b74aaf527006137a7..183f3928e0f145b969150cadb7e9cedc1adca720 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -1917,7 +1917,6 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc switch (stmt->getOpcode()) { case UO_LNot: - // TODO: Handle int, float, pointer negation return trans_create_node_prefix_op(c, PrefixOpBoolNot, trans_to_bool_expr(c, scope, sub_node)); case UO_Not: return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); -- 2.54.0