From ab9324e604068d4afb4e65a8e587bea95ab1051a Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Mon, 22 Mar 2021 20:28:30 -0700 Subject: [PATCH] translate-c: intcast compound assignment operand if different-sized integer Use transCCast to cast the RHS of compound assignment if necessary. --- src/translate_c.zig | 62 +++++++++++++++------------------------ test/run_translated_c.zig | 50 +++++++++++++++++++++++++++++++ test/translate_c.zig | 4 +-- 3 files changed, 76 insertions(+), 40 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index facae99ccb..3bc9cb5457 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -3197,43 +3197,34 @@ fn transCreateCompoundAssign( const requires_int_cast = blk: { const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt); const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt); - break :blk are_integers and !are_same_sign; + break :blk are_integers and !(are_same_sign and cIntTypeCmp(lhs_qt, rhs_qt) == .eq); }; + if (used == .unused) { // common case // c: lhs += rhs // zig: lhs += rhs + const lhs_node = try transExpr(c, scope, lhs, .used); + var rhs_node = try transExpr(c, scope, rhs, .used); + if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); + if ((is_mod or is_div) and is_signed) { - const lhs_node = try transExpr(c, scope, lhs, .used); - const rhs_node = try transExpr(c, scope, rhs, .used); + if (requires_int_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); + const operands = .{ .lhs = lhs_node, .rhs = rhs_node }; const builtin = if (is_mod) - try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) + try Tag.rem.create(c.arena, operands) else - try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); + try Tag.div_trunc.create(c.arena, operands); return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); } - const lhs_node = try transExpr(c, scope, lhs, .used); - var rhs_node = if (is_shift or requires_int_cast) - try transExprCoercing(c, scope, rhs, .used) - else - try transExpr(c, scope, rhs, .used); - - if (is_ptr_op_signed) { - rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); - } - - if (is_shift or requires_int_cast) { - // @intCast(rhs) - const cast_to_type = if (is_shift) - try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc) - else - try transQualType(c, scope, getExprQualType(c, lhs), loc); - + if (is_shift) { + const cast_to_type = try qualTypeToLog2IntRef(c, scope, rhs_qt, loc); rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); + } else if (requires_int_cast) { + rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); } - return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used); } // worst case @@ -3255,29 +3246,24 @@ fn transCreateCompoundAssign( const lhs_node = try Tag.identifier.create(c.arena, ref); const ref_node = try Tag.deref.create(c.arena, lhs_node); + var rhs_node = try transExpr(c, &block_scope.base, rhs, .used); + if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); if ((is_mod or is_div) and is_signed) { - const rhs_node = try transExpr(c, &block_scope.base, rhs, .used); + if (requires_int_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); + const operands = .{ .lhs = ref_node, .rhs = rhs_node }; const builtin = if (is_mod) - try Tag.rem.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node }) + try Tag.rem.create(c.arena, operands) else - try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node }); + try Tag.div_trunc.create(c.arena, operands); const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used); try block_scope.statements.append(assign); } else { - var rhs_node = try transExpr(c, &block_scope.base, rhs, .used); - - if (is_shift or requires_int_cast) { - // @intCast(rhs) - const cast_to_type = if (is_shift) - try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc) - else - try transQualType(c, scope, getExprQualType(c, lhs), loc); - + if (is_shift) { + const cast_to_type = try qualTypeToLog2IntRef(c, &block_scope.base, rhs_qt, loc); rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); - } - if (is_ptr_op_signed) { - rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); + } else if (requires_int_cast) { + rhs_node = try transCCast(c, &block_scope.base, loc, lhs_qt, rhs_qt, rhs_node); } const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 9af9583c27..6cac9cd79d 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1258,4 +1258,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("cast RHS of compound assignment if necessary, unused result", + \\#include + \\int main(void) { + \\ signed short val = -1; + \\ val += 1; if (val != 0) abort(); + \\ val -= 1; if (val != -1) abort(); + \\ val *= 2; if (val != -2) abort(); + \\ val /= 2; if (val != -1) abort(); + \\ val %= 2; if (val != -1) abort(); + \\ val <<= 1; if (val != -2) abort(); + \\ val >>= 1; if (val != -1) abort(); + \\ val += 100000000; // compile error if @truncate() not inserted + \\ unsigned short uval = 1; + \\ uval += 1; if (uval != 2) abort(); + \\ uval -= 1; if (uval != 1) abort(); + \\ uval *= 2; if (uval != 2) abort(); + \\ uval /= 2; if (uval != 1) abort(); + \\ uval %= 2; if (uval != 1) abort(); + \\ uval <<= 1; if (uval != 2) abort(); + \\ uval >>= 1; if (uval != 1) abort(); + \\ uval += 100000000; // compile error if @truncate() not inserted + \\} + , ""); + + cases.add("cast RHS of compound assignment if necessary, used result", + \\#include + \\int main(void) { + \\ signed short foo; + \\ signed short val = -1; + \\ foo = (val += 1); if (foo != 0) abort(); + \\ foo = (val -= 1); if (foo != -1) abort(); + \\ foo = (val *= 2); if (foo != -2) abort(); + \\ foo = (val /= 2); if (foo != -1) abort(); + \\ foo = (val %= 2); if (foo != -1) abort(); + \\ foo = (val <<= 1); if (foo != -2) abort(); + \\ foo = (val >>= 1); if (foo != -1) abort(); + \\ foo = (val += 100000000); // compile error if @truncate() not inserted + \\ unsigned short ufoo; + \\ unsigned short uval = 1; + \\ ufoo = (uval += 1); if (ufoo != 2) abort(); + \\ ufoo = (uval -= 1); if (ufoo != 1) abort(); + \\ ufoo = (uval *= 2); if (ufoo != 2) abort(); + \\ ufoo = (uval /= 2); if (ufoo != 1) abort(); + \\ ufoo = (uval %= 2); if (ufoo != 1) abort(); + \\ ufoo = (uval <<= 1); if (ufoo != 2) abort(); + \\ ufoo = (uval >>= 1); if (ufoo != 1) abort(); + \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 871441cb1d..54bb468cf9 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -2766,7 +2766,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ var a = arg_a; \\ var i: c_int = 0; \\ while (a > @bitCast(c_uint, @as(c_int, 0))) { - \\ a >>= @intCast(@import("std").math.Log2Int(c_int), 1); + \\ a >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1)); \\ } \\ return i; \\} @@ -2786,7 +2786,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ var a = arg_a; \\ var i: c_int = 0; \\ while (a > @bitCast(c_uint, @as(c_int, 0))) { - \\ a >>= @intCast(@import("std").math.Log2Int(c_int), 1); + \\ a >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1)); \\ } \\ return i; \\}