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 => {
|
.Div => {
|
||||||
if (!cIsUnsignedInteger(qt)) {
|
if (cIsSignedInteger(qt)) {
|
||||||
// signed integer division uses @divTrunc
|
// signed integer division uses @divTrunc
|
||||||
const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@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));
|
try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
|
||||||
@ -1182,7 +1182,7 @@ fn transBinaryOperator(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Rem => {
|
.Rem => {
|
||||||
if (!cIsUnsignedInteger(qt)) {
|
if (cIsSignedInteger(qt)) {
|
||||||
// signed integer division uses @rem
|
// signed integer division uses @rem
|
||||||
const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
|
const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
|
||||||
try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
|
try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
|
||||||
@ -3048,13 +3048,37 @@ fn transCreateCompoundAssign(
|
|||||||
used: ResultUsed,
|
used: ResultUsed,
|
||||||
) TransError!*ast.Node {
|
) TransError!*ast.Node {
|
||||||
const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
|
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 lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
|
||||||
const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
|
const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
|
||||||
const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
|
const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
|
||||||
|
const is_signed = cIsSignedInteger(getExprQualType(rp.c, lhs));
|
||||||
if (used == .unused) {
|
if (used == .unused) {
|
||||||
// common case
|
// common case
|
||||||
// c: lhs += rhs
|
// c: lhs += rhs
|
||||||
// zig: 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 lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||||
const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
|
const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
|
||||||
var rhs_node = if (is_shift)
|
var rhs_node = if (is_shift)
|
||||||
@ -3097,31 +3121,53 @@ fn transCreateCompoundAssign(
|
|||||||
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
|
||||||
const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
|
const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
|
||||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
_ = 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_mod or is_div) and is_signed) {
|
||||||
if (is_shift) {
|
const op_token = try appendToken(rp.c, .Equal, "=");
|
||||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
|
const op_node = try rp.c.a().create(ast.Node.InfixOp);
|
||||||
const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
|
const builtin = if (is_mod) "@rem" else "@divTrunc";
|
||||||
try cast_node.params.push(rhs_type);
|
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 appendToken(rp.c, .Comma, ",");
|
||||||
try cast_node.params.push(rhs_node);
|
try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value));
|
||||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||||
rhs_node = &cast_node.base;
|
_ = 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);
|
const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
|
||||||
break_node.rhs = ref_node;
|
break_node.rhs = ref_node;
|
||||||
try block_scope.block_node.statements.push(&break_node.base);
|
try block_scope.block_node.statements.push(&break_node.base);
|
||||||
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
|
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
|
||||||
// semicolon must immediately follow rbrace because it is the last token in a block
|
// 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);
|
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
|
||||||
grouped_expr.* = .{
|
grouped_expr.* = .{
|
||||||
.lparen = try appendToken(rp.c, .LParen, "("),
|
.lparen = try appendToken(rp.c, .LParen, "("),
|
||||||
|
@ -2375,20 +2375,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
cases.add("compound assignment operators",
|
cases.add("compound assignment operators",
|
||||||
\\void foo(void) {
|
\\void foo(void) {
|
||||||
\\ int a = 0;
|
\\ 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);
|
||||||
\\ 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{
|
, &[_][]const u8{
|
||||||
\\pub export fn foo() void {
|
\\pub export fn foo() void {
|
||||||
\\ var a: c_int = 0;
|
\\ var a: c_int = 0;
|
||||||
|
\\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
|
||||||
\\ a += (blk: {
|
\\ a += (blk: {
|
||||||
\\ const ref = &a;
|
\\ const ref = &a;
|
||||||
\\ ref.* = ref.* + @as(c_int, 1);
|
\\ ref.* = ref.* + @as(c_int, 1);
|
||||||
@ -2419,16 +2423,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
|||||||
\\ ref.* = ref.* ^ @as(c_int, 1);
|
\\ ref.* = ref.* ^ @as(c_int, 1);
|
||||||
\\ break :blk ref.*;
|
\\ 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: {
|
\\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
|
||||||
\\ const ref = &a;
|
\\ const ref = &a;
|
||||||
\\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
\\ 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));
|
\\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||||
\\ break :blk ref.*;
|
\\ 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…
x
Reference in New Issue
Block a user