| author | |
| committer | |
| log | ab9324e604068d4afb4e65a8e587bea95ab1051a |
| tree | 14ea94d51adb927951236e5deb883e90774fefe6 |
| parent | c8d721aa429ae492a10bc3d21ed5487ad620a032 |
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 | 3197 | const requires_int_cast = blk: { |
| 3198 | 3198 | const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt); |
| 3199 | 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 | 3203 | if (used == .unused) { |
| 3203 | 3204 | // common case |
| 3204 | 3205 | // c: lhs += rhs |
| 3205 | 3206 | // 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 | 3211 | if ((is_mod or is_div) and is_signed) { |
| 3207 | const lhs_node = try transExpr(c, scope, lhs, .used); | |
| 3208 | const rhs_node = try transExpr(c, scope, rhs, .used); | |
| 3212 | if (requires_int_cast) rhs_node = try transCCast(c, scope, loc, lhs_qt, rhs_qt, rhs_node); | |
| 3213 | const operands = .{ .lhs = lhs_node, .rhs = rhs_node }; | |
| 3209 | 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 | 3216 | else |
| 3212 | try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); | |
| 3217 | try Tag.div_trunc.create(c.arena, operands); | |
| 3213 | 3218 | |
| 3214 | 3219 | return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); |
| 3215 | 3220 | } |
| 3216 | 3221 | |
| 3217 | const lhs_node = try transExpr(c, scope, lhs, .used); | |
| 3218 | var rhs_node = if (is_shift or requires_int_cast) | |
| 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 | ||
| 3222 | if (is_shift) { | |
| 3223 | const cast_to_type = try qualTypeToLog2IntRef(c, scope, rhs_qt, loc); | |
| 3234 | 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 | 3228 | return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used); |
| 3238 | 3229 | } |
| 3239 | 3230 | // worst case |
| ... | ... | @@ -3255,29 +3246,24 @@ fn transCreateCompoundAssign( |
| 3255 | 3246 | const lhs_node = try Tag.identifier.create(c.arena, ref); |
| 3256 | 3247 | const ref_node = try Tag.deref.create(c.arena, lhs_node); |
| 3257 | 3248 | |
| 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 | 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 | 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 | 3256 | else |
| 3263 | try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node }); | |
| 3257 | try Tag.div_trunc.create(c.arena, operands); | |
| 3264 | 3258 | |
| 3265 | 3259 | const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used); |
| 3266 | 3260 | try block_scope.statements.append(assign); |
| 3267 | 3261 | } else { |
| 3268 | var rhs_node = try transExpr(c, &block_scope.base, rhs, .used); | |
| 3269 | ||
| 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 | ||
| 3262 | if (is_shift) { | |
| 3263 | const cast_to_type = try qualTypeToLog2IntRef(c, &block_scope.base, rhs_qt, loc); | |
| 3277 | 3264 | rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); |
| 3278 | } | |
| 3279 | if (is_ptr_op_signed) { | |
| 3280 | rhs_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); | |
| 3265 | } else if (requires_int_cast) { | |
| 3266 | rhs_node = try transCCast(c, &block_scope.base, loc, lhs_qt, rhs_qt, rhs_node); | |
| 3281 | 3267 | } |
| 3282 | 3268 | |
| 3283 | 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 | 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 | 2766 | \\ var a = arg_a; |
| 2767 | 2767 | \\ var i: c_int = 0; |
| 2768 | 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 | 2771 | \\ return i; |
| 2772 | 2772 | \\} |
| ... | ... | @@ -2786,7 +2786,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2786 | 2786 | \\ var a = arg_a; |
| 2787 | 2787 | \\ var i: c_int = 0; |
| 2788 | 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 | 2791 | \\ return i; |
| 2792 | 2792 | \\} |