authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-03-22 20:28:30-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-28 15:21:12+03:00
logab9324e604068d4afb4e65a8e587bea95ab1051a
tree14ea94d51adb927951236e5deb883e90774fefe6
parentc8d721aa429ae492a10bc3d21ed5487ad620a032

translate-c: intcast compound assignment operand if different-sized integer

Use transCCast to cast the RHS of compound assignment if necessary.

3 files changed, 76 insertions(+), 40 deletions(-)

src/translate_c.zig+24-38
...@@ -3197,43 +3197,34 @@ fn transCreateCompoundAssign(...@@ -3197,43 +3197,34 @@ fn transCreateCompoundAssign(
3197 const requires_int_cast = blk: {3197 const requires_int_cast = blk: {
3198 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);3198 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
3199 const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt);3199 const are_same_sign = cIsSignedInteger(lhs_qt) == cIsSignedInteger(rhs_qt);
3200 break :blk are_integers and !are_same_sign;3200 break :blk are_integers and !(are_same_sign and cIntTypeCmp(lhs_qt, rhs_qt) == .eq);
3201 };3201 };
3202
3202 if (used == .unused) {3203 if (used == .unused) {
3203 // common case3204 // common case
3204 // c: lhs += rhs3205 // c: lhs += rhs
3205 // zig: lhs += rhs3206 // zig: lhs += rhs
3207 const lhs_node = try transExpr(c, scope, lhs, .used);
3208 var rhs_node = try transExpr(c, scope, rhs, .used);
3209 if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3210
3206 if ((is_mod or is_div) and is_signed) {3211 if ((is_mod or is_div) and is_signed) {
3207 const lhs_node = try transExpr(c, scope, lhs, .used);3212 if (requires_int_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
3208 const rhs_node = try transExpr(c, scope, rhs, .used);3213 const operands = .{ .lhs = lhs_node, .rhs = rhs_node };
3209 const builtin = if (is_mod)3214 const builtin = if (is_mod)
3210 try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })3215 try Tag.rem.create(c.arena, operands)
3211 else3216 else
3212 try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });3217 try Tag.div_trunc.create(c.arena, operands);
32133218
3214 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);3219 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
3215 }3220 }
32163221
3217 const lhs_node = try transExpr(c, scope, lhs, .used);3222 if (is_shift) {
3218 var rhs_node = if (is_shift or requires_int_cast)3223 const cast_to_type = try qualTypeToLog2IntRef(c, scope, rhs_qt, loc);
3219 try transExprCoercing(c, scope, rhs, .used)
3220 else
3221 try transExpr(c, scope, rhs, .used);
3222
3223 if (is_ptr_op_signed) {
3224 rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3225 }
3226
3227 if (is_shift or requires_int_cast) {
3228 // @intCast(rhs)
3229 const cast_to_type = if (is_shift)
3230 try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
3231 else
3232 try transQualType(c, scope, getExprQualType(c, lhs), loc);
3233
3234 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });3224 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
3225 } else if (requires_int_cast) {
3226 rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
3235 }3227 }
3236
3237 return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used);3228 return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used);
3238 }3229 }
3239 // worst case3230 // worst case
...@@ -3255,29 +3246,24 @@ fn transCreateCompoundAssign(...@@ -3255,29 +3246,24 @@ fn transCreateCompoundAssign(
3255 const lhs_node = try Tag.identifier.create(c.arena, ref);3246 const lhs_node = try Tag.identifier.create(c.arena, ref);
3256 const ref_node = try Tag.deref.create(c.arena, lhs_node);3247 const ref_node = try Tag.deref.create(c.arena, lhs_node);
32573248
3249 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
3250 if (is_ptr_op_signed) rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3258 if ((is_mod or is_div) and is_signed) {3251 if ((is_mod or is_div) and is_signed) {
3259 const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);3252 if (requires_int_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node);
3253 const operands = .{ .lhs = ref_node, .rhs = rhs_node };
3260 const builtin = if (is_mod)3254 const builtin = if (is_mod)
3261 try Tag.rem.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node })3255 try Tag.rem.create(c.arena, operands)
3262 else3256 else
3263 try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node });3257 try Tag.div_trunc.create(c.arena, operands);
32643258
3265 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);3259 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);
3266 try block_scope.statements.append(assign);3260 try block_scope.statements.append(assign);
3267 } else {3261 } else {
3268 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);3262 if (is_shift) {
32693263 const cast_to_type = try qualTypeToLog2IntRef(c, &block_scope.base, rhs_qt, loc);
3270 if (is_shift or requires_int_cast) {
3271 // @intCast(rhs)
3272 const cast_to_type = if (is_shift)
3273 try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
3274 else
3275 try transQualType(c, scope, getExprQualType(c, lhs), loc);
3276
3277 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });3264 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
3278 }3265 } else if (requires_int_cast) {
3279 if (is_ptr_op_signed) {3266 rhs_node = try transCCast(c, &block_scope.base, loc, lhs_qt, rhs_qt, rhs_node);
3280 rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
3281 }3267 }
32823268
3283 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);3269 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);
test/run_translated_c.zig+50
...@@ -1258,4 +1258,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1258,4 +1258,54 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1258 \\ return 0;1258 \\ return 0;
1259 \\}1259 \\}
1260 , "");1260 , "");
1261
1262 cases.add("cast RHS of compound assignment if necessary, unused result",
1263 \\#include <stdlib.h>
1264 \\int main(void) {
1265 \\ signed short val = -1;
1266 \\ val += 1; if (val != 0) abort();
1267 \\ val -= 1; if (val != -1) abort();
1268 \\ val *= 2; if (val != -2) abort();
1269 \\ val /= 2; if (val != -1) abort();
1270 \\ val %= 2; if (val != -1) abort();
1271 \\ val <<= 1; if (val != -2) abort();
1272 \\ val >>= 1; if (val != -1) abort();
1273 \\ val += 100000000; // compile error if @truncate() not inserted
1274 \\ unsigned short uval = 1;
1275 \\ uval += 1; if (uval != 2) abort();
1276 \\ uval -= 1; if (uval != 1) abort();
1277 \\ uval *= 2; if (uval != 2) abort();
1278 \\ uval /= 2; if (uval != 1) abort();
1279 \\ uval %= 2; if (uval != 1) abort();
1280 \\ uval <<= 1; if (uval != 2) abort();
1281 \\ uval >>= 1; if (uval != 1) abort();
1282 \\ uval += 100000000; // compile error if @truncate() not inserted
1283 \\}
1284 , "");
1285
1286 cases.add("cast RHS of compound assignment if necessary, used result",
1287 \\#include <stdlib.h>
1288 \\int main(void) {
1289 \\ signed short foo;
1290 \\ signed short val = -1;
1291 \\ foo = (val += 1); if (foo != 0) abort();
1292 \\ foo = (val -= 1); if (foo != -1) abort();
1293 \\ foo = (val *= 2); if (foo != -2) abort();
1294 \\ foo = (val /= 2); if (foo != -1) abort();
1295 \\ foo = (val %= 2); if (foo != -1) abort();
1296 \\ foo = (val <<= 1); if (foo != -2) abort();
1297 \\ foo = (val >>= 1); if (foo != -1) abort();
1298 \\ foo = (val += 100000000); // compile error if @truncate() not inserted
1299 \\ unsigned short ufoo;
1300 \\ unsigned short uval = 1;
1301 \\ ufoo = (uval += 1); if (ufoo != 2) abort();
1302 \\ ufoo = (uval -= 1); if (ufoo != 1) abort();
1303 \\ ufoo = (uval *= 2); if (ufoo != 2) abort();
1304 \\ ufoo = (uval /= 2); if (ufoo != 1) abort();
1305 \\ ufoo = (uval %= 2); if (ufoo != 1) abort();
1306 \\ ufoo = (uval <<= 1); if (ufoo != 2) abort();
1307 \\ ufoo = (uval >>= 1); if (ufoo != 1) abort();
1308 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted
1309 \\}
1310 , "");
1261}1311}
test/translate_c.zig+2-2
...@@ -2766,7 +2766,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2766,7 +2766,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2766 \\ var a = arg_a;2766 \\ var a = arg_a;
2767 \\ var i: c_int = 0;2767 \\ var i: c_int = 0;
2768 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {2768 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
2769 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), 1);2769 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2770 \\ }2770 \\ }
2771 \\ return i;2771 \\ return i;
2772 \\}2772 \\}
...@@ -2786,7 +2786,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2786,7 +2786,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2786 \\ var a = arg_a;2786 \\ var a = arg_a;
2787 \\ var i: c_int = 0;2787 \\ var i: c_int = 0;
2788 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {2788 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
2789 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), 1);2789 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2790 \\ }2790 \\ }
2791 \\ return i;2791 \\ return i;
2792 \\}2792 \\}