diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 47933917b1..b5973786a3 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -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, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index bcf0ea01da..f347070eef 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -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); diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index a967362a8e..87970168e8 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -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; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 26dbb2d424..faf7958793 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -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); diff --git a/test/translate_c.zig b/test/translate_c.zig index 8d1fc90833..5e5eccb60d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -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 + \\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 - \\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 \\ @@ -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 + \\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; + \\ }); + \\} + }); }