authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-03-05 09:54:59-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-07 14:54:04+02:00
log6d69a29d753de8680ff1220b8d9127e890e7d965
tree141db1ed1e331010b8c87e005a9f54fc2612d06f
parent874c63f89cb6174d2dba32f4d08c140b5eed6744

translate-c: Support compound assignment of pointer and signed int

This handles `ptr += idx` and `ptr -= idx` when `idx` is a signed integer expression.

2 files changed, 35 insertions(+), 9 deletions(-)

src/translate_c.zig+25-9
...@@ -1111,6 +1111,22 @@ fn transOffsetOfExpr(...@@ -1111,6 +1111,22 @@ fn transOffsetOfExpr(
1111 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});1111 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});
1112}1112}
11131113
1114/// Cast a signed integer node to a usize, for use in pointer arithmetic. Negative numbers
1115/// will become very large positive numbers but that is ok since we only use this in
1116/// pointer arithmetic expressions, where wraparound will ensure we get the correct value.
1117/// node -> @bitCast(usize, @intCast(isize, node))
1118fn usizeCastForWrappingPtrArithmetic(gpa: *mem.Allocator, node: Node) TransError!Node {
1119 const intcast_node = try Tag.int_cast.create(gpa, .{
1120 .lhs = try Tag.identifier.create(gpa, "isize"),
1121 .rhs = node,
1122 });
1123
1124 return Tag.bit_cast.create(gpa, .{
1125 .lhs = try Tag.identifier.create(gpa, "usize"),
1126 .rhs = intcast_node,
1127 });
1128}
1129
1114/// Translate an arithmetic expression with a pointer operand and a signed-integer operand.1130/// Translate an arithmetic expression with a pointer operand and a signed-integer operand.
1115/// Zig requires a usize argument for pointer arithmetic, so we intCast to isize and then1131/// Zig requires a usize argument for pointer arithmetic, so we intCast to isize and then
1116/// bitcast to usize; pointer wraparound make the math work.1132/// bitcast to usize; pointer wraparound make the math work.
...@@ -1133,15 +1149,7 @@ fn transCreatePointerArithmeticSignedOp(...@@ -1133,15 +1149,7 @@ fn transCreatePointerArithmeticSignedOp(
1133 const lhs_node = try transExpr(c, scope, swizzled_lhs, .used);1149 const lhs_node = try transExpr(c, scope, swizzled_lhs, .used);
1134 const rhs_node = try transExpr(c, scope, swizzled_rhs, .used);1150 const rhs_node = try transExpr(c, scope, swizzled_rhs, .used);
11351151
1136 const intcast_node = try Tag.int_cast.create(c.arena, .{1152 const bitcast_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
1137 .lhs = try Tag.identifier.create(c.arena, "isize"),
1138 .rhs = rhs_node,
1139 });
1140
1141 const bitcast_node = try Tag.bit_cast.create(c.arena, .{
1142 .lhs = try Tag.identifier.create(c.arena, "usize"),
1143 .rhs = intcast_node,
1144 });
11451153
1146 const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node };1154 const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node };
1147 const arith_node = try if (is_add) Tag.add.create(c.arena, arith_args) else Tag.sub.create(c.arena, arith_args);1155 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(...@@ -3035,6 +3043,7 @@ fn transCreateCompoundAssign(
3035 const lhs_qt = getExprQualType(c, lhs);3043 const lhs_qt = getExprQualType(c, lhs);
3036 const rhs_qt = getExprQualType(c, rhs);3044 const rhs_qt = getExprQualType(c, rhs);
3037 const is_signed = cIsSignedInteger(lhs_qt);3045 const is_signed = cIsSignedInteger(lhs_qt);
3046 const is_ptr_op_signed = qualTypeIsPtr(lhs_qt) and cIsSignedInteger(rhs_qt);
3038 const requires_int_cast = blk: {3047 const requires_int_cast = blk: {
3039 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);3048 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
3040 const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt);3049 const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt);
...@@ -3061,6 +3070,10 @@ fn transCreateCompoundAssign(...@@ -3061,6 +3070,10 @@ fn transCreateCompoundAssign(
3061 else3070 else
3062 try transExpr(c, scope, rhs, .used);3071 try transExpr(c, scope, rhs, .used);
30633072
3073 if (is_ptr_op_signed) {
3074 rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3075 }
3076
3064 if (is_shift or requires_int_cast) {3077 if (is_shift or requires_int_cast) {
3065 // @intCast(rhs)3078 // @intCast(rhs)
3066 const cast_to_type = if (is_shift)3079 const cast_to_type = if (is_shift)
...@@ -3113,6 +3126,9 @@ fn transCreateCompoundAssign(...@@ -3113,6 +3126,9 @@ fn transCreateCompoundAssign(
31133126
3114 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });3127 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
3115 }3128 }
3129 if (is_ptr_op_signed) {
3130 rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3131 }
31163132
3117 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);3133 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);
3118 try block_scope.statements.append(assign);3134 try block_scope.statements.append(assign);
test/run_translated_c.zig+10
...@@ -1154,6 +1154,16 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1154,6 +1154,16 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1154 \\ y = x - idx;1154 \\ y = x - idx;
1155 \\ if (y != x + 1 || y != &array[6]) abort();1155 \\ if (y != x + 1 || y != &array[6]) abort();
1156 \\1156 \\
1157 \\ idx = 1;
1158 \\ x += idx;
1159 \\ if (x != &array[6]) abort();
1160 \\ x -= idx;
1161 \\ if (x != &array[5]) abort();
1162 \\ y = (x += idx);
1163 \\ if (y != x || y != &array[6]) abort();
1164 \\ y = (x -= idx);
1165 \\ if (y != x || y != &array[5]) abort();
1166 \\
1157 \\ return 0;1167 \\ return 0;
1158 \\}1168 \\}
1159 , "");1169 , "");