authorgravatar for kavika@gmail.comMerlyn Morgan-Graham <kavika@gmail.com> 2019-12-15 15:45:46-08:00
committergravatar for kavika@gmail.comMerlyn Morgan-Graham <kavika@gmail.com> 2019-12-16 01:34:04-08:00
logacff2d407b45519cc6dc24639dfe1289c899addd
tree3147268e7b53b4f9f16865f5be6b2304d1b6bcf1
parentc8c89648b0d98af07aad88a813a74ff650cf3bbe

Add bit shift binary ops in translate-c-2


2 files changed, 181 insertions(+), 10 deletions(-)

src-self-hosted/translate_c.zig+156-10
......@@ -575,6 +575,45 @@ fn transStmt(
575575 }
576576}
577577
578fn transCreateNodeShiftOp(
579 rp: RestorePoint,
580 scope: *Scope,
581 stmt: *const ZigClangBinaryOperator,
582 comptime op: ast.Node.InfixOp.Op,
583 comptime op_tok_id: std.zig.Token.Id,
584 comptime bytes: []const u8,
585) !*ast.Node {
586 if (!(op == .BitShiftLeft or op == .BitShiftRight)) {
587 @compileError("op must be either .BitShiftLeft or .BitShiftRight");
588 }
589
590 const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
591 const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
592 const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
593 // lhs >> u5(rh)
594
595 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
596 const op_token = try appendToken(rp.c, op_tok_id, bytes);
597
598 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
599 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
600 try as_node.params.push(rhs_type);
601 _ = try appendToken(rp.c, .Comma, ",");
602 const rhs = try transExpr(rp, scope, rhs_expr, .used, .l_value);
603 try as_node.params.push(rhs.node);
604 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
605
606 const node = try rp.c.a().create(ast.Node.InfixOp);
607 node.* = ast.Node.InfixOp{
608 .op_token = op_token,
609 .lhs = lhs.node,
610 .op = op,
611 .rhs = &as_node.base,
612 };
613
614 return &node.base;
615}
616
578617fn transBinaryOperator(
579618 rp: RestorePoint,
580619 scope: *Scope,
......@@ -679,15 +718,22 @@ fn transBinaryOperator(
679718 });
680719 }
681720 },
682 .Shl,
683 .Shr,
684 => return revertAndWarn(
685 rp,
686 error.UnsupportedTranslation,
687 ZigClangBinaryOperator_getBeginLoc(stmt),
688 "TODO: handle more C binary operators: {}",
689 .{op},
690 ),
721 .Shl => {
722 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
723 return maybeSuppressResult(rp, scope, result_used, TransResult{
724 .node = node,
725 .child_scope = scope,
726 .node_scope = scope,
727 });
728 },
729 .Shr => {
730 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
731 return maybeSuppressResult(rp, scope, result_used, TransResult{
732 .node = node,
733 .child_scope = scope,
734 .node_scope = scope,
735 });
736 },
691737 .LT => {
692738 const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessThan, .AngleBracketLeft, "<", true);
693739 return maybeSuppressResult(rp, scope, result_used, TransResult{
......@@ -1664,6 +1710,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
16641710 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
16651711}
16661712
1713fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 {
1714 const ty = ZigClangQualType_getTypePtr(qt);
1715
1716 switch (ZigClangType_getTypeClass(ty)) {
1717 .Builtin => {
1718 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1719
1720 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1721 .Char_U,
1722 .UChar,
1723 .Char_S,
1724 .SChar,
1725 => return 8,
1726 .UInt128,
1727 .Int128,
1728 => return 128,
1729 else => return 0,
1730 }
1731
1732 unreachable;
1733 },
1734 .Typedef => {
1735 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
1736 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
1737 const type_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
1738
1739 if (std.mem.eql(u8, type_name, "uint8_t") or std.mem.eql(u8, type_name, "int8_t")) {
1740 return 8;
1741 } else if (std.mem.eql(u8, type_name, "uint16_t") or std.mem.eql(u8, type_name, "int16_t")) {
1742 return 16;
1743 } else if (std.mem.eql(u8, type_name, "uint32_t") or std.mem.eql(u8, type_name, "int32_t")) {
1744 return 32;
1745 } else if (std.mem.eql(u8, type_name, "uint64_t") or std.mem.eql(u8, type_name, "int64_t")) {
1746 return 64;
1747 } else {
1748 return 0;
1749 }
1750 },
1751 else => return 0,
1752 }
1753
1754 unreachable;
1755}
1756
1757fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
1758 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
1759
1760 if (int_bit_width != 0) {
1761 // we can perform the log2 now.
1762 const cast_bit_width = std.math.log2_int(u64, int_bit_width);
1763 const node = try rp.c.a().create(ast.Node.IntegerLiteral);
1764 node.* = ast.Node.IntegerLiteral{
1765 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
1766 };
1767 return &node.base;
1768 }
1769
1770 const zig_type_node = try transQualType(rp, qt, source_loc);
1771
1772 // @import("std").math.Log2Int(c_long);
1773 //
1774 // FnCall
1775 // FieldAccess
1776 // FieldAccess
1777 // FnCall (.builtin = true)
1778 // Symbol "import"
1779 // StringLiteral "std"
1780 // Symbol "math"
1781 // Symbol "Log2Int"
1782 // Symbol <zig_type_node> (var from above)
1783
1784 const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import");
1785 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
1786 const std_node = try rp.c.a().create(ast.Node.StringLiteral);
1787 std_node.* = ast.Node.StringLiteral{
1788 .token = std_token,
1789 };
1790 try import_fn_call.params.push(&std_node.base);
1791 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
1792
1793 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
1794 const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int");
1795 const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base);
1796 try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node);
1797 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
1798
1799 return &log2int_fn_call.base;
1800}
1801
16671802fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
16681803 const ty = ZigClangQualType_getTypePtr(qt);
16691804
......@@ -1827,7 +1962,7 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
18271962 _ = try appendToken(c, .LParen, "(");
18281963 const node = try c.a().create(ast.Node.SuffixOp);
18291964 node.* = ast.Node.SuffixOp{
1830 .lhs = fn_expr,
1965 .lhs = .{ .node = fn_expr },
18311966 .op = ast.Node.SuffixOp.Op{
18321967 .Call = ast.Node.SuffixOp.Op.Call{
18331968 .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
......@@ -1839,6 +1974,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
18391974 return node;
18401975}
18411976
1977fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp {
1978 const field_access_node = try c.a().create(ast.Node.InfixOp);
1979 field_access_node.* = .{
1980 .op_token = try appendToken(c, .Period, "."),
1981 .lhs = container,
1982 .op = .Period,
1983 .rhs = try transCreateNodeIdentifier(c, field_name),
1984 };
1985 return field_access_node;
1986}
1987
18421988fn transCreateNodePrefixOp(
18431989 c: *Context,
18441990 op: ast.Node.PrefixOp.Op,
test/translate_c.zig+25
......@@ -1023,6 +1023,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
10231023 \\}
10241024 });
10251025
1026 cases.add_2("shift right with a fixed size type, no while", // TODO can fold this into "shift right assign with a fixed size type" once `while` and `>>=` and `uint32_t` are handled in translate-c-2
1027 \\#include <stdint.h>
1028 \\uint32_t some_func(uint32_t a) {
1029 \\ uint32_t b = a >> 1;
1030 \\ return b;
1031 \\}
1032 , &[_][]const u8{
1033 \\pub export fn some_func(a: uint32_t) uint32_t {
1034 \\ var b: uint32_t = a >> @as(u5, 1);
1035 \\ return b;
1036 \\}
1037 });
1038
10261039 cases.add("anonymous enum",
10271040 \\enum {
10281041 \\ One,
......@@ -1199,6 +1212,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11991212 \\}
12001213 });
12011214
1215 cases.add_2("bitshift, no parens", // TODO can fold this into "bitshift" once parens are preserved correctly in translate-c-2
1216 \\int foo(void) {
1217 \\ int a = (1 << 2);
1218 \\ return a >> 1;
1219 \\}
1220 , &[_][]const u8{
1221 \\pub export fn foo() c_int {
1222 \\ var a: c_int = 1 << @as(@import("std").math.Log2Int(c_int), 2);
1223 \\ return a >> @as(@import("std").math.Log2Int(c_int), 1);
1224 \\}
1225 });
1226
12021227 cases.addC("compound assignment operators",
12031228 \\void foo(void) {
12041229 \\ int a = 0;