translate-c-2 compound assign

This commit is contained in:
Vexu 2019-12-19 16:07:33 +02:00
parent 6cd402f1b4
commit f837c7c9cd
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
5 changed files with 559 additions and 233 deletions

View File

@ -1431,13 +1431,13 @@ pub const Node = struct {
AssignBitShiftRight,
AssignBitXor,
AssignDiv,
AssignMinus,
AssignMinusWrap,
AssignSub,
AssignSubWrap,
AssignMod,
AssignPlus,
AssignPlusWrap,
AssignTimes,
AssignTimesWarp,
AssignAdd,
AssignAddWrap,
AssignMult,
AssignMultWrap,
BangEqual,
BitAnd,
BitOr,
@ -1490,13 +1490,13 @@ pub const Node = struct {
Op.AssignBitShiftRight,
Op.AssignBitXor,
Op.AssignDiv,
Op.AssignMinus,
Op.AssignMinusWrap,
Op.AssignSub,
Op.AssignSubWrap,
Op.AssignMod,
Op.AssignPlus,
Op.AssignPlusWrap,
Op.AssignTimes,
Op.AssignTimesWarp,
Op.AssignAdd,
Op.AssignAddWrap,
Op.AssignMult,
Op.AssignMultWrap,
Op.BangEqual,
Op.BitAnd,
Op.BitOr,

View File

@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
const token = nextToken(it);
const op = switch (token.ptr.id) {
.AsteriskEqual => Op{ .AssignTimes = {} },
.AsteriskEqual => Op{ .AssignMult = {} },
.SlashEqual => Op{ .AssignDiv = {} },
.PercentEqual => Op{ .AssignMod = {} },
.PlusEqual => Op{ .AssignPlus = {} },
.MinusEqual => Op{ .AssignMinus = {} },
.PlusEqual => Op{ .AssignAdd = {} },
.MinusEqual => Op{ .AssignSub = {} },
.AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },
.AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },
.AmpersandEqual => Op{ .AssignBitAnd = {} },
.CaretEqual => Op{ .AssignBitXor = {} },
.PipeEqual => Op{ .AssignBitOr = {} },
.AsteriskPercentEqual => Op{ .AssignTimesWarp = {} },
.PlusPercentEqual => Op{ .AssignPlusWrap = {} },
.MinusPercentEqual => Op{ .AssignMinusWrap = {} },
.AsteriskPercentEqual => Op{ .AssignMultWrap = {} },
.PlusPercentEqual => Op{ .AssignAddWrap = {} },
.MinusPercentEqual => Op{ .AssignSubWrap = {} },
.Equal => Op{ .Assign = {} },
else => {
putBackToken(it, token.index);

View File

@ -1120,3 +1120,11 @@ pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigC
pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType;
pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr;
pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation;
pub extern fn ZigClangCompoundAssignOperator_getType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
pub extern fn ZigClangCompoundAssignOperator_getComputationLHSType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
pub extern fn ZigClangCompoundAssignOperator_getComputationResultType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
pub extern fn ZigClangCompoundAssignOperator_getBeginLoc(*const ZigClangCompoundAssignOperator) ZigClangSourceLocation;
pub extern fn ZigClangCompoundAssignOperator_getOpcode(*const ZigClangCompoundAssignOperator) ZigClangBO;
pub extern fn ZigClangCompoundAssignOperator_getLHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;
pub extern fn ZigClangCompoundAssignOperator_getRHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;

View File

@ -898,6 +898,7 @@ fn transStmt(
.CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
.UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),
.UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used),
.CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used),
else => {
return revertAndWarn(
rp,
@ -2178,21 +2179,21 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
switch (ZigClangUnaryOperator_getOpcode(stmt)) {
.PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
return transCreatePostCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
else
return transCreatePostCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
.PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
return transCreatePostCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
else
return transCreatePostCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
.PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
return transCreatePreCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
else
return transCreatePreCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
.PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
return transCreatePreCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
else
return transCreatePreCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
.AddrOf => {
const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
@ -2232,7 +2233,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
return &op_node.base;
},
else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Real", .{}),
else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "unsupported C translation {}", .{ZigClangUnaryOperator_getOpcode(stmt)}),
}
}
@ -2353,13 +2354,129 @@ fn transCreatePostCrement(
try block_scope.block_node.statements.push(assign);
const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
break_node.rhs = try transCreateNodeIdentifier(rp.c,tmp);
break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
try block_scope.block_node.statements.push(&break_node.base);
_ = try appendToken(rp.c, .Semicolon, ";");
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block_scope.block_node.base;
}
fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {
.MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
return transCreateCompoundAssign(rp, scope, stmt, .AssignMultWrap, .AsteriskPercentEqual, "*%=", .MultWrap, .AsteriskPercent, "*%", used)
else
return transCreateCompoundAssign(rp, scope, stmt, .AssignMult, .AsteriskEqual, "*=", .Mult, .Asterisk, "*", used),
.AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
else
return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
.SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
else
return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
.ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),
.ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),
.AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),
.XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),
.OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),
else => return revertAndWarn(
rp,
error.UnsupportedTranslation,
ZigClangCompoundAssignOperator_getBeginLoc(stmt),
"unsupported C translation {}",
.{ZigClangCompoundAssignOperator_getOpcode(stmt)},
),
}
}
fn transCreateCompoundAssign(
rp: RestorePoint,
scope: *Scope,
stmt: *const ZigClangCompoundAssignOperator,
assign_op: ast.Node.InfixOp.Op,
assign_tok_id: std.zig.Token.Id,
assign_bytes: []const u8,
bin_op: ast.Node.InfixOp.Op,
bin_tok_id: std.zig.Token.Id,
bin_bytes: []const u8,
used: ResultUsed,
) TransError!*ast.Node {
const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
if (used == .unused) {
// common case
// c: lhs += rhs
// zig: lhs += rhs
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 = try transExpr(rp, scope, rhs, .used, .r_value);
if (is_shift) {
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
try as_node.params.push(rhs_type);
_ = try appendToken(rp.c, .Comma, ",");
try as_node.params.push(rhs_node);
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
rhs_node = &as_node.base;
}
if (scope.id != .Condition)
_ = try appendToken(rp.c, .Semicolon, ";");
return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
}
// worst case
// c: lhs += rhs
// zig: (blk: {
// zig: const _ref = &lhs;
// zig: _ref.* = _ref.* + rhs;
// zig: break :blk _ref.*
// zig: })
const block_scope = try Scope.Block.init(rp.c, scope, "blk");
block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()});
const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
node.eq_token = try appendToken(rp.c, .Equal, "=");
const addr_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
node.init_node = &addr_node.base;
node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
try block_scope.block_node.statements.push(&node.base);
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 as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
try as_node.params.push(rhs_type);
_ = try appendToken(rp.c, .Comma, ",");
try as_node.params.push(rhs_node);
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
rhs_node = &as_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 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, ";");
return &block_scope.block_node.base;
}
fn transCPtrCast(
rp: RestorePoint,
loc: ZigClangSourceLocation,
@ -2585,7 +2702,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access);
try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node);
try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node);
log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
return &log2int_fn_call.base;
@ -3317,7 +3434,7 @@ fn transCreateNodeShiftOp(
const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
// lhs >> u5(rh)
// lhs >> @as(u5, rh)
const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
const op_token = try appendToken(rp.c, op_tok_id, bytes);

View File

@ -1830,6 +1830,207 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add_2("shift right assign",
\\int log2(unsigned a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{// TODO function arguments should be copied
\\pub export fn log2(a: c_uint) c_int {
\\ var i: c_int = 0;
\\ while ((a > @as(c_uint, 0))) {
\\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
\\ }
\\ return i;
\\}
});
cases.add_2("shift right assign with a fixed size type",
\\#include <stdint.h>
\\int log2(uint32_t a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{
\\pub export fn log2(a: u32) c_int {
\\ var i: c_int = 0;
\\ while ((a > @as(c_uint, 0))) {
\\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
\\ }
\\ return i;
\\}
});
cases.add_2("compound assignment operators",
\\void foo(void) {
\\ int a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_int = 0;
\\ a += (blk: {
\\ const _ref_1 = &a;
\\ _ref_1.* = _ref_1.* + 1;
\\ break :blk _ref_1.*;
\\ });
\\ a -= (blk: {
\\ const _ref_2 = &a;
\\ _ref_2.* = _ref_2.* - 1;
\\ break :blk _ref_2.*;
\\ });
\\ a *= (blk: {
\\ const _ref_3 = &a;
\\ _ref_3.* = _ref_3.* * 1;
\\ break :blk _ref_3.*;
\\ });
\\ a &= (blk: {
\\ const _ref_4 = &a;
\\ _ref_4.* = _ref_4.* & 1;
\\ break :blk _ref_4.*;
\\ });
\\ a |= (blk: {
\\ const _ref_5 = &a;
\\ _ref_5.* = _ref_5.* | 1;
\\ break :blk _ref_5.*;
\\ });
\\ a ^= (blk: {
\\ const _ref_6 = &a;
\\ _ref_6.* = _ref_6.* ^ 1;
\\ break :blk _ref_6.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
\\ const _ref_7 = &a;
\\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
\\ break :blk _ref_7.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
\\ const _ref_8 = &a;
\\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
\\ break :blk _ref_8.*;
\\ }));
\\}
});
cases.add_2("compound assignment operators unsigned",
\\void foo(void) {
\\ unsigned a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_uint = @as(c_uint, 0);
\\ a +%= (blk: {
\\ const _ref_1 = &a;
\\ _ref_1.* = _ref_1.* +% @as(c_uint, 1);
\\ break :blk _ref_1.*;
\\ });
\\ a -%= (blk: {
\\ const _ref_2 = &a;
\\ _ref_2.* = _ref_2.* -% @as(c_uint, 1);
\\ break :blk _ref_2.*;
\\ });
\\ a *%= (blk: {
\\ const _ref_3 = &a;
\\ _ref_3.* = _ref_3.* *% @as(c_uint, 1);
\\ break :blk _ref_3.*;
\\ });
\\ a &= (blk: {
\\ const _ref_4 = &a;
\\ _ref_4.* = _ref_4.* & @as(c_uint, 1);
\\ break :blk _ref_4.*;
\\ });
\\ a |= (blk: {
\\ const _ref_5 = &a;
\\ _ref_5.* = _ref_5.* | @as(c_uint, 1);
\\ break :blk _ref_5.*;
\\ });
\\ a ^= (blk: {
\\ const _ref_6 = &a;
\\ _ref_6.* = _ref_6.* ^ @as(c_uint, 1);
\\ break :blk _ref_6.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
\\ const _ref_7 = &a;
\\ _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
\\ break :blk _ref_7.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
\\ const _ref_8 = &a;
\\ _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
\\ break :blk _ref_8.*;
\\ }));
\\}
});
cases.add_2("post increment/decrement",
\\void foo(void) {
\\ int i = 0;
\\ unsigned u = 0;
\\ i++;
\\ i--;
\\ u++;
\\ u--;
\\ i = i++;
\\ i = i--;
\\ u = u++;
\\ u = u--;
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var i: c_int = 0;
\\ var u: c_uint = @as(c_uint, 0);
\\ i += 1;
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = blk: {
\\ const _ref_1 = &i;
\\ const _tmp_2 = _ref_1.*;
\\ _ref_1.* += 1;
\\ break :blk _tmp_2;
\\ };
\\ i = blk: {
\\ const _ref_3 = &i;
\\ const _tmp_4 = _ref_3.*;
\\ _ref_3.* -= 1;
\\ break :blk _tmp_4;
\\ };
\\ u = blk: {
\\ const _ref_5 = &u;
\\ const _tmp_6 = _ref_5.*;
\\ _ref_5.* +%= 1;
\\ break :blk _tmp_6;
\\ };
\\ u = blk: {
\\ const _ref_7 = &u;
\\ const _tmp_8 = _ref_7.*;
\\ _ref_7.* -%= 1;
\\ break :blk _tmp_8;
\\ };
\\}
});
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
cases.add("macro defines string literal with hex",
@ -1856,45 +2057,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const FOO_CHAR = 63;
});
cases.addC("shift right assign",
\\int log2(unsigned a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{
\\pub export fn log2(_arg_a: c_uint) c_int {
\\ var a = _arg_a;
\\ var i: c_int = 0;
\\ while (a > @as(c_uint, 0)) {
\\ a >>= @as(@import("std").math.Log2Int(c_uint), 1);
\\ }
\\ return i;
\\}
});
cases.addC("shift right assign with a fixed size type",
\\#include <stdint.h>
\\int log2(uint32_t a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{
\\pub export fn log2(_arg_a: u32) c_int {
\\ var a = _arg_a;
\\ var i: c_int = 0;
\\ while (a > @as(c_uint, 0)) {
\\ a >>= @as(u5, 1);
\\ }
\\ return i;
\\}
});
cases.addC("__extension__ cast",
\\int foo(void) {
\\ return __extension__ 1;
@ -1905,170 +2067,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.addC("compound assignment operators",
\\void foo(void) {
\\ int a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_int = 0;
\\ a += (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* + 1);
\\ break :x _ref.*;
\\ });
\\ a -= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* - 1);
\\ break :x _ref.*;
\\ });
\\ a *= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* * 1);
\\ break :x _ref.*;
\\ });
\\ a &= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* & 1);
\\ break :x _ref.*;
\\ });
\\ a |= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* | 1);
\\ break :x _ref.*;
\\ });
\\ a ^= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* ^ 1);
\\ break :x _ref.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_int), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
\\ break :x _ref.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_int), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
\\ break :x _ref.*;
\\ }));
\\}
});
cases.addC("compound assignment operators unsigned",
\\void foo(void) {
\\ unsigned a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_uint = @as(c_uint, 0);
\\ a +%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* +% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a -%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* -% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a *%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* *% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a &= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* & @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a |= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* | @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a ^= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* ^ @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
\\ break :x _ref.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
\\ break :x _ref.*;
\\ }));
\\}
});
cases.addC("post increment/decrement",
\\void foo(void) {
\\ int i = 0;
\\ unsigned u = 0;
\\ i++;
\\ i--;
\\ u++;
\\ u--;
\\ i = i++;
\\ i = i--;
\\ u = u++;
\\ u = u--;
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var i: c_int = 0;
\\ var u: c_uint = @as(c_uint, 0);
\\ i += 1;
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = (x: {
\\ const _ref = &i;
\\ const _tmp = _ref.*;
\\ _ref.* += 1;
\\ break :x _tmp;
\\ });
\\ i = (x: {
\\ const _ref = &i;
\\ const _tmp = _ref.*;
\\ _ref.* -= 1;
\\ break :x _tmp;
\\ });
\\ u = (x: {
\\ const _ref = &u;
\\ const _tmp = _ref.*;
\\ _ref.* +%= 1;
\\ break :x _tmp;
\\ });
\\ u = (x: {
\\ const _ref = &u;
\\ const _tmp = _ref.*;
\\ _ref.* -%= 1;
\\ break :x _tmp;
\\ });
\\}
});
cases.addC("implicit casts",
\\#include <stdbool.h>
\\
@ -2789,4 +2787,207 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ });
\\}
});
cases.addC("shift right assign",
\\int log2(unsigned a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{
\\pub export fn log2(_arg_a: c_uint) c_int {
\\ var a = _arg_a;
\\ var i: c_int = 0;
\\ while (a > @as(c_uint, 0)) {
\\ a >>= @as(@import("std").math.Log2Int(c_uint), 1);
\\ }
\\ return i;
\\}
});
cases.addC("shift right assign with a fixed size type",
\\#include <stdint.h>
\\int log2(uint32_t a) {
\\ int i = 0;
\\ while (a > 0) {
\\ a >>= 1;
\\ }
\\ return i;
\\}
, &[_][]const u8{
\\pub export fn log2(_arg_a: u32) c_int {
\\ var a = _arg_a;
\\ var i: c_int = 0;
\\ while (a > @as(c_uint, 0)) {
\\ a >>= @as(u5, 1);
\\ }
\\ return i;
\\}
});
cases.addC("compound assignment operators",
\\void foo(void) {
\\ int a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_int = 0;
\\ a += (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* + 1);
\\ break :x _ref.*;
\\ });
\\ a -= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* - 1);
\\ break :x _ref.*;
\\ });
\\ a *= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* * 1);
\\ break :x _ref.*;
\\ });
\\ a &= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* & 1);
\\ break :x _ref.*;
\\ });
\\ a |= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* | 1);
\\ break :x _ref.*;
\\ });
\\ a ^= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* ^ 1);
\\ break :x _ref.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_int), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
\\ break :x _ref.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_int), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
\\ break :x _ref.*;
\\ }));
\\}
});
cases.addC("compound assignment operators unsigned",
\\void foo(void) {
\\ unsigned a = 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);
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_uint = @as(c_uint, 0);
\\ a +%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* +% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a -%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* -% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a *%= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* *% @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a &= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* & @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a |= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* | @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a ^= (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* ^ @as(c_uint, 1));
\\ break :x _ref.*;
\\ });
\\ a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
\\ break :x _ref.*;
\\ }));
\\ a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
\\ const _ref = &a;
\\ _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
\\ break :x _ref.*;
\\ }));
\\}
});
cases.addC("post increment/decrement",
\\void foo(void) {
\\ int i = 0;
\\ unsigned u = 0;
\\ i++;
\\ i--;
\\ u++;
\\ u--;
\\ i = i++;
\\ i = i--;
\\ u = u++;
\\ u = u--;
\\}
, &[_][]const u8{
\\pub export fn foo() void {
\\ var i: c_int = 0;
\\ var u: c_uint = @as(c_uint, 0);
\\ i += 1;
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = (x: {
\\ const _ref = &i;
\\ const _tmp = _ref.*;
\\ _ref.* += 1;
\\ break :x _tmp;
\\ });
\\ i = (x: {
\\ const _ref = &i;
\\ const _tmp = _ref.*;
\\ _ref.* -= 1;
\\ break :x _tmp;
\\ });
\\ u = (x: {
\\ const _ref = &u;
\\ const _tmp = _ref.*;
\\ _ref.* +%= 1;
\\ break :x _tmp;
\\ });
\\ u = (x: {
\\ const _ref = &u;
\\ const _tmp = _ref.*;
\\ _ref.* -%= 1;
\\ break :x _tmp;
\\ });
\\}
});
}