| ... | ... | @@ -112,11 +112,7 @@ const ValueRenderLocation = enum { |
| 112 | 112 | } |
| 113 | 113 | }; |
| 114 | 114 | |
| 115 | | const BuiltinInfo = enum { |
| 116 | | None, |
| 117 | | Range, |
| 118 | | Bits, |
| 119 | | }; |
| 115 | const BuiltinInfo = enum { none, bits }; |
| 120 | 116 | |
| 121 | 117 | const reserved_idents = std.ComptimeStringMap(void, .{ |
| 122 | 118 | // C language |
| ... | ... | @@ -440,6 +436,10 @@ pub const Function = struct { |
| 440 | 436 | return f.object.dg.typeToCType(ty, kind); |
| 441 | 437 | } |
| 442 | 438 | |
| 439 | fn byteSize(f: *Function, cty: CType) u64 { |
| 440 | return f.object.dg.byteSize(cty); |
| 441 | } |
| 442 | |
| 443 | 443 | fn renderType(f: *Function, w: anytype, t: Type) !void { |
| 444 | 444 | return f.object.dg.renderType(w, t); |
| 445 | 445 | } |
| ... | ... | @@ -1003,8 +1003,9 @@ pub const DeclGen = struct { |
| 1003 | 1003 | // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); |
| 1004 | 1004 | } |
| 1005 | 1005 | |
| 1006 | | try writer.writeAll("zig_make_special_"); |
| 1007 | | if (location == .StaticInitializer) try writer.writeAll("constant_"); |
| 1006 | try writer.writeAll("zig_"); |
| 1007 | try writer.writeAll(if (location == .StaticInitializer) "init" else "make"); |
| 1008 | try writer.writeAll("_special_"); |
| 1008 | 1009 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 1009 | 1010 | try writer.writeByte('('); |
| 1010 | 1011 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); |
| ... | ... | @@ -1565,6 +1566,10 @@ pub const DeclGen = struct { |
| 1565 | 1566 | return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind); |
| 1566 | 1567 | } |
| 1567 | 1568 | |
| 1569 | fn byteSize(dg: *DeclGen, cty: CType) u64 { |
| 1570 | return cty.byteSize(dg.ctypes.set, dg.module.getTarget()); |
| 1571 | } |
| 1572 | |
| 1568 | 1573 | /// Renders a type as a single identifier, generating intermediate typedefs |
| 1569 | 1574 | /// if necessary. |
| 1570 | 1575 | /// |
| ... | ... | @@ -1861,51 +1866,64 @@ pub const DeclGen = struct { |
| 1861 | 1866 | } |
| 1862 | 1867 | |
| 1863 | 1868 | fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void { |
| 1864 | | const target = dg.module.getTarget(); |
| 1865 | | if (ty.isAbiInt()) { |
| 1866 | | const int_info = ty.intInfo(target); |
| 1867 | | const c_bits = toCIntBits(int_info.bits) orelse |
| 1868 | | return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 1869 | | try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }); |
| 1870 | | } else if (ty.isRuntimeFloat()) { |
| 1871 | | try ty.print(writer, dg.module); |
| 1872 | | } else if (ty.isPtrAtRuntime()) { |
| 1873 | | try writer.print("p{d}", .{ty.bitSize(target)}); |
| 1874 | | } else if (ty.zigTypeTag() == .Bool) { |
| 1875 | | try writer.print("u8", .{}); |
| 1876 | | } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ |
| 1877 | | ty.fmt(dg.module), |
| 1878 | | }); |
| 1869 | try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete)); |
| 1870 | } |
| 1871 | |
| 1872 | fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void { |
| 1873 | switch (cty.tag()) { |
| 1874 | else => try writer.print("{c}{d}", .{ |
| 1875 | if (cty.isBool()) |
| 1876 | signAbbrev(.unsigned) |
| 1877 | else if (cty.isInteger()) |
| 1878 | signAbbrev(cty.signedness() orelse .unsigned) |
| 1879 | else if (cty.isFloat()) |
| 1880 | @as(u8, 'f') |
| 1881 | else if (cty.isPointer()) |
| 1882 | @as(u8, 'p') |
| 1883 | else |
| 1884 | return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ |
| 1885 | cty.tag(), |
| 1886 | }), |
| 1887 | if (cty.isFloat()) cty.floatActiveBits(dg.module.getTarget()) else dg.byteSize(cty) * 8, |
| 1888 | }), |
| 1889 | .array => try writer.writeAll("big"), |
| 1890 | .vector => try writer.writeAll("vec"), |
| 1891 | } |
| 1879 | 1892 | } |
| 1880 | 1893 | |
| 1881 | 1894 | fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void { |
| 1882 | | const target = dg.module.getTarget(); |
| 1883 | 1895 | switch (info) { |
| 1884 | | .None => {}, |
| 1885 | | .Range => { |
| 1886 | | var arena = std.heap.ArenaAllocator.init(dg.gpa); |
| 1887 | | defer arena.deinit(); |
| 1888 | | |
| 1889 | | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; |
| 1890 | | var stack align(@alignOf(ExpectedContents)) = |
| 1891 | | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 1892 | | |
| 1893 | | const int_info = ty.intInfo(target); |
| 1894 | | if (int_info.signedness == .signed) { |
| 1895 | | const min_val = try ty.minInt(stack.get(), target); |
| 1896 | | try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, min_val, .Other)}); |
| 1896 | .none => {}, |
| 1897 | .bits => { |
| 1898 | const cty = try dg.typeToCType(ty, .complete); |
| 1899 | if (cty.castTag(.vector)) |pl| { |
| 1900 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = pl.data.len }; |
| 1901 | try writer.print(", {}", .{try dg.fmtIntLiteral( |
| 1902 | Type.u32, |
| 1903 | Value.initPayload(&len_pl.base), |
| 1904 | .FunctionArgument, |
| 1905 | )}); |
| 1897 | 1906 | } |
| 1898 | 1907 | |
| 1899 | | const max_val = try ty.maxInt(stack.get(), target); |
| 1900 | | try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, max_val, .Other)}); |
| 1901 | | }, |
| 1902 | | .Bits => { |
| 1903 | | var bits_pl = Value.Payload.U64{ |
| 1904 | | .base = .{ .tag = .int_u64 }, |
| 1905 | | .data = ty.bitSize(target), |
| 1906 | | }; |
| 1907 | | const bits_val = Value.initPayload(&bits_pl.base); |
| 1908 | | try writer.print(", {}", .{try dg.fmtIntLiteral(Type.u8, bits_val, .Other)}); |
| 1908 | const target = dg.module.getTarget(); |
| 1909 | const elem_ty = ty.shallowElemType(); |
| 1910 | const elem_info = if (elem_ty.isAbiInt()) |
| 1911 | elem_ty.intInfo(target) |
| 1912 | else |
| 1913 | std.builtin.Type.Int{ |
| 1914 | .signedness = .unsigned, |
| 1915 | .bits = @intCast(u16, elem_ty.bitSize(target)), |
| 1916 | }; |
| 1917 | switch (cty.tag()) { |
| 1918 | else => {}, |
| 1919 | .array, .vector => try writer.print(", {}", .{elem_info.signedness == .signed}), |
| 1920 | } |
| 1921 | |
| 1922 | var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = elem_info.bits }; |
| 1923 | try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) { |
| 1924 | else => Type.u8, |
| 1925 | .array, .vector => Type.u16, |
| 1926 | }, Value.initPayload(&bits_pl.base), .FunctionArgument)}); |
| 1909 | 1927 | }, |
| 1910 | 1928 | } |
| 1911 | 1929 | } |
| ... | ... | @@ -2758,35 +2776,35 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2758 | 2776 | |
| 2759 | 2777 | // TODO use a different strategy for add, sub, mul, div |
| 2760 | 2778 | // that communicates to the optimizer that wrapping is UB. |
| 2761 | | .add => try airBinOp(f, inst, "+", "add", .None), |
| 2762 | | .sub => try airBinOp(f, inst, "-", "sub", .None), |
| 2763 | | .mul => try airBinOp(f, inst, "*", "mul", .None), |
| 2779 | .add => try airBinOp(f, inst, "+", "add", .none), |
| 2780 | .sub => try airBinOp(f, inst, "-", "sub", .none), |
| 2781 | .mul => try airBinOp(f, inst, "*", "mul", .none), |
| 2764 | 2782 | |
| 2765 | 2783 | .neg => try airFloatNeg(f, inst), |
| 2766 | | .div_float => try airBinBuiltinCall(f, inst, "div", .None), |
| 2784 | .div_float => try airBinBuiltinCall(f, inst, "div", .none), |
| 2767 | 2785 | |
| 2768 | | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), |
| 2786 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), |
| 2769 | 2787 | .rem => blk: { |
| 2770 | 2788 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2771 | 2789 | const lhs_ty = f.air.typeOf(bin_op.lhs); |
| 2772 | 2790 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2773 | 2791 | // so we only check one. |
| 2774 | 2792 | break :blk if (lhs_ty.isInt()) |
| 2775 | | try airBinOp(f, inst, "%", "rem", .None) |
| 2793 | try airBinOp(f, inst, "%", "rem", .none) |
| 2776 | 2794 | else |
| 2777 | 2795 | try airBinFloatOp(f, inst, "fmod"); |
| 2778 | 2796 | }, |
| 2779 | | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), |
| 2780 | | .mod => try airBinBuiltinCall(f, inst, "mod", .None), |
| 2797 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), |
| 2798 | .mod => try airBinBuiltinCall(f, inst, "mod", .none), |
| 2781 | 2799 | |
| 2782 | | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), |
| 2783 | | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), |
| 2784 | | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), |
| 2800 | .addwrap => try airBinBuiltinCall(f, inst, "addw", .bits), |
| 2801 | .subwrap => try airBinBuiltinCall(f, inst, "subw", .bits), |
| 2802 | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .bits), |
| 2785 | 2803 | |
| 2786 | | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), |
| 2787 | | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), |
| 2788 | | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), |
| 2789 | | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), |
| 2804 | .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits), |
| 2805 | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits), |
| 2806 | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .bits), |
| 2807 | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits), |
| 2790 | 2808 | |
| 2791 | 2809 | .sqrt => try airUnFloatOp(f, inst, "sqrt"), |
| 2792 | 2810 | .sin => try airUnFloatOp(f, inst, "sin"), |
| ... | ... | @@ -2805,34 +2823,38 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2805 | 2823 | |
| 2806 | 2824 | .mul_add => try airMulAdd(f, inst), |
| 2807 | 2825 | |
| 2808 | | .add_with_overflow => try airOverflow(f, inst, "add", .Bits), |
| 2809 | | .sub_with_overflow => try airOverflow(f, inst, "sub", .Bits), |
| 2810 | | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), |
| 2811 | | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), |
| 2826 | .add_with_overflow => try airOverflow(f, inst, "add", .bits), |
| 2827 | .sub_with_overflow => try airOverflow(f, inst, "sub", .bits), |
| 2828 | .mul_with_overflow => try airOverflow(f, inst, "mul", .bits), |
| 2829 | .shl_with_overflow => try airOverflow(f, inst, "shl", .bits), |
| 2812 | 2830 | |
| 2813 | 2831 | .min => try airMinMax(f, inst, '<', "fmin"), |
| 2814 | 2832 | .max => try airMinMax(f, inst, '>', "fmax"), |
| 2815 | 2833 | |
| 2816 | 2834 | .slice => try airSlice(f, inst), |
| 2817 | 2835 | |
| 2818 | | .cmp_gt => try airCmpOp(f, inst, ">", "gt"), |
| 2819 | | .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), |
| 2820 | | .cmp_lt => try airCmpOp(f, inst, "<", "lt"), |
| 2821 | | .cmp_lte => try airCmpOp(f, inst, "<=", "le"), |
| 2836 | .cmp_gt => try airCmpOp(f, inst, .gt), |
| 2837 | .cmp_gte => try airCmpOp(f, inst, .gte), |
| 2838 | .cmp_lt => try airCmpOp(f, inst, .lt), |
| 2839 | .cmp_lte => try airCmpOp(f, inst, .lte), |
| 2822 | 2840 | |
| 2823 | | .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), |
| 2824 | | .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), |
| 2841 | .cmp_eq => try airEquality(f, inst, .eq), |
| 2842 | .cmp_neq => try airEquality(f, inst, .neq), |
| 2825 | 2843 | |
| 2826 | | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), |
| 2844 | .cmp_vector => blk: { |
| 2845 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 2846 | const extra = f.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| 2847 | break :blk try cmpBuiltinCall(f, inst, extra, extra.compareOperator(), .operator, .bits); |
| 2848 | }, |
| 2827 | 2849 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), |
| 2828 | 2850 | |
| 2829 | 2851 | // bool_and and bool_or are non-short-circuit operations |
| 2830 | | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), |
| 2831 | | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), |
| 2832 | | .xor => try airBinOp(f, inst, "^", "xor", .None), |
| 2833 | | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), |
| 2834 | | .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), |
| 2835 | | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), |
| 2852 | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .none), |
| 2853 | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .none), |
| 2854 | .xor => try airBinOp(f, inst, "^", "xor", .none), |
| 2855 | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .none), |
| 2856 | .shl, => try airBinBuiltinCall(f, inst, "shlw", .bits), |
| 2857 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .none), |
| 2836 | 2858 | .not => try airNot (f, inst), |
| 2837 | 2859 | |
| 2838 | 2860 | .optional_payload => try airOptionalPayload(f, inst), |
| ... | ... | @@ -2877,11 +2899,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2877 | 2899 | .memcpy => try airMemcpy(f, inst), |
| 2878 | 2900 | .set_union_tag => try airSetUnionTag(f, inst), |
| 2879 | 2901 | .get_union_tag => try airGetUnionTag(f, inst), |
| 2880 | | .clz => try airUnBuiltinCall(f, inst, "clz", .Bits), |
| 2881 | | .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits), |
| 2882 | | .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits), |
| 2883 | | .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits), |
| 2884 | | .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits), |
| 2902 | .clz => try airUnBuiltinCall(f, inst, "clz", .bits), |
| 2903 | .ctz => try airUnBuiltinCall(f, inst, "ctz", .bits), |
| 2904 | .popcount => try airUnBuiltinCall(f, inst, "popcount", .bits), |
| 2905 | .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .bits), |
| 2906 | .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .bits), |
| 2885 | 2907 | .tag_name => try airTagName(f, inst), |
| 2886 | 2908 | .error_name => try airErrorName(f, inst), |
| 2887 | 2909 | .splat => try airSplat(f, inst), |
| ... | ... | @@ -3349,7 +3371,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3349 | 3371 | try f.writeCValueDeref(writer, operand); |
| 3350 | 3372 | try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); |
| 3351 | 3373 | if (cant_cast) try writer.writeByte(')'); |
| 3352 | | try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); |
| 3374 | try f.object.dg.renderBuiltinInfo(writer, field_ty, .bits); |
| 3353 | 3375 | try writer.writeByte(')'); |
| 3354 | 3376 | } else { |
| 3355 | 3377 | try f.writeCValue(writer, local, .Other); |
| ... | ... | @@ -3744,7 +3766,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3744 | 3766 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3745 | 3767 | const inst_ty = f.air.typeOfIndex(inst); |
| 3746 | 3768 | if (inst_ty.tag() != .bool) |
| 3747 | | return try airUnBuiltinCall(f, inst, "not", .Bits); |
| 3769 | return try airUnBuiltinCall(f, inst, "not", .bits); |
| 3748 | 3770 | |
| 3749 | 3771 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3750 | 3772 | |
| ... | ... | @@ -3803,7 +3825,7 @@ fn airBinOp( |
| 3803 | 3825 | return local; |
| 3804 | 3826 | } |
| 3805 | 3827 | |
| 3806 | | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { |
| 3828 | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: std.math.CompareOperator) !CValue { |
| 3807 | 3829 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3808 | 3830 | |
| 3809 | 3831 | if (f.liveness.isUnused(inst)) { |
| ... | ... | @@ -3813,10 +3835,11 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: |
| 3813 | 3835 | |
| 3814 | 3836 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3815 | 3837 | const target = f.object.dg.module.getTarget(); |
| 3816 | | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3817 | | return try cmpBuiltinCall(f, inst, operator, "cmp"); |
| 3838 | const operand_bits = operand_ty.bitSize(target); |
| 3839 | if (operand_ty.isInt() and operand_bits > 64) |
| 3840 | return cmpBuiltinCall(f, inst, bin_op, operator, .cmp, if (operand_bits > 128) .bits else .none); |
| 3818 | 3841 | if (operand_ty.isRuntimeFloat()) |
| 3819 | | return try cmpBuiltinCall(f, inst, operator, operation); |
| 3842 | return cmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); |
| 3820 | 3843 | |
| 3821 | 3844 | const inst_ty = f.air.typeOfIndex(inst); |
| 3822 | 3845 | const lhs = try f.resolveInst(bin_op.lhs); |
| ... | ... | @@ -3829,7 +3852,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: |
| 3829 | 3852 | try writer.writeAll(" = "); |
| 3830 | 3853 | try f.writeCValue(writer, lhs, .Other); |
| 3831 | 3854 | try writer.writeByte(' '); |
| 3832 | | try writer.writeAll(operator); |
| 3855 | try writer.writeAll(compareOperatorC(operator)); |
| 3833 | 3856 | try writer.writeByte(' '); |
| 3834 | 3857 | try f.writeCValue(writer, rhs, .Other); |
| 3835 | 3858 | try writer.writeAll(";\n"); |
| ... | ... | @@ -3840,9 +3863,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: |
| 3840 | 3863 | fn airEquality( |
| 3841 | 3864 | f: *Function, |
| 3842 | 3865 | inst: Air.Inst.Index, |
| 3843 | | negate_prefix: []const u8, |
| 3844 | | operator: []const u8, |
| 3845 | | operation: []const u8, |
| 3866 | operator: std.math.CompareOperator, |
| 3846 | 3867 | ) !CValue { |
| 3847 | 3868 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3848 | 3869 | |
| ... | ... | @@ -3853,10 +3874,11 @@ fn airEquality( |
| 3853 | 3874 | |
| 3854 | 3875 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3855 | 3876 | const target = f.object.dg.module.getTarget(); |
| 3856 | | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3857 | | return try cmpBuiltinCall(f, inst, operator, "cmp"); |
| 3877 | const operand_bits = operand_ty.bitSize(target); |
| 3878 | if (operand_ty.isInt() and operand_bits > 64) |
| 3879 | return cmpBuiltinCall(f, inst, bin_op, operator, .cmp, if (operand_bits > 128) .bits else .none); |
| 3858 | 3880 | if (operand_ty.isRuntimeFloat()) |
| 3859 | | return try cmpBuiltinCall(f, inst, operator, operation); |
| 3881 | return cmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); |
| 3860 | 3882 | |
| 3861 | 3883 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3862 | 3884 | const rhs = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -3872,7 +3894,12 @@ fn airEquality( |
| 3872 | 3894 | // (A && B) || (C && (A == B)) |
| 3873 | 3895 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| 3874 | 3896 | |
| 3875 | | try writer.writeAll(negate_prefix); |
| 3897 | switch (operator) { |
| 3898 | .eq => {}, |
| 3899 | .neq => try writer.writeByte('!'), |
| 3900 | else => unreachable, |
| 3901 | } |
| 3902 | try writer.writeAll("(("); |
| 3876 | 3903 | try f.writeCValue(writer, lhs, .Other); |
| 3877 | 3904 | try writer.writeAll(".is_null && "); |
| 3878 | 3905 | try f.writeCValue(writer, rhs, .Other); |
| ... | ... | @@ -3891,7 +3918,7 @@ fn airEquality( |
| 3891 | 3918 | |
| 3892 | 3919 | try f.writeCValue(writer, lhs, .Other); |
| 3893 | 3920 | try writer.writeByte(' '); |
| 3894 | | try writer.writeAll(operator); |
| 3921 | try writer.writeAll(compareOperatorC(operator)); |
| 3895 | 3922 | try writer.writeByte(' '); |
| 3896 | 3923 | try f.writeCValue(writer, rhs, .Other); |
| 3897 | 3924 | try writer.writeAll(";\n"); |
| ... | ... | @@ -3972,7 +3999,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 3972 | 3999 | const inst_ty = f.air.typeOfIndex(inst); |
| 3973 | 4000 | const target = f.object.dg.module.getTarget(); |
| 3974 | 4001 | if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) |
| 3975 | | return try airBinBuiltinCall(f, inst, operation[1..], .None); |
| 4002 | return try airBinBuiltinCall(f, inst, operation[1..], .none); |
| 3976 | 4003 | if (inst_ty.isRuntimeFloat()) |
| 3977 | 4004 | return try airBinFloatOp(f, inst, operation); |
| 3978 | 4005 | |
| ... | ... | @@ -4418,12 +4445,35 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4418 | 4445 | |
| 4419 | 4446 | // Ensure padding bits have the expected value. |
| 4420 | 4447 | if (dest_ty.isAbiInt()) { |
| 4448 | const dest_cty = try f.typeToCType(dest_ty, .complete); |
| 4449 | const dest_info = dest_ty.intInfo(target); |
| 4450 | var wrap_ty_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dest_info.signedness) { |
| 4451 | .unsigned => .int_unsigned, |
| 4452 | .signed => .int_signed, |
| 4453 | } }, .data = dest_info.bits }; |
| 4454 | |
| 4421 | 4455 | try f.writeCValue(writer, local, .Other); |
| 4456 | if (dest_cty.castTag(.array)) |pl| { |
| 4457 | try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) { |
| 4458 | .Little => pl.data.len - 1, |
| 4459 | .Big => 0, |
| 4460 | }}); |
| 4461 | wrap_ty_pl.data -= 1; |
| 4462 | wrap_ty_pl.data %= @intCast(u16, f.byteSize(f.indexToCType(pl.data.elem_type)) * 8); |
| 4463 | wrap_ty_pl.data += 1; |
| 4464 | } |
| 4465 | const wrap_ty = Type.initPayload(&wrap_ty_pl.base); |
| 4422 | 4466 | try writer.writeAll(" = zig_wrap_"); |
| 4423 | | try f.object.dg.renderTypeForBuiltinFnName(writer, dest_ty); |
| 4467 | try f.object.dg.renderTypeForBuiltinFnName(writer, wrap_ty); |
| 4424 | 4468 | try writer.writeByte('('); |
| 4425 | 4469 | try f.writeCValue(writer, local, .Other); |
| 4426 | | try f.object.dg.renderBuiltinInfo(writer, dest_ty, .Bits); |
| 4470 | if (dest_cty.castTag(.array)) |pl| { |
| 4471 | try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) { |
| 4472 | .Little => pl.data.len - 1, |
| 4473 | .Big => 0, |
| 4474 | }}); |
| 4475 | } |
| 4476 | try f.object.dg.renderBuiltinInfo(writer, wrap_ty, .bits); |
| 4427 | 4477 | try writer.writeAll(");\n"); |
| 4428 | 4478 | } |
| 4429 | 4479 | |
| ... | ... | @@ -5438,7 +5488,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5438 | 5488 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 5439 | 5489 | try writer.writeByte(')'); |
| 5440 | 5490 | if (cant_cast) try writer.writeByte(')'); |
| 5441 | | try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits); |
| 5491 | try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits); |
| 5442 | 5492 | try writer.writeAll(");\n"); |
| 5443 | 5493 | if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; |
| 5444 | 5494 | |
| ... | ... | @@ -5871,7 +5921,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5871 | 5921 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 5872 | 5922 | try writer.writeByte(')'); |
| 5873 | 5923 | if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { |
| 5874 | | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); |
| 5924 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 5875 | 5925 | try writer.writeByte(')'); |
| 5876 | 5926 | } |
| 5877 | 5927 | try writer.writeAll(";\n"); |
| ... | ... | @@ -5972,29 +6022,46 @@ fn airBinBuiltinCall( |
| 5972 | 6022 | fn cmpBuiltinCall( |
| 5973 | 6023 | f: *Function, |
| 5974 | 6024 | inst: Air.Inst.Index, |
| 5975 | | operator: []const u8, |
| 5976 | | operation: []const u8, |
| 6025 | data: anytype, |
| 6026 | operator: std.math.CompareOperator, |
| 6027 | operation: enum { cmp, operator }, |
| 6028 | info: BuiltinInfo, |
| 5977 | 6029 | ) !CValue { |
| 5978 | 6030 | const inst_ty = f.air.typeOfIndex(inst); |
| 5979 | | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5980 | | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 6031 | const operand_ty = f.air.typeOf(data.lhs); |
| 5981 | 6032 | |
| 5982 | | const lhs = try f.resolveInst(bin_op.lhs); |
| 5983 | | const rhs = try f.resolveInst(bin_op.rhs); |
| 5984 | | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6033 | const lhs = try f.resolveInst(data.lhs); |
| 6034 | const rhs = try f.resolveInst(data.rhs); |
| 6035 | try reap(f, inst, &.{ data.lhs, data.rhs }); |
| 6036 | |
| 6037 | const ref_ret = inst_ty.tag() != .bool; |
| 5985 | 6038 | |
| 5986 | 6039 | const writer = f.object.writer(); |
| 5987 | 6040 | const local = try f.allocLocal(inst, inst_ty); |
| 5988 | | try f.writeCValue(writer, local, .Other); |
| 5989 | | try writer.writeAll(" = zig_"); |
| 5990 | | try writer.writeAll(operation); |
| 5991 | | try writer.writeByte('_'); |
| 6041 | if (!ref_ret) { |
| 6042 | try f.writeCValue(writer, local, .Other); |
| 6043 | try writer.writeAll(" = "); |
| 6044 | } |
| 6045 | try writer.print("zig_{s}_", .{switch (operation) { |
| 6046 | else => @tagName(operation), |
| 6047 | .operator => compareOperatorAbbrev(operator), |
| 6048 | }}); |
| 5992 | 6049 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| 5993 | 6050 | try writer.writeByte('('); |
| 6051 | if (ref_ret) { |
| 6052 | try f.writeCValue(writer, local, .FunctionArgument); |
| 6053 | try writer.writeAll(", "); |
| 6054 | } |
| 5994 | 6055 | try f.writeCValue(writer, lhs, .FunctionArgument); |
| 5995 | 6056 | try writer.writeAll(", "); |
| 5996 | 6057 | try f.writeCValue(writer, rhs, .FunctionArgument); |
| 5997 | | try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); |
| 6058 | try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); |
| 6059 | try writer.writeByte(')'); |
| 6060 | if (!ref_ret) try writer.print(" {s} {}", .{ |
| 6061 | compareOperatorC(operator), |
| 6062 | try f.fmtIntLiteral(Type.initTag(.i32), Value.zero), |
| 6063 | }); |
| 6064 | try writer.writeAll(";\n"); |
| 5998 | 6065 | return local; |
| 5999 | 6066 | } |
| 6000 | 6067 | |
| ... | ... | @@ -6675,7 +6742,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6675 | 6742 | |
| 6676 | 6743 | try writer.writeAll(", "); |
| 6677 | 6744 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6678 | | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); |
| 6745 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 6679 | 6746 | try writer.writeByte(')'); |
| 6680 | 6747 | if (!empty) try writer.writeByte(')'); |
| 6681 | 6748 | |
| ... | ... | @@ -7094,6 +7161,28 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { |
| 7094 | 7161 | } else unreachable; |
| 7095 | 7162 | } |
| 7096 | 7163 | |
| 7164 | fn compareOperatorAbbrev(operator: std.math.CompareOperator) []const u8 { |
| 7165 | return switch (operator) { |
| 7166 | .lt => "lt", |
| 7167 | .lte => "le", |
| 7168 | .eq => "eq", |
| 7169 | .gte => "ge", |
| 7170 | .gt => "gt", |
| 7171 | .neq => "ne", |
| 7172 | }; |
| 7173 | } |
| 7174 | |
| 7175 | fn compareOperatorC(operator: std.math.CompareOperator) []const u8 { |
| 7176 | return switch (operator) { |
| 7177 | .lt => "<", |
| 7178 | .lte => "<=", |
| 7179 | .eq => "==", |
| 7180 | .gte => ">=", |
| 7181 | .gt => ">", |
| 7182 | .neq => "!=", |
| 7183 | }; |
| 7184 | } |
| 7185 | |
| 7097 | 7186 | fn StringLiteral(comptime WriterType: type) type { |
| 7098 | 7187 | // MSVC has a length limit of 16380 per string literal (before concatenation) |
| 7099 | 7188 | const max_char_len = 4; |
| ... | ... | @@ -7239,14 +7328,6 @@ fn formatIntLiteral( |
| 7239 | 7328 | .positive = undefined, |
| 7240 | 7329 | }; |
| 7241 | 7330 | defer allocator.free(wrap.limbs); |
| 7242 | | if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or |
| 7243 | | data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits)) |
| 7244 | | return writer.print("{s}_{s}", .{ |
| 7245 | | data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{ |
| 7246 | | if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits, |
| 7247 | | }), |
| 7248 | | if (int.positive) "MAX" else "MIN", |
| 7249 | | }); |
| 7250 | 7331 | |
| 7251 | 7332 | const c_limb_info: struct { |
| 7252 | 7333 | cty: CType, |
| ... | ... | @@ -7277,6 +7358,15 @@ fn formatIntLiteral( |
| 7277 | 7358 | }, |
| 7278 | 7359 | }; |
| 7279 | 7360 | if (c_limb_info.count == 1) { |
| 7361 | if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or |
| 7362 | data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits)) |
| 7363 | return writer.print("{s}_{s}", .{ |
| 7364 | data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{ |
| 7365 | if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits, |
| 7366 | }), |
| 7367 | if (int.positive) "MAX" else "MIN", |
| 7368 | }); |
| 7369 | |
| 7280 | 7370 | if (!int.positive) try writer.writeByte('-'); |
| 7281 | 7371 | try data.cty.renderLiteralPrefix(writer, data.kind); |
| 7282 | 7372 | |
| ... | ... | @@ -7310,7 +7400,7 @@ fn formatIntLiteral( |
| 7310 | 7400 | try writer.writeAll(string); |
| 7311 | 7401 | } else { |
| 7312 | 7402 | try data.cty.renderLiteralPrefix(writer, data.kind); |
| 7313 | | wrap.convertToTwosComplement(int, .unsigned, data.int_info.bits); |
| 7403 | wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits); |
| 7314 | 7404 | std.mem.set(BigIntLimb, wrap.limbs[wrap.len..], 0); |
| 7315 | 7405 | wrap.len = wrap.limbs.len; |
| 7316 | 7406 | const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count); |
| ... | ... | @@ -7343,7 +7433,7 @@ fn formatIntLiteral( |
| 7343 | 7433 | c_limb_cty = c_limb_info.cty.toSigned(); |
| 7344 | 7434 | |
| 7345 | 7435 | c_limb_mut.positive = wrap.positive; |
| 7346 | | c_limb_mut.convertToTwosComplement( |
| 7436 | c_limb_mut.truncate( |
| 7347 | 7437 | c_limb_mut.toConst(), |
| 7348 | 7438 | .signed, |
| 7349 | 7439 | data.int_info.bits - limb_i * @bitSizeOf(BigIntLimb), |