translate-c: account for signedness when translating div & mod
Signed-off-by: Jadon Fowler <j@jadon.io>
This commit is contained in:
parent
b9cb1e0d83
commit
391ee996a5
|
@ -1170,7 +1170,7 @@ fn transBinaryOperator(
|
|||
}
|
||||
},
|
||||
.Div => {
|
||||
if (!cIsUnsignedInteger(qt)) {
|
||||
if (cIsSignedInteger(qt)) {
|
||||
// signed integer division uses @divTrunc
|
||||
const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
|
||||
try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
|
||||
|
@ -1182,7 +1182,7 @@ fn transBinaryOperator(
|
|||
}
|
||||
},
|
||||
.Rem => {
|
||||
if (!cIsUnsignedInteger(qt)) {
|
||||
if (cIsSignedInteger(qt)) {
|
||||
// signed integer division uses @rem
|
||||
const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
|
||||
try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
|
||||
|
@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign(
|
|||
used: ResultUsed,
|
||||
) TransError!*ast.Node {
|
||||
const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
|
||||
const is_div = bin_op == .Div;
|
||||
const is_mod = bin_op == .Mod;
|
||||
const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
|
||||
const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
|
||||
const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
|
||||
const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs));
|
||||
if (used == .unused) {
|
||||
// common case
|
||||
// c: lhs += rhs
|
||||
// zig: lhs += rhs
|
||||
|
||||
if ((is_mod or is_div) and is_signed) {
|
||||
const op_token = try appendToken(rp.c, .Equal, "=");
|
||||
const op_node = try rp.c.a().create(ast.Node.InfixOp);
|
||||
const builtin = if (is_mod) "@rem" else "@divTrunc";
|
||||
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
|
||||
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||
try builtin_node.params.push(lhs_node);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
|
||||
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
op_node.* = .{
|
||||
.op_token = op_token,
|
||||
.lhs = lhs_node,
|
||||
.op = .Assign,
|
||||
.rhs = &builtin_node.base,
|
||||
};
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &op_node.base;
|
||||
}
|
||||
|
||||
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||
const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
|
||||
var rhs_node = if (is_shift)
|
||||
|
@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign(
|
|||
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
||||
const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
|
||||
var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
|
||||
if (is_shift) {
|
||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
|
||||
const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
|
||||
try cast_node.params.push(rhs_type);
|
||||
|
||||
if ((is_mod or is_div) and is_signed) {
|
||||
const op_token = try appendToken(rp.c, .Equal, "=");
|
||||
const op_node = try rp.c.a().create(ast.Node.InfixOp);
|
||||
const builtin = if (is_mod) "@rem" else "@divTrunc";
|
||||
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin);
|
||||
try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node));
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try cast_node.params.push(rhs_node);
|
||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
rhs_node = &cast_node.base;
|
||||
try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
|
||||
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
op_node.* = .{
|
||||
.op_token = op_token,
|
||||
.lhs = ref_node,
|
||||
.op = .Assign,
|
||||
.rhs = &builtin_node.base,
|
||||
};
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
try block_scope.block_node.statements.push(&op_node.base);
|
||||
} else {
|
||||
const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
|
||||
var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
|
||||
|
||||
if (is_shift) {
|
||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
|
||||
const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
|
||||
try cast_node.params.push(rhs_type);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try cast_node.params.push(rhs_node);
|
||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
rhs_node = &cast_node.base;
|
||||
}
|
||||
|
||||
const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
|
||||
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||
const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
|
||||
try block_scope.block_node.statements.push(assign);
|
||||
}
|
||||
const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
|
||||
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
|
||||
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||
const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
|
||||
try block_scope.block_node.statements.push(assign);
|
||||
|
||||
const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
|
||||
break_node.rhs = ref_node;
|
||||
try block_scope.block_node.statements.push(&break_node.base);
|
||||
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
|
||||
// semicolon must immediately follow rbrace because it is the last token in a block
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
_ = try appendToken(rp.c, .Semicolon, ";4");
|
||||
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
|
||||
grouped_expr.* = .{
|
||||
.lparen = try appendToken(rp.c, .LParen, "("),
|
||||
|
|
|
@ -2375,20 +2375,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||
cases.add("compound assignment operators",
|
||||
\\void foo(void) {
|
||||
\\ int a = 0;
|
||||
\\ unsigned b = 0;
|
||||
\\ a += (a += 1);
|
||||
\\ a -= (a -= 1);
|
||||
\\ a *= (a *= 1);
|
||||
\\ a &= (a &= 1);
|
||||
\\ a |= (a |= 1);
|
||||
\\ a ^= (a ^= 1);
|
||||
\\ a /= (a /= 1);
|
||||
\\ a %= (a %= 1);
|
||||
\\ a >>= (a >>= 1);
|
||||
\\ a <<= (a <<= 1);
|
||||
\\ a /= (a /= 1);
|
||||
\\ a %= (a %= 1);
|
||||
\\ b /= (b /= 1);
|
||||
\\ b %= (b %= 1);
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_int = 0;
|
||||
\\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
|
||||
\\ a += (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* + @as(c_int, 1);
|
||||
|
@ -2419,16 +2423,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||
\\ ref.* = ref.* ^ @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a /= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* / @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a %= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* % @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
|
@ -2439,6 +2433,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||
\\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\ a = @divTrunc(a, (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\ a = @rem(a, (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = @rem(ref.*, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\ b /= (blk: {
|
||||
\\ const ref = &b;
|
||||
\\ ref.* = ref.* / @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ b %= (blk: {
|
||||
\\ const ref = &b;
|
||||
\\ ref.* = ref.* % @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user