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(
11701170 }
11711171 },
11721172 .Div => {
1173 if (!cIsUnsignedInteger(qt)) {
1173 if (cIsSignedInteger(qt)) {
11741174 // signed integer division uses @divTrunc
11751175 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
11761176 try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
......@@ -1182,7 +1182,7 @@ fn transBinaryOperator(
11821182 }
11831183 },
11841184 .Rem => {
1185 if (!cIsUnsignedInteger(qt)) {
1185 if (cIsSignedInteger(qt)) {
11861186 // signed integer division uses @rem
11871187 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
11881188 try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
......@@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign(
30483048 used: ResultUsed,
30493049) TransError!*ast.Node {
30503050 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
3051 const is_div = bin_op == .Div;
3052 const is_mod = bin_op == .Mod;
30513053 const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
30523054 const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
30533055 const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
3056 const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs));
30543057 if (used == .unused) {
30553058 // common case
30563059 // c: lhs += rhs
30573060 // 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
30583082 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
30593083 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
30603084 var rhs_node = if (is_shift)
......@@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign(
30973121 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
30983122 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
30993123 _ = try appendToken(rp.c, .Semicolon, ";");
3100 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
3101 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
3102 if (is_shift) {
3103 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
3104 const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
3105 try cast_node.params.push(rhs_type);
3124
3125 if ((is_mod or is_div) and is_signed) {
3126 const op_token = try appendToken(rp.c, .Equal, "=");
3127 const op_node = try rp.c.a().create(ast.Node.InfixOp);
3128 const builtin = if (is_mod) "@rem" else "@divTrunc";
3129 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
3130 try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node));
31063131 _ = try appendToken(rp.c, .Comma, ",");
3107 try cast_node.params.push(rhs_node);
3108 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3109 rhs_node = &cast_node.base;
3110 }
3111 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
3132 try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
3133 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3134 _ = try appendToken(rp.c, .Semicolon, ";");
3135 op_node.* = .{
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, "=");
3116 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
3117 try block_scope.block_node.statements.push(assign);
3157 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
3158 _ = try appendToken(rp.c, .Semicolon, ";");
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
31193165 const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
31203166 break_node.rhs = ref_node;
31213167 try block_scope.block_node.statements.push(&break_node.base);
31223168 block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
31233169 // 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");
31253171 const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
31263172 grouped_expr.* = .{
31273173 .lparen = try appendToken(rp.c, .LParen, "("),
test/translate_c.zig+26-12
......@@ -2375,20 +2375,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
23752375 cases.add("compound assignment operators",
23762376 \\void foo(void) {
23772377 \\ int a = 0;
2378 \\ unsigned b = 0;
23782379 \\ a += (a += 1);
23792380 \\ a -= (a -= 1);
23802381 \\ a *= (a *= 1);
23812382 \\ a &= (a &= 1);
23822383 \\ a |= (a |= 1);
23832384 \\ a ^= (a ^= 1);
2384 \\ a /= (a /= 1);
2385 \\ a %= (a %= 1);
23862385 \\ a >>= (a >>= 1);
23872386 \\ a <<= (a <<= 1);
2387 \\ a /= (a /= 1);
2388 \\ a %= (a %= 1);
2389 \\ b /= (b /= 1);
2390 \\ b %= (b %= 1);
23882391 \\}
23892392 , &[_][]const u8{
23902393 \\pub export fn foo() void {
23912394 \\ var a: c_int = 0;
2395 \\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
23922396 \\ a += (blk: {
23932397 \\ const ref = &a;
23942398 \\ ref.* = ref.* + @as(c_int, 1);
......@@ -2419,16 +2423,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
24192423 \\ ref.* = ref.* ^ @as(c_int, 1);
24202424 \\ break :blk ref.*;
24212425 \\ });
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 \\ });
24322426 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
24332427 \\ const ref = &a;
24342428 \\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
......@@ -2439,6 +2433,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
24392433 \\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
24402434 \\ break :blk ref.*;
24412435 \\ }));
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 \\ });
24422456 \\}
24432457 });
24442458