authorgravatar for j@jadon.ioJadon Fowler <j@jadon.io> 2020-04-04 02:16:30-04:00
committergravatar for j@jadon.ioJadon Fowler <j@jadon.io> 2020-04-04 02:16:30-04:00
log391ee996a57873b7dfc0f72b3904051a6e1a6e8a
tree36f40bda2200b06e16406ae3fc7de3a8a5302432
parentb9cb1e0d837a9660b95a4476202baf1533614c9d

translate-c: account for signedness when translating div & mod

Signed-off-by: Jadon Fowler <j@jadon.io>

2 files changed, 90 insertions(+), 30 deletions(-)

src-self-hosted/translate_c.zig+64-18
...@@ -1170,7 +1170,7 @@ fn transBinaryOperator(...@@ -1170,7 +1170,7 @@ fn transBinaryOperator(
1170 }1170 }
1171 },1171 },
1172 .Div => {1172 .Div => {
1173 if (!cIsUnsignedInteger(qt)) {1173 if (cIsSignedInteger(qt)) {
1174 // signed integer division uses @divTrunc1174 // signed integer division uses @divTrunc
1175 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");1175 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
1176 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));1176 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
...@@ -1182,7 +1182,7 @@ fn transBinaryOperator(...@@ -1182,7 +1182,7 @@ fn transBinaryOperator(
1182 }1182 }
1183 },1183 },
1184 .Rem => {1184 .Rem => {
1185 if (!cIsUnsignedInteger(qt)) {1185 if (cIsSignedInteger(qt)) {
1186 // signed integer division uses @rem1186 // signed integer division uses @rem
1187 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");1187 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
1188 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));1188 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
...@@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign(...@@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign(
3048 used: ResultUsed,3048 used: ResultUsed,
3049) TransError!*ast.Node {3049) TransError!*ast.Node {
3050 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;3050 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
3051 const is_div = bin_op == .Div;
3052 const is_mod = bin_op == .Mod;
3051 const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);3053 const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
3052 const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);3054 const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
3053 const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);3055 const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
3056 const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs));
3054 if (used == .unused) {3057 if (used == .unused) {
3055 // common case3058 // common case
3056 // c: lhs += rhs3059 // c: lhs += rhs
3057 // zig: lhs += rhs3060 // zig: lhs += rhs
3061
3062 if ((is_mod or is_div) and is_signed) {
3063 const op_token = try appendToken(rp.c, .Equal, "=");
3064 const op_node = try rp.c.a().create(ast.Node.InfixOp);
3065 const builtin = if (is_mod) "@rem" else "@divTrunc";
3066 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
3067 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
3068 try builtin_node.params.push(lhs_node);
3069 _ = try appendToken(rp.c, .Comma, ",");
3070 try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
3071 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3072 op_node.* = .{
3073 .op_token = op_token,
3074 .lhs = lhs_node,
3075 .op = .Assign,
3076 .rhs = &builtin_node.base,
3077 };
3078 _ = try appendToken(rp.c, .Semicolon, ";");
3079 return &op_node.base;
3080 }
3081
3058 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3082 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
3059 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);3083 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
3060 var rhs_node = if (is_shift)3084 var rhs_node = if (is_shift)
...@@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign(...@@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign(
3097 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);3121 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3098 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);3122 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
3099 _ = try appendToken(rp.c, .Semicolon, ";");3123 _ = try appendToken(rp.c, .Semicolon, ";");
3100 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);3124
3101 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);3125 if ((is_mod or is_div) and is_signed) {
3102 if (is_shift) {3126 const op_token = try appendToken(rp.c, .Equal, "=");
3103 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");3127 const op_node = try rp.c.a().create(ast.Node.InfixOp);
3104 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);3128 const builtin = if (is_mod) "@rem" else "@divTrunc";
3105 try cast_node.params.push(rhs_type);3129 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
3130 try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node));
3106 _ = try appendToken(rp.c, .Comma, ",");3131 _ = try appendToken(rp.c, .Comma, ",");
3107 try cast_node.params.push(rhs_node);3132 try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
3108 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");3133 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3109 rhs_node = &cast_node.base;3134 _ = try appendToken(rp.c, .Semicolon, ";");
3110 }3135 op_node.* = .{
3111 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);3136 .op_token = op_token,
3137 .lhs = ref_node,
3138 .op = .Assign,
3139 .rhs = &builtin_node.base,
3140 };
3141 _ = try appendToken(rp.c, .Semicolon, ";");
3142 try block_scope.block_node.statements.push(&op_node.base);
3143 } else {
3144 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
3145 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
31123146
3113 _ = try appendToken(rp.c, .Semicolon, ";");3147 if (is_shift) {
3148 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
3149 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
3150 try cast_node.params.push(rhs_type);
3151 _ = try appendToken(rp.c, .Comma, ",");
3152 try cast_node.params.push(rhs_node);
3153 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3154 rhs_node = &cast_node.base;
3155 }
31143156
3115 const eq_token = try appendToken(rp.c, .Equal, "=");3157 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
3116 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);3158 _ = try appendToken(rp.c, .Semicolon, ";");
3117 try block_scope.block_node.statements.push(assign);3159
3160 const eq_token = try appendToken(rp.c, .Equal, "=");
3161 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
3162 try block_scope.block_node.statements.push(assign);
3163 }
31183164
3119 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);3165 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
3120 break_node.rhs = ref_node;3166 break_node.rhs = ref_node;
3121 try block_scope.block_node.statements.push(&break_node.base);3167 try block_scope.block_node.statements.push(&break_node.base);
3122 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");3168 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
3123 // semicolon must immediately follow rbrace because it is the last token in a block3169 // semicolon must immediately follow rbrace because it is the last token in a block
3124 _ = try appendToken(rp.c, .Semicolon, ";");3170 _ = try appendToken(rp.c, .Semicolon, ";4");
3125 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);3171 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
3126 grouped_expr.* = .{3172 grouped_expr.* = .{
3127 .lparen = try appendToken(rp.c, .LParen, "("),3173 .lparen = try appendToken(rp.c, .LParen, "("),
test/translate_c.zig+26-12
...@@ -2375,20 +2375,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2375,20 +2375,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2375 cases.add("compound assignment operators",2375 cases.add("compound assignment operators",
2376 \\void foo(void) {2376 \\void foo(void) {
2377 \\ int a = 0;2377 \\ int a = 0;
2378 \\ unsigned b = 0;
2378 \\ a += (a += 1);2379 \\ a += (a += 1);
2379 \\ a -= (a -= 1);2380 \\ a -= (a -= 1);
2380 \\ a *= (a *= 1);2381 \\ a *= (a *= 1);
2381 \\ a &= (a &= 1);2382 \\ a &= (a &= 1);
2382 \\ a |= (a |= 1);2383 \\ a |= (a |= 1);
2383 \\ a ^= (a ^= 1);2384 \\ a ^= (a ^= 1);
2384 \\ a /= (a /= 1);
2385 \\ a %= (a %= 1);
2386 \\ a >>= (a >>= 1);2385 \\ a >>= (a >>= 1);
2387 \\ a <<= (a <<= 1);2386 \\ a <<= (a <<= 1);
2387 \\ a /= (a /= 1);
2388 \\ a %= (a %= 1);
2389 \\ b /= (b /= 1);
2390 \\ b %= (b %= 1);
2388 \\}2391 \\}
2389 , &[_][]const u8{2392 , &[_][]const u8{
2390 \\pub export fn foo() void {2393 \\pub export fn foo() void {
2391 \\ var a: c_int = 0;2394 \\ var a: c_int = 0;
2395 \\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
2392 \\ a += (blk: {2396 \\ a += (blk: {
2393 \\ const ref = &a;2397 \\ const ref = &a;
2394 \\ ref.* = ref.* + @as(c_int, 1);2398 \\ ref.* = ref.* + @as(c_int, 1);
...@@ -2419,16 +2423,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2419,16 +2423,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2419 \\ ref.* = ref.* ^ @as(c_int, 1);2423 \\ ref.* = ref.* ^ @as(c_int, 1);
2420 \\ break :blk ref.*;2424 \\ break :blk ref.*;
2421 \\ });2425 \\ });
2422 \\ a /= (blk: {
2423 \\ const ref = &a;
2424 \\ ref.* = ref.* / @as(c_int, 1);
2425 \\ break :blk ref.*;
2426 \\ });
2427 \\ a %= (blk: {
2428 \\ const ref = &a;
2429 \\ ref.* = ref.* % @as(c_int, 1);
2430 \\ break :blk ref.*;
2431 \\ });
2432 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {2426 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
2433 \\ const ref = &a;2427 \\ const ref = &a;
2434 \\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));2428 \\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
...@@ -2439,6 +2433,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2439,6 +2433,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2439 \\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));2433 \\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2440 \\ break :blk ref.*;2434 \\ break :blk ref.*;
2441 \\ }));2435 \\ }));
2436 \\ a = @divTrunc(a, (blk: {
2437 \\ const ref = &a;
2438 \\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
2439 \\ break :blk ref.*;
2440 \\ }));
2441 \\ a = @rem(a, (blk: {
2442 \\ const ref = &a;
2443 \\ ref.* = @rem(ref.*, @as(c_int, 1));
2444 \\ break :blk ref.*;
2445 \\ }));
2446 \\ b /= (blk: {
2447 \\ const ref = &b;
2448 \\ ref.* = ref.* / @bitCast(c_uint, @as(c_int, 1));
2449 \\ break :blk ref.*;
2450 \\ });
2451 \\ b %= (blk: {
2452 \\ const ref = &b;
2453 \\ ref.* = ref.* % @bitCast(c_uint, @as(c_int, 1));
2454 \\ break :blk ref.*;
2455 \\ });
2442 \\}2456 \\}
2443 });2457 });
24442458