From 6d69a29d753de8680ff1220b8d9127e890e7d965 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Fri, 5 Mar 2021 09:54:59 -0800 Subject: [PATCH] translate-c: Support compound assignment of pointer and signed int This handles `ptr += idx` and `ptr -= idx` when `idx` is a signed integer expression. --- src/translate_c.zig | 34 +++++++++++++++++++++++++--------- test/run_translated_c.zig | 10 ++++++++++ 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/translate_c.zig b/src/translate_c.zig index 0fec83e3bb..896f89283d 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1111,6 +1111,22 @@ fn transOffsetOfExpr( return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{}); } +/// Cast a signed integer node to a usize, for use in pointer arithmetic. Negative numbers +/// will become very large positive numbers but that is ok since we only use this in +/// pointer arithmetic expressions, where wraparound will ensure we get the correct value. +/// node -> @bitCast(usize, @intCast(isize, node)) +fn usizeCastForWrappingPtrArithmetic(gpa: *mem.Allocator, node: Node) TransError!Node { + const intcast_node = try Tag.int_cast.create(gpa, .{ + .lhs = try Tag.identifier.create(gpa, "isize"), + .rhs = node, + }); + + return Tag.bit_cast.create(gpa, .{ + .lhs = try Tag.identifier.create(gpa, "usize"), + .rhs = intcast_node, + }); +} + /// Translate an arithmetic expression with a pointer operand and a signed-integer operand. /// Zig requires a usize argument for pointer arithmetic, so we intCast to isize and then /// bitcast to usize; pointer wraparound make the math work. @@ -1133,15 +1149,7 @@ fn transCreatePointerArithmeticSignedOp( const lhs_node = try transExpr(c, scope, swizzled_lhs, .used); const rhs_node = try transExpr(c, scope, swizzled_rhs, .used); - const intcast_node = try Tag.int_cast.create(c.arena, .{ - .lhs = try Tag.identifier.create(c.arena, "isize"), - .rhs = rhs_node, - }); - - const bitcast_node = try Tag.bit_cast.create(c.arena, .{ - .lhs = try Tag.identifier.create(c.arena, "usize"), - .rhs = intcast_node, - }); + const bitcast_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node }; const arith_node = try if (is_add) Tag.add.create(c.arena, arith_args) else Tag.sub.create(c.arena, arith_args); @@ -3035,6 +3043,7 @@ fn transCreateCompoundAssign( const lhs_qt = getExprQualType(c, lhs); const rhs_qt = getExprQualType(c, rhs); const is_signed = cIsSignedInteger(lhs_qt); + const is_ptr_op_signed = qualTypeIsPtr(lhs_qt) and cIsSignedInteger(rhs_qt); 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); @@ -3061,6 +3070,10 @@ fn transCreateCompoundAssign( 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) @@ -3113,6 +3126,9 @@ fn transCreateCompoundAssign( 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); + } const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used); try block_scope.statements.append(assign); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 977400be82..abefe46459 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1154,6 +1154,16 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ y = x - idx; \\ if (y != x + 1 || y != &array[6]) abort(); \\ + \\ idx = 1; + \\ x += idx; + \\ if (x != &array[6]) abort(); + \\ x -= idx; + \\ if (x != &array[5]) abort(); + \\ y = (x += idx); + \\ if (y != x || y != &array[6]) abort(); + \\ y = (x -= idx); + \\ if (y != x || y != &array[5]) abort(); + \\ \\ return 0; \\} , "");