| ... | ... | @@ -43,10 +43,12 @@ pub const CValue = union(enum) { |
| 43 | 43 | decl_ref: InternPool.DeclIndex, |
| 44 | 44 | /// An undefined value (cannot be dereferenced) |
| 45 | 45 | undef: Type, |
| 46 | | /// Render the slice as an identifier (using fmtIdent) |
| 46 | /// Rendered as an identifier (using fmtIdent) |
| 47 | 47 | identifier: []const u8, |
| 48 | | /// Render the slice as an payload.identifier (using fmtIdent) |
| 48 | /// Rendered as "payload." followed by as identifier (using fmtIdent) |
| 49 | 49 | payload_identifier: []const u8, |
| 50 | /// Rendered with fmtCTypePoolString |
| 51 | ctype_pool_string: CType.Pool.String, |
| 50 | 52 | }; |
| 51 | 53 | |
| 52 | 54 | const BlockData = struct { |
| ... | ... | @@ -62,10 +64,10 @@ pub const LazyFnKey = union(enum) { |
| 62 | 64 | never_inline: InternPool.DeclIndex, |
| 63 | 65 | }; |
| 64 | 66 | pub const LazyFnValue = struct { |
| 65 | | fn_name: CType.String, |
| 67 | fn_name: CType.Pool.String, |
| 66 | 68 | data: Data, |
| 67 | 69 | |
| 68 | | pub const Data = union { |
| 70 | const Data = union { |
| 69 | 71 | tag_name: Type, |
| 70 | 72 | never_tail: void, |
| 71 | 73 | never_inline: void, |
| ... | ... | @@ -80,7 +82,7 @@ const Local = struct { |
| 80 | 82 | _: u20 = undefined, |
| 81 | 83 | }, |
| 82 | 84 | |
| 83 | | pub fn getType(local: Local) LocalType { |
| 85 | fn getType(local: Local) LocalType { |
| 84 | 86 | return .{ .ctype = local.ctype, .alignas = local.flags.alignas }; |
| 85 | 87 | } |
| 86 | 88 | }; |
| ... | ... | @@ -96,12 +98,20 @@ const ValueRenderLocation = enum { |
| 96 | 98 | StaticInitializer, |
| 97 | 99 | Other, |
| 98 | 100 | |
| 99 | | pub fn isInitializer(self: ValueRenderLocation) bool { |
| 100 | | return switch (self) { |
| 101 | fn isInitializer(loc: ValueRenderLocation) bool { |
| 102 | return switch (loc) { |
| 101 | 103 | .Initializer, .StaticInitializer => true, |
| 102 | 104 | else => false, |
| 103 | 105 | }; |
| 104 | 106 | } |
| 107 | |
| 108 | fn toCTypeKind(loc: ValueRenderLocation) CType.Kind { |
| 109 | return switch (loc) { |
| 110 | .FunctionArgument => .parameter, |
| 111 | .Initializer, .Other => .complete, |
| 112 | .StaticInitializer => .global, |
| 113 | }; |
| 114 | } |
| 105 | 115 | }; |
| 106 | 116 | |
| 107 | 117 | const BuiltinInfo = enum { none, bits }; |
| ... | ... | @@ -234,12 +244,11 @@ fn isReservedIdent(ident: []const u8) bool { |
| 234 | 244 | |
| 235 | 245 | fn formatIdent( |
| 236 | 246 | ident: []const u8, |
| 237 | | comptime fmt: []const u8, |
| 238 | | options: std.fmt.FormatOptions, |
| 247 | comptime fmt_str: []const u8, |
| 248 | _: std.fmt.FormatOptions, |
| 239 | 249 | writer: anytype, |
| 240 | | ) !void { |
| 241 | | _ = options; |
| 242 | | const solo = fmt.len != 0 and fmt[0] == ' '; // space means solo; not part of a bigger ident. |
| 250 | ) @TypeOf(writer).Error!void { |
| 251 | const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident. |
| 243 | 252 | if (solo and isReservedIdent(ident)) { |
| 244 | 253 | try writer.writeAll("zig_e_"); |
| 245 | 254 | } |
| ... | ... | @@ -256,11 +265,32 @@ fn formatIdent( |
| 256 | 265 | } |
| 257 | 266 | } |
| 258 | 267 | } |
| 259 | | |
| 260 | 268 | pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { |
| 261 | 269 | return .{ .data = ident }; |
| 262 | 270 | } |
| 263 | 271 | |
| 272 | const CTypePoolStringFormatData = struct { |
| 273 | ctype_pool_string: CType.Pool.String, |
| 274 | ctype_pool: *const CType.Pool, |
| 275 | }; |
| 276 | fn formatCTypePoolString( |
| 277 | data: CTypePoolStringFormatData, |
| 278 | comptime fmt_str: []const u8, |
| 279 | fmt_opts: std.fmt.FormatOptions, |
| 280 | writer: anytype, |
| 281 | ) @TypeOf(writer).Error!void { |
| 282 | if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice| |
| 283 | try formatIdent(slice, fmt_str, fmt_opts, writer) |
| 284 | else |
| 285 | try writer.print("{}", .{data.ctype_pool_string.fmt(data.ctype_pool)}); |
| 286 | } |
| 287 | pub fn fmtCTypePoolString( |
| 288 | ctype_pool_string: CType.Pool.String, |
| 289 | ctype_pool: *const CType.Pool, |
| 290 | ) std.fmt.Formatter(formatCTypePoolString) { |
| 291 | return .{ .data = .{ .ctype_pool_string = ctype_pool_string, .ctype_pool = ctype_pool } }; |
| 292 | } |
| 293 | |
| 264 | 294 | // Returns true if `formatIdent` would make any edits to ident. |
| 265 | 295 | // This must be kept in sync with `formatIdent`. |
| 266 | 296 | pub fn isMangledIdent(ident: []const u8, solo: bool) bool { |
| ... | ... | @@ -321,7 +351,7 @@ pub const Function = struct { |
| 321 | 351 | try writer.writeAll(" = "); |
| 322 | 352 | try f.object.dg.renderValue(writer, val, .StaticInitializer); |
| 323 | 353 | try writer.writeAll(";\n "); |
| 324 | | break :result decl_c_value; |
| 354 | break :result .{ .local = decl_c_value.new_local }; |
| 325 | 355 | } else .{ .constant = val }; |
| 326 | 356 | |
| 327 | 357 | gop.value_ptr.* = result; |
| ... | ... | @@ -377,27 +407,7 @@ pub const Function = struct { |
| 377 | 407 | switch (c_value) { |
| 378 | 408 | .none => unreachable, |
| 379 | 409 | .new_local, .local => |i| try w.print("t{d}", .{i}), |
| 380 | | .local_ref => |i| { |
| 381 | | const local = &f.locals.items[i]; |
| 382 | | if (local.flags.alignas.abiOrder().compare(.lt)) { |
| 383 | | const gpa = f.object.dg.gpa; |
| 384 | | const mod = f.object.dg.mod; |
| 385 | | const ctype_pool = &f.object.dg.ctype_pool; |
| 386 | | |
| 387 | | try w.writeByte('('); |
| 388 | | try f.renderCType(w, try ctype_pool.getPointer(gpa, .{ |
| 389 | | .elem_ctype = try ctype_pool.fromIntInfo(gpa, .{ |
| 390 | | .signedness = .unsigned, |
| 391 | | .bits = @min( |
| 392 | | local.flags.alignas.toByteUnits(), |
| 393 | | mod.resolved_target.result.maxIntAlignment(), |
| 394 | | ) * 8, |
| 395 | | }, mod, .forward), |
| 396 | | })); |
| 397 | | try w.writeByte(')'); |
| 398 | | } |
| 399 | | try w.print("&t{d}", .{i}); |
| 400 | | }, |
| 410 | .local_ref => |i| try w.print("&t{d}", .{i}), |
| 401 | 411 | .constant => |val| try f.object.dg.renderValue(w, val, location), |
| 402 | 412 | .arg => |i| try w.print("a{d}", .{i}), |
| 403 | 413 | .arg_array => |i| try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }), |
| ... | ... | @@ -516,7 +526,7 @@ pub const Function = struct { |
| 516 | 526 | }, |
| 517 | 527 | }; |
| 518 | 528 | } |
| 519 | | return gop.value_ptr.fn_name.slice(ctype_pool); |
| 529 | return gop.value_ptr.fn_name.toSlice(ctype_pool).?; |
| 520 | 530 | } |
| 521 | 531 | |
| 522 | 532 | pub fn deinit(f: *Function) void { |
| ... | ... | @@ -538,6 +548,43 @@ pub const Function = struct { |
| 538 | 548 | const zcu = f.object.dg.zcu; |
| 539 | 549 | return f.air.typeOfIndex(inst, &zcu.intern_pool); |
| 540 | 550 | } |
| 551 | |
| 552 | fn copyCValue(f: *Function, ctype: CType, dst: CValue, src: CValue) !void { |
| 553 | switch (dst) { |
| 554 | .new_local, .local => |dst_local_index| switch (src) { |
| 555 | .new_local, .local => |src_local_index| if (dst_local_index == src_local_index) return, |
| 556 | else => {}, |
| 557 | }, |
| 558 | else => {}, |
| 559 | } |
| 560 | const writer = f.object.writer(); |
| 561 | const a = try Assignment.start(f, writer, ctype); |
| 562 | try f.writeCValue(writer, dst, .Other); |
| 563 | try a.assign(f, writer); |
| 564 | try f.writeCValue(writer, src, .Initializer); |
| 565 | try a.end(f, writer); |
| 566 | } |
| 567 | |
| 568 | fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue { |
| 569 | switch (src) { |
| 570 | // Move the freshly allocated local to be owned by this instruction, |
| 571 | // by returning it here instead of freeing it. |
| 572 | .new_local => return src, |
| 573 | else => { |
| 574 | try freeCValue(f, inst, src); |
| 575 | const dst = try f.allocLocal(inst, ty); |
| 576 | try f.copyCValue(try f.ctypeFromType(ty, .complete), dst, src); |
| 577 | return dst; |
| 578 | }, |
| 579 | } |
| 580 | } |
| 581 | |
| 582 | fn freeCValue(f: *Function, inst: ?Air.Inst.Index, val: CValue) !void { |
| 583 | switch (val) { |
| 584 | .new_local => |local_index| try freeLocal(f, inst, local_index, null), |
| 585 | else => {}, |
| 586 | } |
| 587 | } |
| 541 | 588 | }; |
| 542 | 589 | |
| 543 | 590 | /// This data is available when outputting .c code for a `Zcu`. |
| ... | ... | @@ -627,13 +674,14 @@ pub const DeclGen = struct { |
| 627 | 674 | // them). The analysis until now should ensure that the C function |
| 628 | 675 | // pointers are compatible. If they are not, then there is a bug |
| 629 | 676 | // somewhere and we should let the C compiler tell us about it. |
| 630 | | const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype; |
| 677 | const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete); |
| 678 | const elem_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype; |
| 631 | 679 | const decl_ctype = try dg.ctypeFromType(decl_ty, .complete); |
| 632 | 680 | const need_cast = !elem_ctype.eql(decl_ctype) and |
| 633 | 681 | (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function); |
| 634 | 682 | if (need_cast) { |
| 635 | 683 | try writer.writeAll("(("); |
| 636 | | try dg.renderType(writer, ptr_ty); |
| 684 | try dg.renderCType(writer, ptr_ctype); |
| 637 | 685 | try writer.writeByte(')'); |
| 638 | 686 | } |
| 639 | 687 | try writer.writeByte('&'); |
| ... | ... | @@ -692,13 +740,14 @@ pub const DeclGen = struct { |
| 692 | 740 | // them). The analysis until now should ensure that the C function |
| 693 | 741 | // pointers are compatible. If they are not, then there is a bug |
| 694 | 742 | // somewhere and we should let the C compiler tell us about it. |
| 695 | | const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype; |
| 743 | const ctype = try dg.ctypeFromType(ty, .complete); |
| 744 | const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype; |
| 696 | 745 | const decl_ctype = try dg.ctypeFromType(decl_ty, .complete); |
| 697 | 746 | const need_cast = !elem_ctype.eql(decl_ctype) and |
| 698 | 747 | (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function); |
| 699 | 748 | if (need_cast) { |
| 700 | 749 | try writer.writeAll("(("); |
| 701 | | try dg.renderType(writer, ty); |
| 750 | try dg.renderCType(writer, ctype); |
| 702 | 751 | try writer.writeByte(')'); |
| 703 | 752 | } |
| 704 | 753 | try writer.writeByte('&'); |
| ... | ... | @@ -828,6 +877,12 @@ pub const DeclGen = struct { |
| 828 | 877 | } |
| 829 | 878 | } |
| 830 | 879 | |
| 880 | fn renderErrorName(dg: *DeclGen, writer: anytype, err_name: InternPool.NullTerminatedString) !void { |
| 881 | const zcu = dg.zcu; |
| 882 | const ip = &zcu.intern_pool; |
| 883 | try writer.print("zig_error_{}", .{fmtIdent(err_name.toSlice(ip))}); |
| 884 | } |
| 885 | |
| 831 | 886 | fn renderValue( |
| 832 | 887 | dg: *DeclGen, |
| 833 | 888 | writer: anytype, |
| ... | ... | @@ -837,6 +892,7 @@ pub const DeclGen = struct { |
| 837 | 892 | const zcu = dg.zcu; |
| 838 | 893 | const ip = &zcu.intern_pool; |
| 839 | 894 | const target = &dg.mod.resolved_target.result; |
| 895 | const ctype_pool = &dg.ctype_pool; |
| 840 | 896 | |
| 841 | 897 | const initializer_type: ValueRenderLocation = switch (location) { |
| 842 | 898 | .StaticInitializer => .StaticInitializer, |
| ... | ... | @@ -845,6 +901,7 @@ pub const DeclGen = struct { |
| 845 | 901 | |
| 846 | 902 | const ty = val.typeOf(zcu); |
| 847 | 903 | if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location); |
| 904 | const ctype = try dg.ctypeFromType(ty, location.toCTypeKind()); |
| 848 | 905 | switch (ip.indexToKey(val.toIntern())) { |
| 849 | 906 | // types, not values |
| 850 | 907 | .int_type, |
| ... | ... | @@ -890,76 +947,53 @@ pub const DeclGen = struct { |
| 890 | 947 | .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}), |
| 891 | 948 | .lazy_align, .lazy_size => { |
| 892 | 949 | try writer.writeAll("(("); |
| 893 | | try dg.renderType(writer, ty); |
| 950 | try dg.renderCType(writer, ctype); |
| 894 | 951 | try writer.print("){x})", .{try dg.fmtIntLiteral( |
| 895 | 952 | try zcu.intValue(Type.usize, val.toUnsignedInt(zcu)), |
| 896 | 953 | .Other, |
| 897 | 954 | )}); |
| 898 | 955 | }, |
| 899 | 956 | }, |
| 900 | | .err => |err| try writer.print("zig_error_{}", .{ |
| 901 | | fmtIdent(err.name.toSlice(ip)), |
| 902 | | }), |
| 903 | | .error_union => |error_union| { |
| 904 | | const payload_ty = ty.errorUnionPayload(zcu); |
| 905 | | const error_ty = ty.errorUnionSet(zcu); |
| 906 | | const err_int_ty = try zcu.errorIntType(); |
| 907 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 908 | | switch (error_union.val) { |
| 909 | | .err_name => |err_name| return dg.renderValue( |
| 910 | | writer, |
| 911 | | Value.fromInterned((try zcu.intern(.{ .err = .{ |
| 912 | | .ty = error_ty.toIntern(), |
| 913 | | .name = err_name, |
| 914 | | } }))), |
| 915 | | location, |
| 916 | | ), |
| 917 | | .payload => return dg.renderValue( |
| 918 | | writer, |
| 919 | | try zcu.intValue(err_int_ty, 0), |
| 920 | | location, |
| 921 | | ), |
| 957 | .err => |err| try dg.renderErrorName(writer, err.name), |
| 958 | .error_union => |error_union| switch (ctype.info(ctype_pool)) { |
| 959 | .basic => switch (error_union.val) { |
| 960 | .err_name => |err_name| try dg.renderErrorName(writer, err_name), |
| 961 | .payload => try writer.writeAll("0"), |
| 962 | }, |
| 963 | .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 964 | .aggregate => |aggregate| { |
| 965 | if (!location.isInitializer()) { |
| 966 | try writer.writeByte('('); |
| 967 | try dg.renderCType(writer, ctype); |
| 968 | try writer.writeByte(')'); |
| 922 | 969 | } |
| 923 | | } |
| 924 | | |
| 925 | | if (!location.isInitializer()) { |
| 926 | | try writer.writeByte('('); |
| 927 | | try dg.renderType(writer, ty); |
| 928 | | try writer.writeByte(')'); |
| 929 | | } |
| 930 | | |
| 931 | | try writer.writeAll("{ .payload = "); |
| 932 | | try dg.renderValue( |
| 933 | | writer, |
| 934 | | Value.fromInterned(switch (error_union.val) { |
| 935 | | .err_name => (try zcu.undefValue(payload_ty)).toIntern(), |
| 936 | | .payload => |payload| payload, |
| 937 | | }), |
| 938 | | initializer_type, |
| 939 | | ); |
| 940 | | try writer.writeAll(", .error = "); |
| 941 | | switch (error_union.val) { |
| 942 | | .err_name => |err_name| try dg.renderValue( |
| 943 | | writer, |
| 944 | | Value.fromInterned((try zcu.intern(.{ .err = .{ |
| 945 | | .ty = error_ty.toIntern(), |
| 946 | | .name = err_name, |
| 947 | | } }))), |
| 948 | | location, |
| 949 | | ), |
| 950 | | .payload => try dg.renderValue( |
| 951 | | writer, |
| 952 | | try zcu.intValue(err_int_ty, 0), |
| 953 | | location, |
| 954 | | ), |
| 955 | | } |
| 956 | | try writer.writeAll(" }"); |
| 970 | try writer.writeByte('{'); |
| 971 | for (0..aggregate.fields.len) |field_index| { |
| 972 | if (field_index > 0) try writer.writeByte(','); |
| 973 | switch (aggregate.fields.at(field_index, ctype_pool).name.index) { |
| 974 | .@"error" => switch (error_union.val) { |
| 975 | .err_name => |err_name| try dg.renderErrorName(writer, err_name), |
| 976 | .payload => try writer.writeByte('0'), |
| 977 | }, |
| 978 | .payload => switch (error_union.val) { |
| 979 | .err_name => try dg.renderUndefValue( |
| 980 | writer, |
| 981 | ty.errorUnionPayload(zcu), |
| 982 | initializer_type, |
| 983 | ), |
| 984 | .payload => |payload| try dg.renderValue( |
| 985 | writer, |
| 986 | Value.fromInterned(payload), |
| 987 | initializer_type, |
| 988 | ), |
| 989 | }, |
| 990 | else => unreachable, |
| 991 | } |
| 992 | } |
| 993 | try writer.writeByte('}'); |
| 994 | }, |
| 957 | 995 | }, |
| 958 | | .enum_tag => |enum_tag| try dg.renderValue( |
| 959 | | writer, |
| 960 | | Value.fromInterned(enum_tag.int), |
| 961 | | location, |
| 962 | | ), |
| 996 | .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location), |
| 963 | 997 | .float => { |
| 964 | 998 | const bits = ty.floatBits(target.*); |
| 965 | 999 | const f128_val = val.toFloat(f128, zcu); |
| ... | ... | @@ -1050,15 +1084,23 @@ pub const DeclGen = struct { |
| 1050 | 1084 | if (!empty) try writer.writeByte(')'); |
| 1051 | 1085 | }, |
| 1052 | 1086 | .slice => |slice| { |
| 1087 | const aggregate = ctype.info(ctype_pool).aggregate; |
| 1053 | 1088 | if (!location.isInitializer()) { |
| 1054 | 1089 | try writer.writeByte('('); |
| 1055 | | try dg.renderType(writer, ty); |
| 1090 | try dg.renderCType(writer, ctype); |
| 1056 | 1091 | try writer.writeByte(')'); |
| 1057 | 1092 | } |
| 1058 | 1093 | try writer.writeByte('{'); |
| 1059 | | try dg.renderValue(writer, Value.fromInterned(slice.ptr), initializer_type); |
| 1060 | | try writer.writeAll(", "); |
| 1061 | | try dg.renderValue(writer, Value.fromInterned(slice.len), initializer_type); |
| 1094 | for (0..aggregate.fields.len) |field_index| { |
| 1095 | if (field_index > 0) try writer.writeByte(','); |
| 1096 | try dg.renderValue(writer, Value.fromInterned( |
| 1097 | switch (aggregate.fields.at(field_index, ctype_pool).name.index) { |
| 1098 | .ptr => slice.ptr, |
| 1099 | .len => slice.len, |
| 1100 | else => unreachable, |
| 1101 | }, |
| 1102 | ), initializer_type); |
| 1103 | } |
| 1062 | 1104 | try writer.writeByte('}'); |
| 1063 | 1105 | }, |
| 1064 | 1106 | .ptr => |ptr| switch (ptr.addr) { |
| ... | ... | @@ -1066,7 +1108,7 @@ pub const DeclGen = struct { |
| 1066 | 1108 | .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, val, decl_val, location), |
| 1067 | 1109 | .int => |int| { |
| 1068 | 1110 | try writer.writeAll("(("); |
| 1069 | | try dg.renderType(writer, ty); |
| 1111 | try dg.renderCType(writer, ctype); |
| 1070 | 1112 | try writer.print("){x})", .{try dg.fmtIntLiteral(Value.fromInterned(int), location)}); |
| 1071 | 1113 | }, |
| 1072 | 1114 | .eu_payload, |
| ... | ... | @@ -1076,54 +1118,80 @@ pub const DeclGen = struct { |
| 1076 | 1118 | => try dg.renderParentPtr(writer, val.toIntern(), location), |
| 1077 | 1119 | .comptime_field, .comptime_alloc => unreachable, |
| 1078 | 1120 | }, |
| 1079 | | .opt => |opt| { |
| 1080 | | const payload_ty = ty.optionalChild(zcu); |
| 1081 | | |
| 1082 | | const is_null_val = Value.makeBool(opt.val == .none); |
| 1083 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) |
| 1084 | | return dg.renderValue(writer, is_null_val, location); |
| 1085 | | |
| 1086 | | if (ty.optionalReprIsPayload(zcu)) return dg.renderValue( |
| 1087 | | writer, |
| 1121 | .opt => |opt| switch (ctype.info(ctype_pool)) { |
| 1122 | .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) { |
| 1123 | .none => "true", |
| 1124 | else => "false", |
| 1125 | }) else switch (opt.val) { |
| 1126 | .none => try writer.writeAll("0"), |
| 1127 | else => |payload| switch (ip.indexToKey(payload)) { |
| 1128 | .undef => |err_ty| try dg.renderUndefValue( |
| 1129 | writer, |
| 1130 | Type.fromInterned(err_ty), |
| 1131 | location, |
| 1132 | ), |
| 1133 | .err => |err| try dg.renderErrorName(writer, err.name), |
| 1134 | else => unreachable, |
| 1135 | }, |
| 1136 | }, |
| 1137 | .pointer => switch (opt.val) { |
| 1138 | .none => try writer.writeAll("NULL"), |
| 1139 | else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location), |
| 1140 | }, |
| 1141 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 1142 | .aggregate => |aggregate| { |
| 1088 | 1143 | switch (opt.val) { |
| 1089 | | .none => switch (payload_ty.zigTypeTag(zcu)) { |
| 1090 | | .ErrorSet => try zcu.intValue(try zcu.errorIntType(), 0), |
| 1091 | | .Pointer => try zcu.getCoerced(val, payload_ty), |
| 1144 | .none => {}, |
| 1145 | else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) { |
| 1146 | .is_null, .payload => {}, |
| 1147 | .ptr, .len => return dg.renderValue( |
| 1148 | writer, |
| 1149 | Value.fromInterned(payload), |
| 1150 | location, |
| 1151 | ), |
| 1092 | 1152 | else => unreachable, |
| 1093 | 1153 | }, |
| 1094 | | else => |payload| Value.fromInterned(payload), |
| 1095 | | }, |
| 1096 | | location, |
| 1097 | | ); |
| 1098 | | |
| 1099 | | if (!location.isInitializer()) { |
| 1100 | | try writer.writeByte('('); |
| 1101 | | try dg.renderType(writer, ty); |
| 1102 | | try writer.writeByte(')'); |
| 1103 | | } |
| 1104 | | |
| 1105 | | try writer.writeAll("{ .payload = "); |
| 1106 | | switch (opt.val) { |
| 1107 | | .none => try dg.renderUndefValue(writer, payload_ty, initializer_type), |
| 1108 | | else => |payload| try dg.renderValue( |
| 1109 | | writer, |
| 1110 | | Value.fromInterned(payload), |
| 1111 | | initializer_type, |
| 1112 | | ), |
| 1113 | | } |
| 1114 | | try writer.writeAll(", .is_null = "); |
| 1115 | | try dg.renderValue(writer, is_null_val, initializer_type); |
| 1116 | | try writer.writeAll(" }"); |
| 1154 | } |
| 1155 | if (!location.isInitializer()) { |
| 1156 | try writer.writeByte('('); |
| 1157 | try dg.renderCType(writer, ctype); |
| 1158 | try writer.writeByte(')'); |
| 1159 | } |
| 1160 | try writer.writeByte('{'); |
| 1161 | for (0..aggregate.fields.len) |field_index| { |
| 1162 | if (field_index > 0) try writer.writeByte(','); |
| 1163 | switch (aggregate.fields.at(field_index, ctype_pool).name.index) { |
| 1164 | .is_null => try writer.writeAll(switch (opt.val) { |
| 1165 | .none => "true", |
| 1166 | else => "false", |
| 1167 | }), |
| 1168 | .payload => switch (opt.val) { |
| 1169 | .none => try dg.renderUndefValue( |
| 1170 | writer, |
| 1171 | ty.optionalChild(zcu), |
| 1172 | initializer_type, |
| 1173 | ), |
| 1174 | else => |payload| try dg.renderValue( |
| 1175 | writer, |
| 1176 | Value.fromInterned(payload), |
| 1177 | initializer_type, |
| 1178 | ), |
| 1179 | }, |
| 1180 | .ptr => try writer.writeAll("NULL"), |
| 1181 | .len => try dg.renderUndefValue(writer, Type.usize, initializer_type), |
| 1182 | else => unreachable, |
| 1183 | } |
| 1184 | } |
| 1185 | try writer.writeByte('}'); |
| 1186 | }, |
| 1117 | 1187 | }, |
| 1118 | 1188 | .aggregate => switch (ip.indexToKey(ty.toIntern())) { |
| 1119 | 1189 | .array_type, .vector_type => { |
| 1120 | 1190 | if (location == .FunctionArgument) { |
| 1121 | 1191 | try writer.writeByte('('); |
| 1122 | | try dg.renderType(writer, ty); |
| 1192 | try dg.renderCType(writer, ctype); |
| 1123 | 1193 | try writer.writeByte(')'); |
| 1124 | 1194 | } |
| 1125 | | // Fall back to generic implementation. |
| 1126 | | |
| 1127 | 1195 | const ai = ty.arrayInfo(zcu); |
| 1128 | 1196 | if (ai.elem_type.eql(Type.u8, zcu)) { |
| 1129 | 1197 | var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu)); |
| ... | ... | @@ -1160,7 +1228,7 @@ pub const DeclGen = struct { |
| 1160 | 1228 | .anon_struct_type => |tuple| { |
| 1161 | 1229 | if (!location.isInitializer()) { |
| 1162 | 1230 | try writer.writeByte('('); |
| 1163 | | try dg.renderType(writer, ty); |
| 1231 | try dg.renderCType(writer, ctype); |
| 1164 | 1232 | try writer.writeByte(')'); |
| 1165 | 1233 | } |
| 1166 | 1234 | |
| ... | ... | @@ -1196,7 +1264,7 @@ pub const DeclGen = struct { |
| 1196 | 1264 | .auto, .@"extern" => { |
| 1197 | 1265 | if (!location.isInitializer()) { |
| 1198 | 1266 | try writer.writeByte('('); |
| 1199 | | try dg.renderType(writer, ty); |
| 1267 | try dg.renderCType(writer, ctype); |
| 1200 | 1268 | try writer.writeByte(')'); |
| 1201 | 1269 | } |
| 1202 | 1270 | |
| ... | ... | @@ -1238,7 +1306,7 @@ pub const DeclGen = struct { |
| 1238 | 1306 | |
| 1239 | 1307 | if (eff_num_fields == 0) { |
| 1240 | 1308 | try writer.writeByte('('); |
| 1241 | | try dg.renderUndefValue(writer, ty, initializer_type); |
| 1309 | try dg.renderUndefValue(writer, ty, location); |
| 1242 | 1310 | try writer.writeByte(')'); |
| 1243 | 1311 | } else if (ty.bitSize(zcu) > 64) { |
| 1244 | 1312 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) |
| ... | ... | @@ -1293,7 +1361,7 @@ pub const DeclGen = struct { |
| 1293 | 1361 | |
| 1294 | 1362 | if (!empty) try writer.writeAll(" | "); |
| 1295 | 1363 | try writer.writeByte('('); |
| 1296 | | try dg.renderType(writer, ty); |
| 1364 | try dg.renderCType(writer, ctype); |
| 1297 | 1365 | try writer.writeByte(')'); |
| 1298 | 1366 | |
| 1299 | 1367 | const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { |
| ... | ... | @@ -1334,7 +1402,7 @@ pub const DeclGen = struct { |
| 1334 | 1402 | try dg.renderType(writer, backing_ty); |
| 1335 | 1403 | try writer.writeByte(')'); |
| 1336 | 1404 | } |
| 1337 | | try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type); |
| 1405 | try dg.renderValue(writer, Value.fromInterned(un.val), location); |
| 1338 | 1406 | }, |
| 1339 | 1407 | .@"extern" => { |
| 1340 | 1408 | if (location == .StaticInitializer) { |
| ... | ... | @@ -1347,7 +1415,7 @@ pub const DeclGen = struct { |
| 1347 | 1415 | try writer.writeAll(")("); |
| 1348 | 1416 | try dg.renderType(writer, backing_ty); |
| 1349 | 1417 | try writer.writeAll("){"); |
| 1350 | | try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type); |
| 1418 | try dg.renderValue(writer, Value.fromInterned(un.val), location); |
| 1351 | 1419 | try writer.writeAll("})"); |
| 1352 | 1420 | }, |
| 1353 | 1421 | else => unreachable, |
| ... | ... | @@ -1355,7 +1423,7 @@ pub const DeclGen = struct { |
| 1355 | 1423 | } else { |
| 1356 | 1424 | if (!location.isInitializer()) { |
| 1357 | 1425 | try writer.writeByte('('); |
| 1358 | | try dg.renderType(writer, ty); |
| 1426 | try dg.renderCType(writer, ctype); |
| 1359 | 1427 | try writer.writeByte(')'); |
| 1360 | 1428 | } |
| 1361 | 1429 | |
| ... | ... | @@ -1366,43 +1434,56 @@ pub const DeclGen = struct { |
| 1366 | 1434 | if (field_ty.hasRuntimeBits(zcu)) { |
| 1367 | 1435 | if (field_ty.isPtrAtRuntime(zcu)) { |
| 1368 | 1436 | try writer.writeByte('('); |
| 1369 | | try dg.renderType(writer, ty); |
| 1437 | try dg.renderCType(writer, ctype); |
| 1370 | 1438 | try writer.writeByte(')'); |
| 1371 | 1439 | } else if (field_ty.zigTypeTag(zcu) == .Float) { |
| 1372 | 1440 | try writer.writeByte('('); |
| 1373 | | try dg.renderType(writer, ty); |
| 1441 | try dg.renderCType(writer, ctype); |
| 1374 | 1442 | try writer.writeByte(')'); |
| 1375 | 1443 | } |
| 1376 | | try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type); |
| 1377 | | } else { |
| 1378 | | try writer.writeAll("0"); |
| 1379 | | } |
| 1444 | try dg.renderValue(writer, Value.fromInterned(un.val), location); |
| 1445 | } else try writer.writeAll("0"); |
| 1380 | 1446 | return; |
| 1381 | 1447 | } |
| 1382 | 1448 | |
| 1383 | | try writer.writeByte('{'); |
| 1384 | | if (ty.unionTagTypeSafety(zcu)) |_| { |
| 1385 | | const layout = zcu.getUnionLayout(loaded_union); |
| 1386 | | if (layout.tag_size != 0) { |
| 1387 | | try writer.writeAll(" .tag = "); |
| 1388 | | try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type); |
| 1449 | const has_tag = loaded_union.hasTag(ip); |
| 1450 | if (has_tag) try writer.writeByte('{'); |
| 1451 | const aggregate = ctype.info(ctype_pool).aggregate; |
| 1452 | for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| { |
| 1453 | if (outer_field_index > 0) try writer.writeByte(','); |
| 1454 | switch (if (has_tag) |
| 1455 | aggregate.fields.at(outer_field_index, ctype_pool).name.index |
| 1456 | else |
| 1457 | .payload) { |
| 1458 | .tag => try dg.renderValue( |
| 1459 | writer, |
| 1460 | Value.fromInterned(un.tag), |
| 1461 | initializer_type, |
| 1462 | ), |
| 1463 | .payload => { |
| 1464 | try writer.writeByte('{'); |
| 1465 | if (field_ty.hasRuntimeBits(zcu)) { |
| 1466 | try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))}); |
| 1467 | try dg.renderValue( |
| 1468 | writer, |
| 1469 | Value.fromInterned(un.val), |
| 1470 | initializer_type, |
| 1471 | ); |
| 1472 | try writer.writeByte(' '); |
| 1473 | } else for (0..loaded_union.field_types.len) |inner_field_index| { |
| 1474 | const inner_field_ty = Type.fromInterned( |
| 1475 | loaded_union.field_types.get(ip)[inner_field_index], |
| 1476 | ); |
| 1477 | if (!inner_field_ty.hasRuntimeBits(zcu)) continue; |
| 1478 | try dg.renderUndefValue(writer, inner_field_ty, initializer_type); |
| 1479 | break; |
| 1480 | } |
| 1481 | try writer.writeByte('}'); |
| 1482 | }, |
| 1483 | else => unreachable, |
| 1389 | 1484 | } |
| 1390 | | if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}'); |
| 1391 | | if (layout.tag_size != 0) try writer.writeByte(','); |
| 1392 | | try writer.writeAll(" .payload = {"); |
| 1393 | | } |
| 1394 | | if (field_ty.hasRuntimeBits(zcu)) { |
| 1395 | | try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))}); |
| 1396 | | try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type); |
| 1397 | | try writer.writeByte(' '); |
| 1398 | | } else for (0..loaded_union.field_types.len) |this_field_index| { |
| 1399 | | const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]); |
| 1400 | | if (!this_field_ty.hasRuntimeBits(zcu)) continue; |
| 1401 | | try dg.renderUndefValue(writer, this_field_ty, initializer_type); |
| 1402 | | break; |
| 1403 | 1485 | } |
| 1404 | | if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}'); |
| 1405 | | try writer.writeByte('}'); |
| 1486 | if (has_tag) try writer.writeByte('}'); |
| 1406 | 1487 | } |
| 1407 | 1488 | }, |
| 1408 | 1489 | } |
| ... | ... | @@ -1417,6 +1498,7 @@ pub const DeclGen = struct { |
| 1417 | 1498 | const zcu = dg.zcu; |
| 1418 | 1499 | const ip = &zcu.intern_pool; |
| 1419 | 1500 | const target = &dg.mod.resolved_target.result; |
| 1501 | const ctype_pool = &dg.ctype_pool; |
| 1420 | 1502 | |
| 1421 | 1503 | const initializer_type: ValueRenderLocation = switch (location) { |
| 1422 | 1504 | .StaticInitializer => .StaticInitializer, |
| ... | ... | @@ -1428,6 +1510,7 @@ pub const DeclGen = struct { |
| 1428 | 1510 | .ReleaseFast, .ReleaseSmall => false, |
| 1429 | 1511 | }; |
| 1430 | 1512 | |
| 1513 | const ctype = try dg.ctypeFromType(ty, location.toCTypeKind()); |
| 1431 | 1514 | switch (ty.toIntern()) { |
| 1432 | 1515 | .c_longdouble_type, |
| 1433 | 1516 | .f16_type, |
| ... | ... | @@ -1465,48 +1548,64 @@ pub const DeclGen = struct { |
| 1465 | 1548 | => return writer.print("{x}", .{ |
| 1466 | 1549 | try dg.fmtIntLiteral(try zcu.undefValue(ty), location), |
| 1467 | 1550 | }), |
| 1468 | | .ptr_type => if (ty.isSlice(zcu)) { |
| 1469 | | if (!location.isInitializer()) { |
| 1470 | | try writer.writeByte('('); |
| 1471 | | try dg.renderType(writer, ty); |
| 1472 | | try writer.writeByte(')'); |
| 1473 | | } |
| 1551 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 1552 | .One, .Many, .C => { |
| 1553 | try writer.writeAll("(("); |
| 1554 | try dg.renderCType(writer, ctype); |
| 1555 | return writer.print("){x})", .{ |
| 1556 | try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other), |
| 1557 | }); |
| 1558 | }, |
| 1559 | .Slice => { |
| 1560 | if (!location.isInitializer()) { |
| 1561 | try writer.writeByte('('); |
| 1562 | try dg.renderCType(writer, ctype); |
| 1563 | try writer.writeByte(')'); |
| 1564 | } |
| 1474 | 1565 | |
| 1475 | | try writer.writeAll("{("); |
| 1476 | | const ptr_ty = ty.slicePtrFieldType(zcu); |
| 1477 | | try dg.renderType(writer, ptr_ty); |
| 1478 | | return writer.print("){x}, {0x}}}", .{ |
| 1479 | | try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other), |
| 1480 | | }); |
| 1481 | | } else { |
| 1482 | | try writer.writeAll("(("); |
| 1483 | | try dg.renderType(writer, ty); |
| 1484 | | return writer.print("){x})", .{ |
| 1485 | | try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other), |
| 1486 | | }); |
| 1566 | try writer.writeAll("{("); |
| 1567 | const ptr_ty = ty.slicePtrFieldType(zcu); |
| 1568 | try dg.renderType(writer, ptr_ty); |
| 1569 | return writer.print("){x}, {0x}}}", .{ |
| 1570 | try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other), |
| 1571 | }); |
| 1572 | }, |
| 1487 | 1573 | }, |
| 1488 | | .opt_type => { |
| 1489 | | const payload_ty = ty.optionalChild(zcu); |
| 1490 | | |
| 1491 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 1492 | | return dg.renderUndefValue(writer, Type.bool, location); |
| 1493 | | } |
| 1494 | | |
| 1495 | | if (ty.optionalReprIsPayload(zcu)) { |
| 1496 | | return dg.renderUndefValue(writer, payload_ty, location); |
| 1497 | | } |
| 1498 | | |
| 1499 | | if (!location.isInitializer()) { |
| 1500 | | try writer.writeByte('('); |
| 1501 | | try dg.renderType(writer, ty); |
| 1502 | | try writer.writeByte(')'); |
| 1503 | | } |
| 1504 | | |
| 1505 | | try writer.writeAll("{ .payload = "); |
| 1506 | | try dg.renderUndefValue(writer, payload_ty, initializer_type); |
| 1507 | | try writer.writeAll(", .is_null = "); |
| 1508 | | try dg.renderUndefValue(writer, Type.bool, initializer_type); |
| 1509 | | return writer.writeAll(" }"); |
| 1574 | .opt_type => |child_type| switch (ctype.info(ctype_pool)) { |
| 1575 | .basic, .pointer => try dg.renderUndefValue( |
| 1576 | writer, |
| 1577 | Type.fromInterned(if (ctype.isBool()) .bool_type else child_type), |
| 1578 | location, |
| 1579 | ), |
| 1580 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 1581 | .aggregate => |aggregate| { |
| 1582 | switch (aggregate.fields.at(0, ctype_pool).name.index) { |
| 1583 | .is_null, .payload => {}, |
| 1584 | .ptr, .len => return dg.renderUndefValue( |
| 1585 | writer, |
| 1586 | Type.fromInterned(child_type), |
| 1587 | location, |
| 1588 | ), |
| 1589 | else => unreachable, |
| 1590 | } |
| 1591 | if (!location.isInitializer()) { |
| 1592 | try writer.writeByte('('); |
| 1593 | try dg.renderCType(writer, ctype); |
| 1594 | try writer.writeByte(')'); |
| 1595 | } |
| 1596 | try writer.writeByte('{'); |
| 1597 | for (0..aggregate.fields.len) |field_index| { |
| 1598 | if (field_index > 0) try writer.writeByte(','); |
| 1599 | try dg.renderUndefValue(writer, Type.fromInterned( |
| 1600 | switch (aggregate.fields.at(field_index, ctype_pool).name.index) { |
| 1601 | .is_null => .bool_type, |
| 1602 | .payload => child_type, |
| 1603 | else => unreachable, |
| 1604 | }, |
| 1605 | ), initializer_type); |
| 1606 | } |
| 1607 | try writer.writeByte('}'); |
| 1608 | }, |
| 1510 | 1609 | }, |
| 1511 | 1610 | .struct_type => { |
| 1512 | 1611 | const loaded_struct = ip.loadStructType(ty.toIntern()); |
| ... | ... | @@ -1514,7 +1613,7 @@ pub const DeclGen = struct { |
| 1514 | 1613 | .auto, .@"extern" => { |
| 1515 | 1614 | if (!location.isInitializer()) { |
| 1516 | 1615 | try writer.writeByte('('); |
| 1517 | | try dg.renderType(writer, ty); |
| 1616 | try dg.renderCType(writer, ctype); |
| 1518 | 1617 | try writer.writeByte(')'); |
| 1519 | 1618 | } |
| 1520 | 1619 | |
| ... | ... | @@ -1539,7 +1638,7 @@ pub const DeclGen = struct { |
| 1539 | 1638 | .anon_struct_type => |anon_struct_info| { |
| 1540 | 1639 | if (!location.isInitializer()) { |
| 1541 | 1640 | try writer.writeByte('('); |
| 1542 | | try dg.renderType(writer, ty); |
| 1641 | try dg.renderCType(writer, ctype); |
| 1543 | 1642 | try writer.writeByte(')'); |
| 1544 | 1643 | } |
| 1545 | 1644 | |
| ... | ... | @@ -1562,54 +1661,80 @@ pub const DeclGen = struct { |
| 1562 | 1661 | .auto, .@"extern" => { |
| 1563 | 1662 | if (!location.isInitializer()) { |
| 1564 | 1663 | try writer.writeByte('('); |
| 1565 | | try dg.renderType(writer, ty); |
| 1664 | try dg.renderCType(writer, ctype); |
| 1566 | 1665 | try writer.writeByte(')'); |
| 1567 | 1666 | } |
| 1568 | 1667 | |
| 1569 | | try writer.writeByte('{'); |
| 1570 | | if (ty.unionTagTypeSafety(zcu)) |tag_ty| { |
| 1571 | | const layout = ty.unionGetLayout(zcu); |
| 1572 | | if (layout.tag_size != 0) { |
| 1573 | | try writer.writeAll(" .tag = "); |
| 1574 | | try dg.renderUndefValue(writer, tag_ty, initializer_type); |
| 1668 | const has_tag = loaded_union.hasTag(ip); |
| 1669 | if (has_tag) try writer.writeByte('{'); |
| 1670 | const aggregate = ctype.info(ctype_pool).aggregate; |
| 1671 | for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| { |
| 1672 | if (outer_field_index > 0) try writer.writeByte(','); |
| 1673 | switch (if (has_tag) |
| 1674 | aggregate.fields.at(outer_field_index, ctype_pool).name.index |
| 1675 | else |
| 1676 | .payload) { |
| 1677 | .tag => try dg.renderUndefValue( |
| 1678 | writer, |
| 1679 | Type.fromInterned(loaded_union.enum_tag_ty), |
| 1680 | initializer_type, |
| 1681 | ), |
| 1682 | .payload => { |
| 1683 | try writer.writeByte('{'); |
| 1684 | for (0..loaded_union.field_types.len) |inner_field_index| { |
| 1685 | const inner_field_ty = Type.fromInterned( |
| 1686 | loaded_union.field_types.get(ip)[inner_field_index], |
| 1687 | ); |
| 1688 | if (!inner_field_ty.hasRuntimeBits(zcu)) continue; |
| 1689 | try dg.renderUndefValue( |
| 1690 | writer, |
| 1691 | inner_field_ty, |
| 1692 | initializer_type, |
| 1693 | ); |
| 1694 | break; |
| 1695 | } |
| 1696 | try writer.writeByte('}'); |
| 1697 | }, |
| 1698 | else => unreachable, |
| 1575 | 1699 | } |
| 1576 | | if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}'); |
| 1577 | | if (layout.tag_size != 0) try writer.writeByte(','); |
| 1578 | | try writer.writeAll(" .payload = {"); |
| 1579 | | } |
| 1580 | | for (0..loaded_union.field_types.len) |field_index| { |
| 1581 | | const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]); |
| 1582 | | if (!field_ty.hasRuntimeBits(zcu)) continue; |
| 1583 | | try dg.renderUndefValue(writer, field_ty, initializer_type); |
| 1584 | | break; |
| 1585 | 1700 | } |
| 1586 | | if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}'); |
| 1587 | | return writer.writeByte('}'); |
| 1701 | if (has_tag) try writer.writeByte('}'); |
| 1588 | 1702 | }, |
| 1589 | 1703 | .@"packed" => return writer.print("{x}", .{ |
| 1590 | 1704 | try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other), |
| 1591 | 1705 | }), |
| 1592 | 1706 | } |
| 1593 | 1707 | }, |
| 1594 | | .error_union_type => { |
| 1595 | | const payload_ty = ty.errorUnionPayload(zcu); |
| 1596 | | const error_ty = ty.errorUnionSet(zcu); |
| 1597 | | |
| 1598 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 1599 | | return dg.renderUndefValue(writer, error_ty, location); |
| 1600 | | } |
| 1601 | | |
| 1602 | | if (!location.isInitializer()) { |
| 1603 | | try writer.writeByte('('); |
| 1604 | | try dg.renderType(writer, ty); |
| 1605 | | try writer.writeByte(')'); |
| 1606 | | } |
| 1607 | | |
| 1608 | | try writer.writeAll("{ .payload = "); |
| 1609 | | try dg.renderUndefValue(writer, payload_ty, initializer_type); |
| 1610 | | try writer.writeAll(", .error = "); |
| 1611 | | try dg.renderUndefValue(writer, error_ty, initializer_type); |
| 1612 | | return writer.writeAll(" }"); |
| 1708 | .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) { |
| 1709 | .basic => try dg.renderUndefValue( |
| 1710 | writer, |
| 1711 | Type.fromInterned(error_union_type.error_set_type), |
| 1712 | location, |
| 1713 | ), |
| 1714 | .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 1715 | .aggregate => |aggregate| { |
| 1716 | if (!location.isInitializer()) { |
| 1717 | try writer.writeByte('('); |
| 1718 | try dg.renderCType(writer, ctype); |
| 1719 | try writer.writeByte(')'); |
| 1720 | } |
| 1721 | try writer.writeByte('{'); |
| 1722 | for (0..aggregate.fields.len) |field_index| { |
| 1723 | if (field_index > 0) try writer.writeByte(','); |
| 1724 | try dg.renderUndefValue( |
| 1725 | writer, |
| 1726 | Type.fromInterned( |
| 1727 | switch (aggregate.fields.at(field_index, ctype_pool).name.index) { |
| 1728 | .@"error" => error_union_type.error_set_type, |
| 1729 | .payload => error_union_type.payload_type, |
| 1730 | else => unreachable, |
| 1731 | }, |
| 1732 | ), |
| 1733 | initializer_type, |
| 1734 | ); |
| 1735 | } |
| 1736 | try writer.writeByte('}'); |
| 1737 | }, |
| 1613 | 1738 | }, |
| 1614 | 1739 | .array_type, .vector_type => { |
| 1615 | 1740 | const ai = ty.arrayInfo(zcu); |
| ... | ... | @@ -1624,7 +1749,7 @@ pub const DeclGen = struct { |
| 1624 | 1749 | } else { |
| 1625 | 1750 | if (!location.isInitializer()) { |
| 1626 | 1751 | try writer.writeByte('('); |
| 1627 | | try dg.renderType(writer, ty); |
| 1752 | try dg.renderCType(writer, ctype); |
| 1628 | 1753 | try writer.writeByte(')'); |
| 1629 | 1754 | } |
| 1630 | 1755 | |
| ... | ... | @@ -1674,6 +1799,7 @@ pub const DeclGen = struct { |
| 1674 | 1799 | name: union(enum) { |
| 1675 | 1800 | export_index: u32, |
| 1676 | 1801 | ident: []const u8, |
| 1802 | fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString), |
| 1677 | 1803 | }, |
| 1678 | 1804 | ) !void { |
| 1679 | 1805 | const zcu = dg.zcu; |
| ... | ... | @@ -1717,6 +1843,7 @@ pub const DeclGen = struct { |
| 1717 | 1843 | try dg.renderDeclName(w, fn_decl_index, export_index); |
| 1718 | 1844 | }, |
| 1719 | 1845 | .ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }), |
| 1846 | .fmt_ctype_pool_string => |fmt| try w.print("{}{ }", .{ trailing, fmt }), |
| 1720 | 1847 | } |
| 1721 | 1848 | |
| 1722 | 1849 | try renderTypeSuffix( |
| ... | ... | @@ -1772,7 +1899,7 @@ pub const DeclGen = struct { |
| 1772 | 1899 | }); |
| 1773 | 1900 | } |
| 1774 | 1901 | }, |
| 1775 | | .ident => {}, |
| 1902 | .ident, .fmt_ctype_pool_string => {}, |
| 1776 | 1903 | } |
| 1777 | 1904 | }, |
| 1778 | 1905 | .complete => {}, |
| ... | ... | @@ -1800,11 +1927,11 @@ pub const DeclGen = struct { |
| 1800 | 1927 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| 1801 | 1928 | /// | `renderType` | "uint8_t *" | "uint8_t *[10]" | |
| 1802 | 1929 | /// |
| 1803 | | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1930 | fn renderType(dg: *DeclGen, w: anytype, t: Type) error{OutOfMemory}!void { |
| 1804 | 1931 | try dg.renderCType(w, try dg.ctypeFromType(t, .complete)); |
| 1805 | 1932 | } |
| 1806 | 1933 | |
| 1807 | | fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void { |
| 1934 | fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{OutOfMemory}!void { |
| 1808 | 1935 | _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{}); |
| 1809 | 1936 | try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{}); |
| 1810 | 1937 | } |
| ... | ... | @@ -1829,7 +1956,26 @@ pub const DeclGen = struct { |
| 1829 | 1956 | } |
| 1830 | 1957 | } |
| 1831 | 1958 | }; |
| 1959 | fn intCastIsNoop(dg: *DeclGen, dest_ty: Type, src_ty: Type) bool { |
| 1960 | const zcu = dg.zcu; |
| 1961 | const dest_bits = dest_ty.bitSize(zcu); |
| 1962 | const dest_int_info = dest_ty.intInfo(zcu); |
| 1963 | |
| 1964 | const src_is_ptr = src_ty.isPtrAtRuntime(zcu); |
| 1965 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { |
| 1966 | .unsigned => Type.usize, |
| 1967 | .signed => Type.isize, |
| 1968 | } else src_ty; |
| 1832 | 1969 | |
| 1970 | const src_bits = src_eff_ty.bitSize(zcu); |
| 1971 | const src_int_info = if (src_eff_ty.isAbiInt(zcu)) src_eff_ty.intInfo(zcu) else null; |
| 1972 | if (dest_bits <= 64 and src_bits <= 64) { |
| 1973 | const needs_cast = src_int_info == null or |
| 1974 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or |
| 1975 | dest_int_info.signedness != src_int_info.?.signedness); |
| 1976 | return !needs_cast and !src_is_ptr; |
| 1977 | } else return false; |
| 1978 | } |
| 1833 | 1979 | /// Renders a cast to an int type, from either an int or a pointer. |
| 1834 | 1980 | /// |
| 1835 | 1981 | /// Some platforms don't have 128 bit integers, so we need to use |
| ... | ... | @@ -1843,7 +1989,14 @@ pub const DeclGen = struct { |
| 1843 | 1989 | /// | > 64 bit integer | pointer | zig_make_<dest_ty>(0, (zig_<u|i>size)src) |
| 1844 | 1990 | /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src) |
| 1845 | 1991 | /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) |
| 1846 | | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { |
| 1992 | fn renderIntCast( |
| 1993 | dg: *DeclGen, |
| 1994 | w: anytype, |
| 1995 | dest_ty: Type, |
| 1996 | context: IntCastContext, |
| 1997 | src_ty: Type, |
| 1998 | location: ValueRenderLocation, |
| 1999 | ) !void { |
| 1847 | 2000 | const zcu = dg.zcu; |
| 1848 | 2001 | const dest_bits = dest_ty.bitSize(zcu); |
| 1849 | 2002 | const dest_int_info = dest_ty.intInfo(zcu); |
| ... | ... | @@ -1998,12 +2151,23 @@ pub const DeclGen = struct { |
| 1998 | 2151 | fmtIdent("payload"), |
| 1999 | 2152 | fmtIdent(ident), |
| 2000 | 2153 | }), |
| 2154 | .ctype_pool_string => |string| try w.print("{ }", .{ |
| 2155 | fmtCTypePoolString(string, &dg.ctype_pool), |
| 2156 | }), |
| 2001 | 2157 | } |
| 2002 | 2158 | } |
| 2003 | 2159 | |
| 2004 | 2160 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2005 | 2161 | switch (c_value) { |
| 2006 | | .none, .new_local, .local, .local_ref, .constant, .arg, .arg_array => unreachable, |
| 2162 | .none, |
| 2163 | .new_local, |
| 2164 | .local, |
| 2165 | .local_ref, |
| 2166 | .constant, |
| 2167 | .arg, |
| 2168 | .arg_array, |
| 2169 | .ctype_pool_string, |
| 2170 | => unreachable, |
| 2007 | 2171 | .field => |i| try w.print("f{d}", .{i}), |
| 2008 | 2172 | .decl => |decl| { |
| 2009 | 2173 | try w.writeAll("(*"); |
| ... | ... | @@ -2033,7 +2197,17 @@ pub const DeclGen = struct { |
| 2033 | 2197 | |
| 2034 | 2198 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2035 | 2199 | switch (c_value) { |
| 2036 | | .none, .new_local, .local, .local_ref, .constant, .field, .undef, .arg, .arg_array => unreachable, |
| 2200 | .none, |
| 2201 | .new_local, |
| 2202 | .local, |
| 2203 | .local_ref, |
| 2204 | .constant, |
| 2205 | .field, |
| 2206 | .undef, |
| 2207 | .arg, |
| 2208 | .arg_array, |
| 2209 | .ctype_pool_string, |
| 2210 | => unreachable, |
| 2037 | 2211 | .decl, .identifier, .payload_identifier => { |
| 2038 | 2212 | try dg.writeCValue(writer, c_value); |
| 2039 | 2213 | try writer.writeAll("->"); |
| ... | ... | @@ -2172,11 +2346,7 @@ pub const DeclGen = struct { |
| 2172 | 2346 | loc: ValueRenderLocation, |
| 2173 | 2347 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 2174 | 2348 | const zcu = dg.zcu; |
| 2175 | | const kind: CType.Kind = switch (loc) { |
| 2176 | | .FunctionArgument => .parameter, |
| 2177 | | .Initializer, .Other => .complete, |
| 2178 | | .StaticInitializer => .global, |
| 2179 | | }; |
| 2349 | const kind = loc.toCTypeKind(); |
| 2180 | 2350 | const ty = val.typeOf(zcu); |
| 2181 | 2351 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ |
| 2182 | 2352 | .dg = dg, |
| ... | ... | @@ -2439,7 +2609,7 @@ fn renderFields( |
| 2439 | 2609 | .suffix, |
| 2440 | 2610 | .{}, |
| 2441 | 2611 | ); |
| 2442 | | try writer.print("{}{ }", .{ trailing, fmtIdent(field_info.name.slice(ctype_pool)) }); |
| 2612 | try writer.print("{}{ }", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool) }); |
| 2443 | 2613 | try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{}); |
| 2444 | 2614 | try writer.writeAll(";\n"); |
| 2445 | 2615 | } |
| ... | ... | @@ -2698,9 +2868,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn |
| 2698 | 2868 | |
| 2699 | 2869 | try w.writeAll("static "); |
| 2700 | 2870 | try o.dg.renderType(w, name_slice_ty); |
| 2701 | | try w.writeByte(' '); |
| 2702 | | try w.writeAll(val.fn_name.slice(lazy_ctype_pool)); |
| 2703 | | try w.writeByte('('); |
| 2871 | try w.print(" {}(", .{val.fn_name.fmt(lazy_ctype_pool)}); |
| 2704 | 2872 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete); |
| 2705 | 2873 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2706 | 2874 | const tag_names = enum_ty.enumFields(zcu); |
| ... | ... | @@ -2744,21 +2912,18 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn |
| 2744 | 2912 | const fn_decl = zcu.declPtr(fn_decl_index); |
| 2745 | 2913 | const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete); |
| 2746 | 2914 | const fn_info = fn_ctype.info(ctype_pool).function; |
| 2747 | | const fn_name = val.fn_name.slice(lazy_ctype_pool); |
| 2915 | const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool); |
| 2748 | 2916 | |
| 2749 | 2917 | const fwd_decl_writer = o.dg.fwdDeclWriter(); |
| 2750 | 2918 | try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)}); |
| 2751 | | try o.dg.renderFunctionSignature( |
| 2752 | | fwd_decl_writer, |
| 2753 | | fn_decl_index, |
| 2754 | | .forward, |
| 2755 | | .{ .ident = fn_name }, |
| 2756 | | ); |
| 2919 | try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ |
| 2920 | .fmt_ctype_pool_string = fn_name, |
| 2921 | }); |
| 2757 | 2922 | try fwd_decl_writer.writeAll(";\n"); |
| 2758 | 2923 | |
| 2759 | 2924 | try w.print("static zig_{s} ", .{@tagName(key)}); |
| 2760 | 2925 | try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ |
| 2761 | | .ident = fn_name, |
| 2926 | .fmt_ctype_pool_string = fn_name, |
| 2762 | 2927 | }); |
| 2763 | 2928 | try w.writeAll(" {\n return "); |
| 2764 | 2929 | try o.dg.renderDeclName(w, fn_decl_index, 0); |
| ... | ... | @@ -3143,8 +3308,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3143 | 3308 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .none), |
| 3144 | 3309 | .not => try airNot (f, inst), |
| 3145 | 3310 | |
| 3146 | | .optional_payload => try airOptionalPayload(f, inst), |
| 3147 | | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), |
| 3311 | .optional_payload => try airOptionalPayload(f, inst, false), |
| 3312 | .optional_payload_ptr => try airOptionalPayload(f, inst, true), |
| 3148 | 3313 | .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst), |
| 3149 | 3314 | .wrap_optional => try airWrapOptional(f, inst), |
| 3150 | 3315 | |
| ... | ... | @@ -3153,10 +3318,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3153 | 3318 | .is_err_ptr => try airIsErr(f, inst, true, "!="), |
| 3154 | 3319 | .is_non_err_ptr => try airIsErr(f, inst, true, "=="), |
| 3155 | 3320 | |
| 3156 | | .is_null => try airIsNull(f, inst, "==", false), |
| 3157 | | .is_non_null => try airIsNull(f, inst, "!=", false), |
| 3158 | | .is_null_ptr => try airIsNull(f, inst, "==", true), |
| 3159 | | .is_non_null_ptr => try airIsNull(f, inst, "!=", true), |
| 3321 | .is_null => try airIsNull(f, inst, .eq, false), |
| 3322 | .is_non_null => try airIsNull(f, inst, .neq, false), |
| 3323 | .is_null_ptr => try airIsNull(f, inst, .eq, true), |
| 3324 | .is_non_null_ptr => try airIsNull(f, inst, .neq, true), |
| 3160 | 3325 | |
| 3161 | 3326 | .alloc => try airAlloc(f, inst), |
| 3162 | 3327 | .ret_ptr => try airRetPtr(f, inst), |
| ... | ... | @@ -3239,8 +3404,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3239 | 3404 | .slice_ptr => try airSliceField(f, inst, false, "ptr"), |
| 3240 | 3405 | .slice_len => try airSliceField(f, inst, false, "len"), |
| 3241 | 3406 | |
| 3242 | | .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"), |
| 3243 | 3407 | .ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"), |
| 3408 | .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"), |
| 3244 | 3409 | |
| 3245 | 3410 | .ptr_elem_val => try airPtrElemVal(f, inst), |
| 3246 | 3411 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), |
| ... | ... | @@ -3308,7 +3473,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3308 | 3473 | } |
| 3309 | 3474 | try f.value_map.putNoClobber(inst.toRef(), switch (result_value) { |
| 3310 | 3475 | .none => continue, |
| 3311 | | .new_local => |i| .{ .local = i }, |
| 3476 | .new_local => |local_index| .{ .local = local_index }, |
| 3312 | 3477 | else => result_value, |
| 3313 | 3478 | }); |
| 3314 | 3479 | } |
| ... | ... | @@ -3323,7 +3488,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ |
| 3323 | 3488 | |
| 3324 | 3489 | const writer = f.object.writer(); |
| 3325 | 3490 | const local = try f.allocLocal(inst, inst_ty); |
| 3326 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3491 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3327 | 3492 | try f.writeCValue(writer, local, .Other); |
| 3328 | 3493 | try a.assign(f, writer); |
| 3329 | 3494 | if (is_ptr) { |
| ... | ... | @@ -3349,7 +3514,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3349 | 3514 | |
| 3350 | 3515 | const writer = f.object.writer(); |
| 3351 | 3516 | const local = try f.allocLocal(inst, inst_ty); |
| 3352 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3517 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3353 | 3518 | try f.writeCValue(writer, local, .Other); |
| 3354 | 3519 | try a.assign(f, writer); |
| 3355 | 3520 | try f.writeCValue(writer, ptr, .Other); |
| ... | ... | @@ -3375,7 +3540,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3375 | 3540 | |
| 3376 | 3541 | const writer = f.object.writer(); |
| 3377 | 3542 | const local = try f.allocLocal(inst, inst_ty); |
| 3378 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3543 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3379 | 3544 | try f.writeCValue(writer, local, .Other); |
| 3380 | 3545 | try a.assign(f, writer); |
| 3381 | 3546 | try writer.writeByte('('); |
| ... | ... | @@ -3410,7 +3575,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3410 | 3575 | |
| 3411 | 3576 | const writer = f.object.writer(); |
| 3412 | 3577 | const local = try f.allocLocal(inst, inst_ty); |
| 3413 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3578 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3414 | 3579 | try f.writeCValue(writer, local, .Other); |
| 3415 | 3580 | try a.assign(f, writer); |
| 3416 | 3581 | try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" }); |
| ... | ... | @@ -3437,7 +3602,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3437 | 3602 | |
| 3438 | 3603 | const writer = f.object.writer(); |
| 3439 | 3604 | const local = try f.allocLocal(inst, inst_ty); |
| 3440 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3605 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3441 | 3606 | try f.writeCValue(writer, local, .Other); |
| 3442 | 3607 | try a.assign(f, writer); |
| 3443 | 3608 | if (elem_has_bits) try writer.writeByte('&'); |
| ... | ... | @@ -3466,7 +3631,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3466 | 3631 | |
| 3467 | 3632 | const writer = f.object.writer(); |
| 3468 | 3633 | const local = try f.allocLocal(inst, inst_ty); |
| 3469 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3634 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3470 | 3635 | try f.writeCValue(writer, local, .Other); |
| 3471 | 3636 | try a.assign(f, writer); |
| 3472 | 3637 | try f.writeCValue(writer, array, .Other); |
| ... | ... | @@ -3691,17 +3856,18 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3691 | 3856 | const operand_ty = f.typeOf(ty_op.operand); |
| 3692 | 3857 | const scalar_ty = operand_ty.scalarType(zcu); |
| 3693 | 3858 | |
| 3859 | if (f.object.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand); |
| 3860 | |
| 3694 | 3861 | const writer = f.object.writer(); |
| 3695 | 3862 | const local = try f.allocLocal(inst, inst_ty); |
| 3696 | 3863 | const v = try Vectorize.start(f, inst, writer, operand_ty); |
| 3697 | | const a = try Assignment.start(f, writer, scalar_ty); |
| 3864 | const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete)); |
| 3698 | 3865 | try f.writeCValue(writer, local, .Other); |
| 3699 | 3866 | try v.elem(f, writer); |
| 3700 | 3867 | try a.assign(f, writer); |
| 3701 | 3868 | try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other); |
| 3702 | 3869 | try a.end(f, writer); |
| 3703 | 3870 | try v.end(f, inst, writer); |
| 3704 | | |
| 3705 | 3871 | return local; |
| 3706 | 3872 | } |
| 3707 | 3873 | |
| ... | ... | @@ -3711,38 +3877,40 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3711 | 3877 | |
| 3712 | 3878 | const operand = try f.resolveInst(ty_op.operand); |
| 3713 | 3879 | try reap(f, inst, &.{ty_op.operand}); |
| 3880 | |
| 3714 | 3881 | const inst_ty = f.typeOfIndex(inst); |
| 3715 | 3882 | const inst_scalar_ty = inst_ty.scalarType(zcu); |
| 3716 | 3883 | const dest_int_info = inst_scalar_ty.intInfo(zcu); |
| 3717 | 3884 | const dest_bits = dest_int_info.bits; |
| 3718 | | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse |
| 3885 | const dest_c_bits = toCIntBits(dest_bits) orelse |
| 3719 | 3886 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3720 | 3887 | const operand_ty = f.typeOf(ty_op.operand); |
| 3721 | 3888 | const scalar_ty = operand_ty.scalarType(zcu); |
| 3722 | 3889 | const scalar_int_info = scalar_ty.intInfo(zcu); |
| 3723 | 3890 | |
| 3891 | const need_cast = dest_c_bits < 64; |
| 3892 | const need_lo = scalar_int_info.bits > 64 and dest_bits <= 64; |
| 3893 | const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits); |
| 3894 | if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand); |
| 3895 | |
| 3724 | 3896 | const writer = f.object.writer(); |
| 3725 | 3897 | const local = try f.allocLocal(inst, inst_ty); |
| 3726 | 3898 | const v = try Vectorize.start(f, inst, writer, operand_ty); |
| 3727 | | |
| 3899 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete)); |
| 3728 | 3900 | try f.writeCValue(writer, local, .Other); |
| 3729 | 3901 | try v.elem(f, writer); |
| 3730 | | try writer.writeAll(" = "); |
| 3731 | | |
| 3732 | | if (dest_c_bits < 64) { |
| 3902 | try a.assign(f, writer); |
| 3903 | if (need_cast) { |
| 3733 | 3904 | try writer.writeByte('('); |
| 3734 | 3905 | try f.renderType(writer, inst_scalar_ty); |
| 3735 | 3906 | try writer.writeByte(')'); |
| 3736 | 3907 | } |
| 3737 | | |
| 3738 | | const needs_lo = scalar_int_info.bits > 64 and dest_bits <= 64; |
| 3739 | | if (needs_lo) { |
| 3908 | if (need_lo) { |
| 3740 | 3909 | try writer.writeAll("zig_lo_"); |
| 3741 | 3910 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); |
| 3742 | 3911 | try writer.writeByte('('); |
| 3743 | 3912 | } |
| 3744 | | |
| 3745 | | if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { |
| 3913 | if (!need_mask) { |
| 3746 | 3914 | try f.writeCValue(writer, operand, .Other); |
| 3747 | 3915 | try v.elem(f, writer); |
| 3748 | 3916 | } else switch (dest_int_info.signedness) { |
| ... | ... | @@ -3782,11 +3950,9 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3782 | 3950 | try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)}); |
| 3783 | 3951 | }, |
| 3784 | 3952 | } |
| 3785 | | |
| 3786 | | if (needs_lo) try writer.writeByte(')'); |
| 3787 | | try writer.writeAll(";\n"); |
| 3953 | if (need_lo) try writer.writeByte(')'); |
| 3954 | try a.end(f, writer); |
| 3788 | 3955 | try v.end(f, inst, writer); |
| 3789 | | |
| 3790 | 3956 | return local; |
| 3791 | 3957 | } |
| 3792 | 3958 | |
| ... | ... | @@ -3797,7 +3963,7 @@ fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3797 | 3963 | const writer = f.object.writer(); |
| 3798 | 3964 | const inst_ty = f.typeOfIndex(inst); |
| 3799 | 3965 | const local = try f.allocLocal(inst, inst_ty); |
| 3800 | | const a = try Assignment.start(f, writer, inst_ty); |
| 3966 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 3801 | 3967 | try f.writeCValue(writer, local, .Other); |
| 3802 | 3968 | try a.assign(f, writer); |
| 3803 | 3969 | try f.writeCValue(writer, operand, .Other); |
| ... | ... | @@ -3842,9 +4008,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3842 | 4008 | const src_val = try f.resolveInst(bin_op.rhs); |
| 3843 | 4009 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3844 | 4010 | |
| 4011 | const src_scalar_ctype = try f.ctypeFromType(src_ty.scalarType(zcu), .complete); |
| 3845 | 4012 | const writer = f.object.writer(); |
| 3846 | | const v = try Vectorize.start(f, inst, writer, ptr_ty); |
| 3847 | | |
| 3848 | 4013 | if (need_memcpy) { |
| 3849 | 4014 | // For this memcpy to safely work we need the rhs to have the same |
| 3850 | 4015 | // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). |
| ... | ... | @@ -3863,6 +4028,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3863 | 4028 | break :blk new_local; |
| 3864 | 4029 | } else src_val; |
| 3865 | 4030 | |
| 4031 | const v = try Vectorize.start(f, inst, writer, ptr_ty); |
| 3866 | 4032 | try writer.writeAll("memcpy((char *)"); |
| 3867 | 4033 | try f.writeCValue(writer, ptr_val, .FunctionArgument); |
| 3868 | 4034 | try v.elem(f, writer); |
| ... | ... | @@ -3873,9 +4039,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3873 | 4039 | try writer.writeAll(", sizeof("); |
| 3874 | 4040 | try f.renderType(writer, src_ty); |
| 3875 | 4041 | try writer.writeAll("))"); |
| 3876 | | if (src_val == .constant) { |
| 3877 | | try freeLocal(f, inst, array_src.new_local, null); |
| 3878 | | } |
| 4042 | try f.freeCValue(inst, array_src); |
| 4043 | try writer.writeAll(";\n"); |
| 4044 | try v.end(f, inst, writer); |
| 3879 | 4045 | } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) { |
| 3880 | 4046 | const host_bits = ptr_info.packed_offset.host_size * 8; |
| 3881 | 4047 | const host_ty = try zcu.intType(.unsigned, host_bits); |
| ... | ... | @@ -3898,9 +4064,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3898 | 4064 | |
| 3899 | 4065 | const mask_val = try zcu.intValue_big(host_ty, mask.toConst()); |
| 3900 | 4066 | |
| 4067 | const v = try Vectorize.start(f, inst, writer, ptr_ty); |
| 4068 | const a = try Assignment.start(f, writer, src_scalar_ctype); |
| 3901 | 4069 | try f.writeCValueDeref(writer, ptr_val); |
| 3902 | 4070 | try v.elem(f, writer); |
| 3903 | | try writer.writeAll(" = zig_or_"); |
| 4071 | try a.assign(f, writer); |
| 4072 | try writer.writeAll("zig_or_"); |
| 3904 | 4073 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3905 | 4074 | try writer.writeAll("(zig_and_"); |
| 3906 | 4075 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| ... | ... | @@ -3931,16 +4100,27 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3931 | 4100 | try v.elem(f, writer); |
| 3932 | 4101 | if (cant_cast) try writer.writeByte(')'); |
| 3933 | 4102 | try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)}); |
| 4103 | try a.end(f, writer); |
| 4104 | try v.end(f, inst, writer); |
| 3934 | 4105 | } else { |
| 4106 | switch (ptr_val) { |
| 4107 | .local_ref => |ptr_local_index| switch (src_val) { |
| 4108 | .new_local, .local => |src_local_index| if (ptr_local_index == src_local_index) |
| 4109 | return .none, |
| 4110 | else => {}, |
| 4111 | }, |
| 4112 | else => {}, |
| 4113 | } |
| 4114 | const v = try Vectorize.start(f, inst, writer, ptr_ty); |
| 4115 | const a = try Assignment.start(f, writer, src_scalar_ctype); |
| 3935 | 4116 | try f.writeCValueDeref(writer, ptr_val); |
| 3936 | 4117 | try v.elem(f, writer); |
| 3937 | | try writer.writeAll(" = "); |
| 4118 | try a.assign(f, writer); |
| 3938 | 4119 | try f.writeCValue(writer, src_val, .Other); |
| 3939 | 4120 | try v.elem(f, writer); |
| 4121 | try a.end(f, writer); |
| 4122 | try v.end(f, inst, writer); |
| 3940 | 4123 | } |
| 3941 | | try writer.writeAll(";\n"); |
| 3942 | | try v.end(f, inst, writer); |
| 3943 | | |
| 3944 | 4124 | return .none; |
| 3945 | 4125 | } |
| 3946 | 4126 | |
| ... | ... | @@ -4103,6 +4283,7 @@ fn airEquality( |
| 4103 | 4283 | operator: std.math.CompareOperator, |
| 4104 | 4284 | ) !CValue { |
| 4105 | 4285 | const zcu = f.object.dg.zcu; |
| 4286 | const ctype_pool = &f.object.dg.ctype_pool; |
| 4106 | 4287 | const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 4107 | 4288 | |
| 4108 | 4289 | const operand_ty = f.typeOf(bin_op.lhs); |
| ... | ... | @@ -4124,28 +4305,47 @@ fn airEquality( |
| 4124 | 4305 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 4125 | 4306 | |
| 4126 | 4307 | const writer = f.object.writer(); |
| 4127 | | const inst_ty = f.typeOfIndex(inst); |
| 4128 | | const local = try f.allocLocal(inst, inst_ty); |
| 4129 | | const a = try Assignment.start(f, writer, inst_ty); |
| 4308 | const local = try f.allocLocal(inst, Type.bool); |
| 4309 | const a = try Assignment.start(f, writer, CType.bool); |
| 4130 | 4310 | try f.writeCValue(writer, local, .Other); |
| 4131 | 4311 | try a.assign(f, writer); |
| 4132 | 4312 | |
| 4133 | | if (operand_ty.zigTypeTag(zcu) == .Optional and !operand_ty.optionalReprIsPayload(zcu)) { |
| 4134 | | try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); |
| 4135 | | try writer.writeAll(" || "); |
| 4136 | | try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); |
| 4137 | | try writer.writeAll(" ? "); |
| 4138 | | try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); |
| 4139 | | try writer.writeAll(compareOperatorC(operator)); |
| 4140 | | try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); |
| 4141 | | try writer.writeAll(" : "); |
| 4142 | | try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" }); |
| 4143 | | try writer.writeAll(compareOperatorC(operator)); |
| 4144 | | try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" }); |
| 4145 | | } else { |
| 4146 | | try f.writeCValue(writer, lhs, .Other); |
| 4147 | | try writer.writeAll(compareOperatorC(operator)); |
| 4148 | | try f.writeCValue(writer, rhs, .Other); |
| 4313 | const operand_ctype = try f.ctypeFromType(operand_ty, .complete); |
| 4314 | switch (operand_ctype.info(ctype_pool)) { |
| 4315 | .basic, .pointer => { |
| 4316 | try f.writeCValue(writer, lhs, .Other); |
| 4317 | try writer.writeAll(compareOperatorC(operator)); |
| 4318 | try f.writeCValue(writer, rhs, .Other); |
| 4319 | }, |
| 4320 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 4321 | .aggregate => |aggregate| if (aggregate.fields.len == 2 and |
| 4322 | (aggregate.fields.at(0, ctype_pool).name.index == .is_null or |
| 4323 | aggregate.fields.at(1, ctype_pool).name.index == .is_null)) |
| 4324 | { |
| 4325 | try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); |
| 4326 | try writer.writeAll(" || "); |
| 4327 | try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); |
| 4328 | try writer.writeAll(" ? "); |
| 4329 | try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" }); |
| 4330 | try writer.writeAll(compareOperatorC(operator)); |
| 4331 | try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" }); |
| 4332 | try writer.writeAll(" : "); |
| 4333 | try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" }); |
| 4334 | try writer.writeAll(compareOperatorC(operator)); |
| 4335 | try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" }); |
| 4336 | } else for (0..aggregate.fields.len) |field_index| { |
| 4337 | if (field_index > 0) try writer.writeAll(switch (operator) { |
| 4338 | .lt, .lte, .gte, .gt => unreachable, |
| 4339 | .eq => " && ", |
| 4340 | .neq => " || ", |
| 4341 | }); |
| 4342 | const field_name: CValue = .{ |
| 4343 | .ctype_pool_string = aggregate.fields.at(field_index, ctype_pool).name, |
| 4344 | }; |
| 4345 | try f.writeCValueMember(writer, lhs, field_name); |
| 4346 | try writer.writeAll(compareOperatorC(operator)); |
| 4347 | try f.writeCValueMember(writer, rhs, field_name); |
| 4348 | }, |
| 4149 | 4349 | } |
| 4150 | 4350 | try a.end(f, writer); |
| 4151 | 4351 | |
| ... | ... | @@ -4155,12 +4355,11 @@ fn airEquality( |
| 4155 | 4355 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4156 | 4356 | const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4157 | 4357 | |
| 4158 | | const inst_ty = f.typeOfIndex(inst); |
| 4159 | 4358 | const operand = try f.resolveInst(un_op); |
| 4160 | 4359 | try reap(f, inst, &.{un_op}); |
| 4161 | 4360 | |
| 4162 | 4361 | const writer = f.object.writer(); |
| 4163 | | const local = try f.allocLocal(inst, inst_ty); |
| 4362 | const local = try f.allocLocal(inst, Type.bool); |
| 4164 | 4363 | try f.writeCValue(writer, local, .Other); |
| 4165 | 4364 | try writer.writeAll(" = "); |
| 4166 | 4365 | try f.writeCValue(writer, operand, .Other); |
| ... | ... | @@ -4180,39 +4379,34 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 4180 | 4379 | const inst_ty = f.typeOfIndex(inst); |
| 4181 | 4380 | const inst_scalar_ty = inst_ty.scalarType(zcu); |
| 4182 | 4381 | const elem_ty = inst_scalar_ty.elemType2(zcu); |
| 4382 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs); |
| 4383 | const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); |
| 4183 | 4384 | |
| 4184 | 4385 | const local = try f.allocLocal(inst, inst_ty); |
| 4185 | 4386 | const writer = f.object.writer(); |
| 4186 | 4387 | const v = try Vectorize.start(f, inst, writer, inst_ty); |
| 4388 | const a = try Assignment.start(f, writer, inst_scalar_ctype); |
| 4187 | 4389 | try f.writeCValue(writer, local, .Other); |
| 4188 | 4390 | try v.elem(f, writer); |
| 4189 | | try writer.writeAll(" = "); |
| 4190 | | |
| 4191 | | if (elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 4192 | | // We must convert to and from integer types to prevent UB if the operation |
| 4193 | | // results in a NULL pointer, or if LHS is NULL. The operation is only UB |
| 4194 | | // if the result is NULL and then dereferenced. |
| 4195 | | try writer.writeByte('('); |
| 4196 | | try f.renderType(writer, inst_scalar_ty); |
| 4197 | | try writer.writeAll(")(((uintptr_t)"); |
| 4198 | | try f.writeCValue(writer, lhs, .Other); |
| 4199 | | try v.elem(f, writer); |
| 4200 | | try writer.writeAll(") "); |
| 4201 | | try writer.writeByte(operator); |
| 4202 | | try writer.writeAll(" ("); |
| 4203 | | try f.writeCValue(writer, rhs, .Other); |
| 4204 | | try v.elem(f, writer); |
| 4205 | | try writer.writeAll("*sizeof("); |
| 4206 | | try f.renderType(writer, elem_ty); |
| 4207 | | try writer.writeAll(")))"); |
| 4208 | | } else { |
| 4209 | | try f.writeCValue(writer, lhs, .Other); |
| 4210 | | try v.elem(f, writer); |
| 4211 | | } |
| 4212 | | |
| 4213 | | try writer.writeAll(";\n"); |
| 4391 | try a.assign(f, writer); |
| 4392 | // We must convert to and from integer types to prevent UB if the operation |
| 4393 | // results in a NULL pointer, or if LHS is NULL. The operation is only UB |
| 4394 | // if the result is NULL and then dereferenced. |
| 4395 | try writer.writeByte('('); |
| 4396 | try f.renderCType(writer, inst_scalar_ctype); |
| 4397 | try writer.writeAll(")(((uintptr_t)"); |
| 4398 | try f.writeCValue(writer, lhs, .Other); |
| 4399 | try v.elem(f, writer); |
| 4400 | try writer.writeAll(") "); |
| 4401 | try writer.writeByte(operator); |
| 4402 | try writer.writeAll(" ("); |
| 4403 | try f.writeCValue(writer, rhs, .Other); |
| 4404 | try v.elem(f, writer); |
| 4405 | try writer.writeAll("*sizeof("); |
| 4406 | try f.renderType(writer, elem_ty); |
| 4407 | try writer.writeAll(")))"); |
| 4408 | try a.end(f, writer); |
| 4214 | 4409 | try v.end(f, inst, writer); |
| 4215 | | |
| 4216 | 4410 | return local; |
| 4217 | 4411 | } |
| 4218 | 4412 | |
| ... | ... | @@ -4273,14 +4467,14 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4273 | 4467 | const writer = f.object.writer(); |
| 4274 | 4468 | const local = try f.allocLocal(inst, inst_ty); |
| 4275 | 4469 | { |
| 4276 | | const a = try Assignment.start(f, writer, ptr_ty); |
| 4470 | const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete)); |
| 4277 | 4471 | try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); |
| 4278 | 4472 | try a.assign(f, writer); |
| 4279 | 4473 | try f.writeCValue(writer, ptr, .Other); |
| 4280 | 4474 | try a.end(f, writer); |
| 4281 | 4475 | } |
| 4282 | 4476 | { |
| 4283 | | const a = try Assignment.start(f, writer, Type.usize); |
| 4477 | const a = try Assignment.start(f, writer, CType.usize); |
| 4284 | 4478 | try f.writeCValueMember(writer, local, .{ .identifier = "len" }); |
| 4285 | 4479 | try a.assign(f, writer); |
| 4286 | 4480 | try f.writeCValue(writer, len, .Initializer); |
| ... | ... | @@ -4347,7 +4541,7 @@ fn airCall( |
| 4347 | 4541 | }).?; |
| 4348 | 4542 | const ret_ty = Type.fromInterned(fn_info.return_type); |
| 4349 | 4543 | const ret_ctype: CType = if (ret_ty.isNoReturn(zcu)) |
| 4350 | | .{ .index = .void } |
| 4544 | CType.void |
| 4351 | 4545 | else |
| 4352 | 4546 | try f.ctypeFromType(ret_ty, .parameter); |
| 4353 | 4547 | |
| ... | ... | @@ -4359,7 +4553,7 @@ fn airCall( |
| 4359 | 4553 | break :result .none; |
| 4360 | 4554 | } else if (f.liveness.isUnused(inst)) { |
| 4361 | 4555 | try writer.writeByte('('); |
| 4362 | | try f.renderCType(writer, .{ .index = .void }); |
| 4556 | try f.renderCType(writer, CType.void); |
| 4363 | 4557 | try writer.writeByte(')'); |
| 4364 | 4558 | break :result .none; |
| 4365 | 4559 | } else { |
| ... | ... | @@ -4414,10 +4608,7 @@ fn airCall( |
| 4414 | 4608 | if (need_comma) try writer.writeAll(", "); |
| 4415 | 4609 | need_comma = true; |
| 4416 | 4610 | try f.writeCValue(writer, resolved_arg, .FunctionArgument); |
| 4417 | | switch (resolved_arg) { |
| 4418 | | .new_local => |local| try freeLocal(f, inst, local, null), |
| 4419 | | else => {}, |
| 4420 | | } |
| 4611 | try f.freeCValue(inst, resolved_arg); |
| 4421 | 4612 | } |
| 4422 | 4613 | try writer.writeAll(");\n"); |
| 4423 | 4614 | |
| ... | ... | @@ -4601,7 +4792,7 @@ fn lowerTry( |
| 4601 | 4792 | } |
| 4602 | 4793 | |
| 4603 | 4794 | const local = try f.allocLocal(inst, inst_ty); |
| 4604 | | const a = try Assignment.start(f, writer, inst_ty); |
| 4795 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 4605 | 4796 | try f.writeCValue(writer, local, .Other); |
| 4606 | 4797 | try a.assign(f, writer); |
| 4607 | 4798 | if (is_ptr) { |
| ... | ... | @@ -4624,7 +4815,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4624 | 4815 | const operand = try f.resolveInst(branch.operand); |
| 4625 | 4816 | try reap(f, inst, &.{branch.operand}); |
| 4626 | 4817 | |
| 4627 | | const a = try Assignment.start(f, writer, operand_ty); |
| 4818 | const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete)); |
| 4628 | 4819 | try f.writeCValue(writer, result, .Other); |
| 4629 | 4820 | try a.assign(f, writer); |
| 4630 | 4821 | try f.writeCValue(writer, operand, .Other); |
| ... | ... | @@ -4637,53 +4828,17 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4637 | 4828 | |
| 4638 | 4829 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4639 | 4830 | const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4640 | | const dest_ty = f.typeOfIndex(inst); |
| 4831 | const inst_ty = f.typeOfIndex(inst); |
| 4641 | 4832 | |
| 4642 | 4833 | const operand = try f.resolveInst(ty_op.operand); |
| 4643 | 4834 | const operand_ty = f.typeOf(ty_op.operand); |
| 4644 | 4835 | |
| 4645 | | const bitcasted = try bitcast(f, dest_ty, operand, operand_ty); |
| 4836 | const bitcasted = try bitcast(f, inst_ty, operand, operand_ty); |
| 4646 | 4837 | try reap(f, inst, &.{ty_op.operand}); |
| 4647 | | return bitcasted.move(f, inst, dest_ty); |
| 4838 | return f.moveCValue(inst, inst_ty, bitcasted); |
| 4648 | 4839 | } |
| 4649 | 4840 | |
| 4650 | | const LocalResult = struct { |
| 4651 | | c_value: CValue, |
| 4652 | | need_free: bool, |
| 4653 | | |
| 4654 | | fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue { |
| 4655 | | const zcu = f.object.dg.zcu; |
| 4656 | | |
| 4657 | | if (lr.need_free) { |
| 4658 | | // Move the freshly allocated local to be owned by this instruction, |
| 4659 | | // by returning it here instead of freeing it. |
| 4660 | | return lr.c_value; |
| 4661 | | } |
| 4662 | | |
| 4663 | | const local = try f.allocLocal(inst, dest_ty); |
| 4664 | | try lr.free(f); |
| 4665 | | const writer = f.object.writer(); |
| 4666 | | try f.writeCValue(writer, local, .Other); |
| 4667 | | if (dest_ty.isAbiInt(zcu)) { |
| 4668 | | try writer.writeAll(" = "); |
| 4669 | | } else { |
| 4670 | | try writer.writeAll(" = ("); |
| 4671 | | try f.renderType(writer, dest_ty); |
| 4672 | | try writer.writeByte(')'); |
| 4673 | | } |
| 4674 | | try f.writeCValue(writer, lr.c_value, .Initializer); |
| 4675 | | try writer.writeAll(";\n"); |
| 4676 | | return local; |
| 4677 | | } |
| 4678 | | |
| 4679 | | fn free(lr: LocalResult, f: *Function) !void { |
| 4680 | | if (lr.need_free) { |
| 4681 | | try freeLocal(f, null, lr.c_value.new_local, null); |
| 4682 | | } |
| 4683 | | } |
| 4684 | | }; |
| 4685 | | |
| 4686 | | fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult { |
| 4841 | fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CValue { |
| 4687 | 4842 | const zcu = f.object.dg.zcu; |
| 4688 | 4843 | const target = &f.object.dg.mod.resolved_target.result; |
| 4689 | 4844 | const ctype_pool = &f.object.dg.ctype_pool; |
| ... | ... | @@ -4693,13 +4848,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4693 | 4848 | const src_info = dest_ty.intInfo(zcu); |
| 4694 | 4849 | const dest_info = operand_ty.intInfo(zcu); |
| 4695 | 4850 | if (src_info.signedness == dest_info.signedness and |
| 4696 | | src_info.bits == dest_info.bits) |
| 4697 | | { |
| 4698 | | return .{ |
| 4699 | | .c_value = operand, |
| 4700 | | .need_free = false, |
| 4701 | | }; |
| 4702 | | } |
| 4851 | src_info.bits == dest_info.bits) return operand; |
| 4703 | 4852 | } |
| 4704 | 4853 | |
| 4705 | 4854 | if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) { |
| ... | ... | @@ -4710,10 +4859,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4710 | 4859 | try writer.writeByte(')'); |
| 4711 | 4860 | try f.writeCValue(writer, operand, .Other); |
| 4712 | 4861 | try writer.writeAll(";\n"); |
| 4713 | | return .{ |
| 4714 | | .c_value = local, |
| 4715 | | .need_free = true, |
| 4716 | | }; |
| 4862 | return local; |
| 4717 | 4863 | } |
| 4718 | 4864 | |
| 4719 | 4865 | const operand_lval = if (operand == .constant) blk: { |
| ... | ... | @@ -4800,14 +4946,8 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4800 | 4946 | try writer.writeAll(");\n"); |
| 4801 | 4947 | } |
| 4802 | 4948 | |
| 4803 | | if (operand == .constant) { |
| 4804 | | try freeLocal(f, null, operand_lval.new_local, null); |
| 4805 | | } |
| 4806 | | |
| 4807 | | return .{ |
| 4808 | | .c_value = local, |
| 4809 | | .need_free = true, |
| 4810 | | }; |
| 4949 | try f.freeCValue(null, operand_lval); |
| 4950 | return local; |
| 4811 | 4951 | } |
| 4812 | 4952 | |
| 4813 | 4953 | fn airTrap(f: *Function, writer: anytype) !CValue { |
| ... | ... | @@ -4918,13 +5058,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4918 | 5058 | const writer = f.object.writer(); |
| 4919 | 5059 | |
| 4920 | 5060 | try writer.writeAll("switch ("); |
| 4921 | | if (condition_ty.zigTypeTag(zcu) == .Bool) { |
| 4922 | | try writer.writeByte('('); |
| 4923 | | try f.renderType(writer, Type.u1); |
| 4924 | | try writer.writeByte(')'); |
| 4925 | | } else if (condition_ty.isPtrAtRuntime(zcu)) { |
| 5061 | |
| 5062 | const lowered_condition_ty = if (condition_ty.toIntern() == .bool_type) |
| 5063 | Type.u1 |
| 5064 | else if (condition_ty.isPtrAtRuntime(zcu)) |
| 5065 | Type.usize |
| 5066 | else |
| 5067 | condition_ty; |
| 5068 | if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) { |
| 4926 | 5069 | try writer.writeByte('('); |
| 4927 | | try f.renderType(writer, Type.usize); |
| 5070 | try f.renderType(writer, lowered_condition_ty); |
| 4928 | 5071 | try writer.writeByte(')'); |
| 4929 | 5072 | } |
| 4930 | 5073 | try f.writeCValue(writer, condition, .Other); |
| ... | ... | @@ -4943,18 +5086,24 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4943 | 5086 | for (0..switch_br.data.cases_len) |case_i| { |
| 4944 | 5087 | const case = f.air.extraData(Air.SwitchBr.Case, extra_index); |
| 4945 | 5088 | const items = @as([]const Air.Inst.Ref, @ptrCast(f.air.extra[case.end..][0..case.data.items_len])); |
| 4946 | | const case_body: []const Air.Inst.Index = @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]); |
| 5089 | const case_body: []const Air.Inst.Index = |
| 5090 | @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]); |
| 4947 | 5091 | extra_index = case.end + case.data.items_len + case_body.len; |
| 4948 | 5092 | |
| 4949 | 5093 | for (items) |item| { |
| 4950 | 5094 | try f.object.indent_writer.insertNewline(); |
| 4951 | 5095 | try writer.writeAll("case "); |
| 4952 | | if (condition_ty.isPtrAtRuntime(zcu)) { |
| 4953 | | try writer.writeByte('('); |
| 4954 | | try f.renderType(writer, Type.usize); |
| 4955 | | try writer.writeByte(')'); |
| 5096 | const item_value = try f.air.value(item, zcu); |
| 5097 | if (item_value.?.getUnsignedInt(zcu)) |item_int| try writer.print("{}\n", .{ |
| 5098 | try f.fmtIntLiteral(try zcu.intValue(lowered_condition_ty, item_int)), |
| 5099 | }) else { |
| 5100 | if (condition_ty.isPtrAtRuntime(zcu)) { |
| 5101 | try writer.writeByte('('); |
| 5102 | try f.renderType(writer, Type.usize); |
| 5103 | try writer.writeByte(')'); |
| 5104 | } |
| 5105 | try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other); |
| 4956 | 5106 | } |
| 4957 | | try f.object.dg.renderValue(writer, (try f.air.value(item, zcu)).?, .Other); |
| 4958 | 5107 | try writer.writeByte(':'); |
| 4959 | 5108 | } |
| 4960 | 5109 | try writer.writeByte(' '); |
| ... | ... | @@ -5276,10 +5425,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5276 | 5425 | fn airIsNull( |
| 5277 | 5426 | f: *Function, |
| 5278 | 5427 | inst: Air.Inst.Index, |
| 5279 | | operator: []const u8, |
| 5428 | operator: std.math.CompareOperator, |
| 5280 | 5429 | is_ptr: bool, |
| 5281 | 5430 | ) !CValue { |
| 5282 | 5431 | const zcu = f.object.dg.zcu; |
| 5432 | const ctype_pool = &f.object.dg.ctype_pool; |
| 5283 | 5433 | const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 5284 | 5434 | |
| 5285 | 5435 | const writer = f.object.writer(); |
| ... | ... | @@ -5287,106 +5437,84 @@ fn airIsNull( |
| 5287 | 5437 | try reap(f, inst, &.{un_op}); |
| 5288 | 5438 | |
| 5289 | 5439 | const local = try f.allocLocal(inst, Type.bool); |
| 5440 | const a = try Assignment.start(f, writer, CType.bool); |
| 5290 | 5441 | try f.writeCValue(writer, local, .Other); |
| 5291 | | try writer.writeAll(" = "); |
| 5292 | | if (is_ptr) { |
| 5293 | | try f.writeCValueDeref(writer, operand); |
| 5294 | | } else { |
| 5295 | | try f.writeCValue(writer, operand, .Other); |
| 5296 | | } |
| 5442 | try a.assign(f, writer); |
| 5297 | 5443 | |
| 5298 | 5444 | const operand_ty = f.typeOf(un_op); |
| 5299 | 5445 | const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty; |
| 5300 | | const payload_ty = optional_ty.optionalChild(zcu); |
| 5301 | | const err_int_ty = try zcu.errorIntType(); |
| 5302 | | |
| 5303 | | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) |
| 5304 | | Value.true |
| 5305 | | else if (optional_ty.isPtrLikeOptional(zcu)) |
| 5306 | | // operand is a regular pointer, test `operand !=/== NULL` |
| 5307 | | try zcu.getCoerced(Value.null, optional_ty) |
| 5308 | | else if (payload_ty.zigTypeTag(zcu) == .ErrorSet) |
| 5309 | | try zcu.intValue(err_int_ty, 0) |
| 5310 | | else if (payload_ty.isSlice(zcu) and optional_ty.optionalReprIsPayload(zcu)) rhs: { |
| 5311 | | try writer.writeAll(".ptr"); |
| 5312 | | const slice_ptr_ty = payload_ty.slicePtrFieldType(zcu); |
| 5313 | | const opt_slice_ptr_ty = try zcu.optionalType(slice_ptr_ty.toIntern()); |
| 5314 | | break :rhs try zcu.nullValue(opt_slice_ptr_ty); |
| 5315 | | } else rhs: { |
| 5316 | | try writer.writeAll(".is_null"); |
| 5317 | | break :rhs Value.true; |
| 5446 | const opt_ctype = try f.ctypeFromType(optional_ty, .complete); |
| 5447 | const rhs = switch (opt_ctype.info(ctype_pool)) { |
| 5448 | .basic, .pointer => rhs: { |
| 5449 | if (is_ptr) |
| 5450 | try f.writeCValueDeref(writer, operand) |
| 5451 | else |
| 5452 | try f.writeCValue(writer, operand, .Other); |
| 5453 | break :rhs if (opt_ctype.isBool()) |
| 5454 | "true" |
| 5455 | else if (opt_ctype.isInteger()) |
| 5456 | "0" |
| 5457 | else |
| 5458 | "NULL"; |
| 5459 | }, |
| 5460 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 5461 | .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { |
| 5462 | .is_null, .payload => rhs: { |
| 5463 | if (is_ptr) |
| 5464 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" }) |
| 5465 | else |
| 5466 | try f.writeCValueMember(writer, operand, .{ .identifier = "is_null" }); |
| 5467 | break :rhs "true"; |
| 5468 | }, |
| 5469 | .ptr, .len => rhs: { |
| 5470 | if (is_ptr) |
| 5471 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "ptr" }) |
| 5472 | else |
| 5473 | try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" }); |
| 5474 | break :rhs "NULL"; |
| 5475 | }, |
| 5476 | else => unreachable, |
| 5477 | }, |
| 5318 | 5478 | }; |
| 5319 | | try writer.writeByte(' '); |
| 5320 | | try writer.writeAll(operator); |
| 5321 | | try writer.writeByte(' '); |
| 5322 | | try f.object.dg.renderValue(writer, rhs, .Other); |
| 5323 | | try writer.writeAll(";\n"); |
| 5324 | | return local; |
| 5325 | | } |
| 5326 | | |
| 5327 | | fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5328 | | const zcu = f.object.dg.zcu; |
| 5329 | | const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5330 | | |
| 5331 | | const operand = try f.resolveInst(ty_op.operand); |
| 5332 | | try reap(f, inst, &.{ty_op.operand}); |
| 5333 | | const opt_ty = f.typeOf(ty_op.operand); |
| 5334 | | |
| 5335 | | const payload_ty = opt_ty.optionalChild(zcu); |
| 5336 | | |
| 5337 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5338 | | return .none; |
| 5339 | | } |
| 5340 | | |
| 5341 | | const inst_ty = f.typeOfIndex(inst); |
| 5342 | | const writer = f.object.writer(); |
| 5343 | | const local = try f.allocLocal(inst, inst_ty); |
| 5344 | | |
| 5345 | | if (opt_ty.optionalReprIsPayload(zcu)) { |
| 5346 | | try f.writeCValue(writer, local, .Other); |
| 5347 | | try writer.writeAll(" = "); |
| 5348 | | try f.writeCValue(writer, operand, .Other); |
| 5349 | | try writer.writeAll(";\n"); |
| 5350 | | return local; |
| 5351 | | } |
| 5352 | | |
| 5353 | | const a = try Assignment.start(f, writer, inst_ty); |
| 5354 | | try f.writeCValue(writer, local, .Other); |
| 5355 | | try a.assign(f, writer); |
| 5356 | | try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); |
| 5479 | try writer.writeAll(compareOperatorC(operator)); |
| 5480 | try writer.writeAll(rhs); |
| 5357 | 5481 | try a.end(f, writer); |
| 5358 | 5482 | return local; |
| 5359 | 5483 | } |
| 5360 | 5484 | |
| 5361 | | fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5485 | fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 5362 | 5486 | const zcu = f.object.dg.zcu; |
| 5487 | const ctype_pool = &f.object.dg.ctype_pool; |
| 5363 | 5488 | const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5364 | 5489 | |
| 5365 | | const writer = f.object.writer(); |
| 5366 | | const operand = try f.resolveInst(ty_op.operand); |
| 5367 | | try reap(f, inst, &.{ty_op.operand}); |
| 5368 | | const ptr_ty = f.typeOf(ty_op.operand); |
| 5369 | | const opt_ty = ptr_ty.childType(zcu); |
| 5370 | 5490 | const inst_ty = f.typeOfIndex(inst); |
| 5491 | const operand_ty = f.typeOf(ty_op.operand); |
| 5492 | const opt_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty; |
| 5493 | const opt_ctype = try f.ctypeFromType(opt_ty, .complete); |
| 5494 | if (opt_ctype.isBool()) return if (is_ptr) .{ .undef = inst_ty } else .none; |
| 5371 | 5495 | |
| 5372 | | if (!inst_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5373 | | return .{ .undef = inst_ty }; |
| 5374 | | } |
| 5375 | | |
| 5376 | | const local = try f.allocLocal(inst, inst_ty); |
| 5377 | | try f.writeCValue(writer, local, .Other); |
| 5378 | | |
| 5379 | | if (opt_ty.optionalReprIsPayload(zcu)) { |
| 5380 | | // the operand is just a regular pointer, no need to do anything special. |
| 5381 | | // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C |
| 5382 | | try writer.writeAll(" = "); |
| 5383 | | try f.writeCValue(writer, operand, .Other); |
| 5384 | | } else { |
| 5385 | | try writer.writeAll(" = &"); |
| 5386 | | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); |
| 5496 | const operand = try f.resolveInst(ty_op.operand); |
| 5497 | switch (opt_ctype.info(ctype_pool)) { |
| 5498 | .basic, .pointer => return f.moveCValue(inst, inst_ty, operand), |
| 5499 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 5500 | .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { |
| 5501 | .is_null, .payload => { |
| 5502 | const writer = f.object.writer(); |
| 5503 | const local = try f.allocLocal(inst, inst_ty); |
| 5504 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 5505 | try f.writeCValue(writer, local, .Other); |
| 5506 | try a.assign(f, writer); |
| 5507 | if (is_ptr) { |
| 5508 | try writer.writeByte('&'); |
| 5509 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); |
| 5510 | } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); |
| 5511 | try a.end(f, writer); |
| 5512 | return local; |
| 5513 | }, |
| 5514 | .ptr, .len => return f.moveCValue(inst, inst_ty, operand), |
| 5515 | else => unreachable, |
| 5516 | }, |
| 5387 | 5517 | } |
| 5388 | | try writer.writeAll(";\n"); |
| 5389 | | return local; |
| 5390 | 5518 | } |
| 5391 | 5519 | |
| 5392 | 5520 | fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -5397,38 +5525,46 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5397 | 5525 | try reap(f, inst, &.{ty_op.operand}); |
| 5398 | 5526 | const operand_ty = f.typeOf(ty_op.operand); |
| 5399 | 5527 | |
| 5400 | | const opt_ty = operand_ty.childType(zcu); |
| 5401 | | |
| 5402 | 5528 | const inst_ty = f.typeOfIndex(inst); |
| 5403 | | |
| 5404 | | if (opt_ty.optionalReprIsPayload(zcu)) { |
| 5405 | | if (f.liveness.isUnused(inst)) { |
| 5406 | | return .none; |
| 5407 | | } |
| 5408 | | const local = try f.allocLocal(inst, inst_ty); |
| 5409 | | // The payload and the optional are the same value. |
| 5410 | | // Setting to non-null will be done when the payload is set. |
| 5411 | | try f.writeCValue(writer, local, .Other); |
| 5412 | | try writer.writeAll(" = "); |
| 5413 | | try f.writeCValue(writer, operand, .Other); |
| 5414 | | try writer.writeAll(";\n"); |
| 5415 | | return local; |
| 5416 | | } else { |
| 5417 | | try f.writeCValueDeref(writer, operand); |
| 5418 | | try writer.writeAll(".is_null = "); |
| 5419 | | try f.object.dg.renderValue(writer, Value.false, .Initializer); |
| 5420 | | try writer.writeAll(";\n"); |
| 5421 | | |
| 5422 | | if (f.liveness.isUnused(inst)) { |
| 5529 | const opt_ctype = try f.ctypeFromType(operand_ty.childType(zcu), .complete); |
| 5530 | switch (opt_ctype.info(&f.object.dg.ctype_pool)) { |
| 5531 | .basic => { |
| 5532 | const a = try Assignment.start(f, writer, opt_ctype); |
| 5533 | try f.writeCValueDeref(writer, operand); |
| 5534 | try a.assign(f, writer); |
| 5535 | try f.object.dg.renderValue(writer, Value.false, .Initializer); |
| 5536 | try a.end(f, writer); |
| 5423 | 5537 | return .none; |
| 5424 | | } |
| 5425 | | |
| 5426 | | const local = try f.allocLocal(inst, inst_ty); |
| 5427 | | try f.writeCValue(writer, local, .Other); |
| 5428 | | try writer.writeAll(" = &"); |
| 5429 | | try f.writeCValueDeref(writer, operand); |
| 5430 | | try writer.writeAll(".payload;\n"); |
| 5431 | | return local; |
| 5538 | }, |
| 5539 | .pointer => { |
| 5540 | if (f.liveness.isUnused(inst)) return .none; |
| 5541 | const local = try f.allocLocal(inst, inst_ty); |
| 5542 | const a = try Assignment.start(f, writer, opt_ctype); |
| 5543 | try f.writeCValue(writer, local, .Other); |
| 5544 | try a.assign(f, writer); |
| 5545 | try f.writeCValue(writer, operand, .Other); |
| 5546 | try a.end(f, writer); |
| 5547 | return local; |
| 5548 | }, |
| 5549 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 5550 | .aggregate => { |
| 5551 | { |
| 5552 | const a = try Assignment.start(f, writer, opt_ctype); |
| 5553 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" }); |
| 5554 | try a.assign(f, writer); |
| 5555 | try f.object.dg.renderValue(writer, Value.false, .Initializer); |
| 5556 | try a.end(f, writer); |
| 5557 | } |
| 5558 | if (f.liveness.isUnused(inst)) return .none; |
| 5559 | const local = try f.allocLocal(inst, inst_ty); |
| 5560 | const a = try Assignment.start(f, writer, opt_ctype); |
| 5561 | try f.writeCValue(writer, local, .Other); |
| 5562 | try a.assign(f, writer); |
| 5563 | try writer.writeByte('&'); |
| 5564 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); |
| 5565 | try a.end(f, writer); |
| 5566 | return local; |
| 5567 | }, |
| 5432 | 5568 | } |
| 5433 | 5569 | } |
| 5434 | 5570 | |
| ... | ... | @@ -5688,13 +5824,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5688 | 5824 | if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local; |
| 5689 | 5825 | |
| 5690 | 5826 | const local = try f.allocLocal(inst, inst_ty); |
| 5691 | | try writer.writeAll("memcpy("); |
| 5692 | | try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument); |
| 5693 | | try writer.writeAll(", "); |
| 5694 | | try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument); |
| 5695 | | try writer.writeAll(", sizeof("); |
| 5696 | | try f.renderType(writer, inst_ty); |
| 5697 | | try writer.writeAll("));\n"); |
| 5827 | if (local.new_local != temp_local.new_local) { |
| 5828 | try writer.writeAll("memcpy("); |
| 5829 | try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument); |
| 5830 | try writer.writeAll(", "); |
| 5831 | try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument); |
| 5832 | try writer.writeAll(", sizeof("); |
| 5833 | try f.renderType(writer, inst_ty); |
| 5834 | try writer.writeAll("));\n"); |
| 5835 | } |
| 5698 | 5836 | try freeLocal(f, inst, temp_local.new_local, null); |
| 5699 | 5837 | return local; |
| 5700 | 5838 | }, |
| ... | ... | @@ -5723,20 +5861,23 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5723 | 5861 | try writer.writeAll(";\n"); |
| 5724 | 5862 | break :blk operand_local; |
| 5725 | 5863 | } else struct_byval; |
| 5726 | | |
| 5727 | 5864 | const local = try f.allocLocal(inst, inst_ty); |
| 5728 | | try writer.writeAll("memcpy(&"); |
| 5729 | | try f.writeCValue(writer, local, .Other); |
| 5730 | | try writer.writeAll(", &"); |
| 5731 | | try f.writeCValue(writer, operand_lval, .Other); |
| 5732 | | try writer.writeAll(", sizeof("); |
| 5733 | | try f.renderType(writer, inst_ty); |
| 5734 | | try writer.writeAll("));\n"); |
| 5735 | | |
| 5736 | | if (struct_byval == .constant) { |
| 5737 | | try freeLocal(f, inst, operand_lval.new_local, null); |
| 5865 | if (switch (local) { |
| 5866 | .new_local, .local => |local_index| switch (operand_lval) { |
| 5867 | .new_local, .local => |operand_local_index| local_index != operand_local_index, |
| 5868 | else => true, |
| 5869 | }, |
| 5870 | else => true, |
| 5871 | }) { |
| 5872 | try writer.writeAll("memcpy(&"); |
| 5873 | try f.writeCValue(writer, local, .Other); |
| 5874 | try writer.writeAll(", &"); |
| 5875 | try f.writeCValue(writer, operand_lval, .Other); |
| 5876 | try writer.writeAll(", sizeof("); |
| 5877 | try f.renderType(writer, inst_ty); |
| 5878 | try writer.writeAll("));\n"); |
| 5738 | 5879 | } |
| 5739 | | |
| 5880 | try f.freeCValue(inst, operand_lval); |
| 5740 | 5881 | return local; |
| 5741 | 5882 | }, |
| 5742 | 5883 | } |
| ... | ... | @@ -5745,7 +5886,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5745 | 5886 | }; |
| 5746 | 5887 | |
| 5747 | 5888 | const local = try f.allocLocal(inst, inst_ty); |
| 5748 | | const a = try Assignment.start(f, writer, inst_ty); |
| 5889 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 5749 | 5890 | try f.writeCValue(writer, local, .Other); |
| 5750 | 5891 | try a.assign(f, writer); |
| 5751 | 5892 | try f.writeCValueMember(writer, struct_byval, field_name); |
| ... | ... | @@ -5818,7 +5959,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 5818 | 5959 | } |
| 5819 | 5960 | |
| 5820 | 5961 | const local = try f.allocLocal(inst, inst_ty); |
| 5821 | | const a = try Assignment.start(f, writer, inst_ty); |
| 5962 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 5822 | 5963 | try f.writeCValue(writer, local, .Other); |
| 5823 | 5964 | try a.assign(f, writer); |
| 5824 | 5965 | if (is_ptr) { |
| ... | ... | @@ -5830,35 +5971,42 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 5830 | 5971 | } |
| 5831 | 5972 | |
| 5832 | 5973 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5833 | | const zcu = f.object.dg.zcu; |
| 5974 | const ctype_pool = &f.object.dg.ctype_pool; |
| 5834 | 5975 | const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 5835 | 5976 | |
| 5836 | 5977 | const inst_ty = f.typeOfIndex(inst); |
| 5837 | | const repr_is_payload = inst_ty.optionalReprIsPayload(zcu); |
| 5838 | | const payload_ty = f.typeOf(ty_op.operand); |
| 5839 | | const payload = try f.resolveInst(ty_op.operand); |
| 5840 | | try reap(f, inst, &.{ty_op.operand}); |
| 5978 | const inst_ctype = try f.ctypeFromType(inst_ty, .complete); |
| 5979 | if (inst_ctype.isBool()) return .{ .constant = Value.true }; |
| 5841 | 5980 | |
| 5842 | | const writer = f.object.writer(); |
| 5843 | | const local = try f.allocLocal(inst, inst_ty); |
| 5844 | | { |
| 5845 | | const a = try Assignment.start(f, writer, payload_ty); |
| 5846 | | if (repr_is_payload) |
| 5847 | | try f.writeCValue(writer, local, .Other) |
| 5848 | | else |
| 5849 | | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 5850 | | try a.assign(f, writer); |
| 5851 | | try f.writeCValue(writer, payload, .Other); |
| 5852 | | try a.end(f, writer); |
| 5853 | | } |
| 5854 | | if (!repr_is_payload) { |
| 5855 | | const a = try Assignment.start(f, writer, Type.bool); |
| 5856 | | try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); |
| 5857 | | try a.assign(f, writer); |
| 5858 | | try f.object.dg.renderValue(writer, Value.false, .Other); |
| 5859 | | try a.end(f, writer); |
| 5981 | const operand = try f.resolveInst(ty_op.operand); |
| 5982 | switch (inst_ctype.info(ctype_pool)) { |
| 5983 | .basic, .pointer => return f.moveCValue(inst, inst_ty, operand), |
| 5984 | .aligned, .array, .vector, .fwd_decl, .function => unreachable, |
| 5985 | .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) { |
| 5986 | .is_null, .payload => { |
| 5987 | const operand_ctype = try f.ctypeFromType(f.typeOf(ty_op.operand), .complete); |
| 5988 | const writer = f.object.writer(); |
| 5989 | const local = try f.allocLocal(inst, inst_ty); |
| 5990 | { |
| 5991 | const a = try Assignment.start(f, writer, CType.bool); |
| 5992 | try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); |
| 5993 | try a.assign(f, writer); |
| 5994 | try writer.writeAll("false"); |
| 5995 | try a.end(f, writer); |
| 5996 | } |
| 5997 | { |
| 5998 | const a = try Assignment.start(f, writer, operand_ctype); |
| 5999 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 6000 | try a.assign(f, writer); |
| 6001 | try f.writeCValue(writer, operand, .Initializer); |
| 6002 | try a.end(f, writer); |
| 6003 | } |
| 6004 | return local; |
| 6005 | }, |
| 6006 | .ptr, .len => return f.moveCValue(inst, inst_ty, operand), |
| 6007 | else => unreachable, |
| 6008 | }, |
| 5860 | 6009 | } |
| 5861 | | return local; |
| 5862 | 6010 | } |
| 5863 | 6011 | |
| 5864 | 6012 | fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -5881,14 +6029,14 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5881 | 6029 | } |
| 5882 | 6030 | |
| 5883 | 6031 | if (!repr_is_err) { |
| 5884 | | const a = try Assignment.start(f, writer, payload_ty); |
| 6032 | const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); |
| 5885 | 6033 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 5886 | 6034 | try a.assign(f, writer); |
| 5887 | 6035 | try f.object.dg.renderUndefValue(writer, payload_ty, .Other); |
| 5888 | 6036 | try a.end(f, writer); |
| 5889 | 6037 | } |
| 5890 | 6038 | { |
| 5891 | | const a = try Assignment.start(f, writer, err_ty); |
| 6039 | const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete)); |
| 5892 | 6040 | if (repr_is_err) |
| 5893 | 6041 | try f.writeCValue(writer, local, .Other) |
| 5894 | 6042 | else |
| ... | ... | @@ -5904,31 +6052,43 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5904 | 6052 | const zcu = f.object.dg.zcu; |
| 5905 | 6053 | const writer = f.object.writer(); |
| 5906 | 6054 | const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 6055 | const inst_ty = f.typeOfIndex(inst); |
| 5907 | 6056 | const operand = try f.resolveInst(ty_op.operand); |
| 5908 | | const error_union_ty = f.typeOf(ty_op.operand).childType(zcu); |
| 6057 | const operand_ty = f.typeOf(ty_op.operand); |
| 6058 | const error_union_ty = operand_ty.childType(zcu); |
| 5909 | 6059 | |
| 5910 | 6060 | const payload_ty = error_union_ty.errorUnionPayload(zcu); |
| 5911 | 6061 | const err_int_ty = try zcu.errorIntType(); |
| 5912 | 6062 | const no_err = try zcu.intValue(err_int_ty, 0); |
| 6063 | try reap(f, inst, &.{ty_op.operand}); |
| 5913 | 6064 | |
| 5914 | 6065 | // First, set the non-error value. |
| 5915 | 6066 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 6067 | const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete)); |
| 5916 | 6068 | try f.writeCValueDeref(writer, operand); |
| 5917 | | try writer.print(" = {};\n", .{try f.fmtIntLiteral(no_err)}); |
| 5918 | | return operand; |
| 6069 | try a.assign(f, writer); |
| 6070 | try writer.print("{}", .{try f.fmtIntLiteral(no_err)}); |
| 6071 | try a.end(f, writer); |
| 6072 | return .none; |
| 6073 | } |
| 6074 | { |
| 6075 | const a = try Assignment.start(f, writer, try f.ctypeFromType(err_int_ty, .complete)); |
| 6076 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }); |
| 6077 | try a.assign(f, writer); |
| 6078 | try writer.print("{}", .{try f.fmtIntLiteral(no_err)}); |
| 6079 | try a.end(f, writer); |
| 5919 | 6080 | } |
| 5920 | | try reap(f, inst, &.{ty_op.operand}); |
| 5921 | | try f.writeCValueDeref(writer, operand); |
| 5922 | | try writer.print(".error = {};\n", .{try f.fmtIntLiteral(no_err)}); |
| 5923 | 6081 | |
| 5924 | 6082 | // Then return the payload pointer (only if it is used) |
| 5925 | 6083 | if (f.liveness.isUnused(inst)) return .none; |
| 5926 | 6084 | |
| 5927 | | const local = try f.allocLocal(inst, f.typeOfIndex(inst)); |
| 6085 | const local = try f.allocLocal(inst, inst_ty); |
| 6086 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 5928 | 6087 | try f.writeCValue(writer, local, .Other); |
| 5929 | | try writer.writeAll(" = &("); |
| 5930 | | try f.writeCValueDeref(writer, operand); |
| 5931 | | try writer.writeAll(").payload;\n"); |
| 6088 | try a.assign(f, writer); |
| 6089 | try writer.writeByte('&'); |
| 6090 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); |
| 6091 | try a.end(f, writer); |
| 5932 | 6092 | return local; |
| 5933 | 6093 | } |
| 5934 | 6094 | |
| ... | ... | @@ -5961,14 +6121,14 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5961 | 6121 | const writer = f.object.writer(); |
| 5962 | 6122 | const local = try f.allocLocal(inst, inst_ty); |
| 5963 | 6123 | if (!repr_is_err) { |
| 5964 | | const a = try Assignment.start(f, writer, payload_ty); |
| 6124 | const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); |
| 5965 | 6125 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 5966 | 6126 | try a.assign(f, writer); |
| 5967 | 6127 | try f.writeCValue(writer, payload, .Other); |
| 5968 | 6128 | try a.end(f, writer); |
| 5969 | 6129 | } |
| 5970 | 6130 | { |
| 5971 | | const a = try Assignment.start(f, writer, err_ty); |
| 6131 | const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete)); |
| 5972 | 6132 | if (repr_is_err) |
| 5973 | 6133 | try f.writeCValue(writer, local, .Other) |
| 5974 | 6134 | else |
| ... | ... | @@ -5993,7 +6153,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const |
| 5993 | 6153 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 5994 | 6154 | const error_ty = err_union_ty.errorUnionSet(zcu); |
| 5995 | 6155 | |
| 5996 | | const a = try Assignment.start(f, writer, Type.bool); |
| 6156 | const a = try Assignment.start(f, writer, CType.bool); |
| 5997 | 6157 | try f.writeCValue(writer, local, .Other); |
| 5998 | 6158 | try a.assign(f, writer); |
| 5999 | 6159 | const err_int_ty = try zcu.errorIntType(); |
| ... | ... | @@ -6030,7 +6190,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6030 | 6190 | const array_ty = operand_ty.childType(zcu); |
| 6031 | 6191 | |
| 6032 | 6192 | { |
| 6033 | | const a = try Assignment.start(f, writer, ptr_ty); |
| 6193 | const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete)); |
| 6034 | 6194 | try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); |
| 6035 | 6195 | try a.assign(f, writer); |
| 6036 | 6196 | if (operand == .undef) { |
| ... | ... | @@ -6056,7 +6216,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6056 | 6216 | try a.end(f, writer); |
| 6057 | 6217 | } |
| 6058 | 6218 | { |
| 6059 | | const a = try Assignment.start(f, writer, Type.usize); |
| 6219 | const a = try Assignment.start(f, writer, CType.usize); |
| 6060 | 6220 | try f.writeCValueMember(writer, local, .{ .identifier = "len" }); |
| 6061 | 6221 | try a.assign(f, writer); |
| 6062 | 6222 | try writer.print("{}", .{ |
| ... | ... | @@ -6091,7 +6251,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6091 | 6251 | const writer = f.object.writer(); |
| 6092 | 6252 | const local = try f.allocLocal(inst, inst_ty); |
| 6093 | 6253 | const v = try Vectorize.start(f, inst, writer, operand_ty); |
| 6094 | | const a = try Assignment.start(f, writer, scalar_ty); |
| 6254 | const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete)); |
| 6095 | 6255 | try f.writeCValue(writer, local, .Other); |
| 6096 | 6256 | try v.elem(f, writer); |
| 6097 | 6257 | try a.assign(f, writer); |
| ... | ... | @@ -6133,11 +6293,10 @@ fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6133 | 6293 | try writer.writeAll(" = ("); |
| 6134 | 6294 | try f.renderType(writer, inst_ty); |
| 6135 | 6295 | try writer.writeByte(')'); |
| 6136 | | if (operand_ty.isSlice(zcu)) { |
| 6137 | | try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" }); |
| 6138 | | } else { |
| 6296 | if (operand_ty.isSlice(zcu)) |
| 6297 | try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" }) |
| 6298 | else |
| 6139 | 6299 | try f.writeCValue(writer, operand, .Other); |
| 6140 | | } |
| 6141 | 6300 | try writer.writeAll(";\n"); |
| 6142 | 6301 | return local; |
| 6143 | 6302 | } |
| ... | ... | @@ -6306,9 +6465,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6306 | 6465 | const new_value = try f.resolveInst(extra.new_value); |
| 6307 | 6466 | const ptr_ty = f.typeOf(extra.ptr); |
| 6308 | 6467 | const ty = ptr_ty.childType(zcu); |
| 6468 | const ctype = try f.ctypeFromType(ty, .complete); |
| 6309 | 6469 | |
| 6310 | 6470 | const writer = f.object.writer(); |
| 6311 | | const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value); |
| 6471 | const new_value_mat = try Materialize.start(f, inst, ty, new_value); |
| 6312 | 6472 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 6313 | 6473 | |
| 6314 | 6474 | const repr_ty = if (ty.isRuntimeFloat()) |
| ... | ... | @@ -6319,7 +6479,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6319 | 6479 | const local = try f.allocLocal(inst, inst_ty); |
| 6320 | 6480 | if (inst_ty.isPtrLikeOptional(zcu)) { |
| 6321 | 6481 | { |
| 6322 | | const a = try Assignment.start(f, writer, ty); |
| 6482 | const a = try Assignment.start(f, writer, ctype); |
| 6323 | 6483 | try f.writeCValue(writer, local, .Other); |
| 6324 | 6484 | try a.assign(f, writer); |
| 6325 | 6485 | try f.writeCValue(writer, expected_value, .Other); |
| ... | ... | @@ -6349,7 +6509,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6349 | 6509 | try writer.writeAll(") {\n"); |
| 6350 | 6510 | f.object.indent_writer.pushIndent(); |
| 6351 | 6511 | { |
| 6352 | | const a = try Assignment.start(f, writer, ty); |
| 6512 | const a = try Assignment.start(f, writer, ctype); |
| 6353 | 6513 | try f.writeCValue(writer, local, .Other); |
| 6354 | 6514 | try a.assign(f, writer); |
| 6355 | 6515 | try writer.writeAll("NULL"); |
| ... | ... | @@ -6359,14 +6519,14 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6359 | 6519 | try writer.writeAll("}\n"); |
| 6360 | 6520 | } else { |
| 6361 | 6521 | { |
| 6362 | | const a = try Assignment.start(f, writer, ty); |
| 6522 | const a = try Assignment.start(f, writer, ctype); |
| 6363 | 6523 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 6364 | 6524 | try a.assign(f, writer); |
| 6365 | 6525 | try f.writeCValue(writer, expected_value, .Other); |
| 6366 | 6526 | try a.end(f, writer); |
| 6367 | 6527 | } |
| 6368 | 6528 | { |
| 6369 | | const a = try Assignment.start(f, writer, Type.bool); |
| 6529 | const a = try Assignment.start(f, writer, CType.bool); |
| 6370 | 6530 | try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); |
| 6371 | 6531 | try a.assign(f, writer); |
| 6372 | 6532 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| ... | ... | @@ -6412,7 +6572,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6412 | 6572 | const operand = try f.resolveInst(extra.operand); |
| 6413 | 6573 | |
| 6414 | 6574 | const writer = f.object.writer(); |
| 6415 | | const operand_mat = try Materialize.start(f, inst, writer, ty, operand); |
| 6575 | const operand_mat = try Materialize.start(f, inst, ty, operand); |
| 6416 | 6576 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 6417 | 6577 | |
| 6418 | 6578 | const repr_bits = @as(u16, @intCast(ty.abiSize(zcu) * 8)); |
| ... | ... | @@ -6501,7 +6661,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 6501 | 6661 | const element = try f.resolveInst(bin_op.rhs); |
| 6502 | 6662 | |
| 6503 | 6663 | const writer = f.object.writer(); |
| 6504 | | const element_mat = try Materialize.start(f, inst, writer, ty, element); |
| 6664 | const element_mat = try Materialize.start(f, inst, ty, element); |
| 6505 | 6665 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6506 | 6666 | |
| 6507 | 6667 | const repr_ty = if (ty.isRuntimeFloat()) |
| ... | ... | @@ -6612,7 +6772,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6612 | 6772 | try f.writeCValue(writer, index, .Other); |
| 6613 | 6773 | try writer.writeAll(") "); |
| 6614 | 6774 | |
| 6615 | | const a = try Assignment.start(f, writer, elem_ty); |
| 6775 | const a = try Assignment.start(f, writer, try f.ctypeFromType(elem_ty, .complete)); |
| 6616 | 6776 | try writer.writeAll("(("); |
| 6617 | 6777 | try f.renderType(writer, elem_ptr_ty); |
| 6618 | 6778 | try writer.writeByte(')'); |
| ... | ... | @@ -6637,7 +6797,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6637 | 6797 | .Slice => { |
| 6638 | 6798 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); |
| 6639 | 6799 | try writer.writeAll(", "); |
| 6640 | | try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument); |
| 6800 | try f.writeCValue(writer, bitcasted, .FunctionArgument); |
| 6641 | 6801 | try writer.writeAll(", "); |
| 6642 | 6802 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); |
| 6643 | 6803 | try writer.writeAll(");\n"); |
| ... | ... | @@ -6648,12 +6808,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6648 | 6808 | |
| 6649 | 6809 | try f.writeCValue(writer, dest_slice, .FunctionArgument); |
| 6650 | 6810 | try writer.writeAll(", "); |
| 6651 | | try f.writeCValue(writer, bitcasted.c_value, .FunctionArgument); |
| 6811 | try f.writeCValue(writer, bitcasted, .FunctionArgument); |
| 6652 | 6812 | try writer.print(", {d});\n", .{len}); |
| 6653 | 6813 | }, |
| 6654 | 6814 | .Many, .C => unreachable, |
| 6655 | 6815 | } |
| 6656 | | try bitcasted.free(f); |
| 6816 | try f.freeCValue(inst, bitcasted); |
| 6657 | 6817 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6658 | 6818 | return .none; |
| 6659 | 6819 | } |
| ... | ... | @@ -6700,7 +6860,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6700 | 6860 | const tag_ty = union_ty.unionTagTypeSafety(zcu).?; |
| 6701 | 6861 | |
| 6702 | 6862 | const writer = f.object.writer(); |
| 6703 | | const a = try Assignment.start(f, writer, tag_ty); |
| 6863 | const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete)); |
| 6704 | 6864 | try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" }); |
| 6705 | 6865 | try a.assign(f, writer); |
| 6706 | 6866 | try f.writeCValue(writer, new_tag, .Other); |
| ... | ... | @@ -6722,7 +6882,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6722 | 6882 | const inst_ty = f.typeOfIndex(inst); |
| 6723 | 6883 | const writer = f.object.writer(); |
| 6724 | 6884 | const local = try f.allocLocal(inst, inst_ty); |
| 6725 | | const a = try Assignment.start(f, writer, inst_ty); |
| 6885 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete)); |
| 6726 | 6886 | try f.writeCValue(writer, local, .Other); |
| 6727 | 6887 | try a.assign(f, writer); |
| 6728 | 6888 | try f.writeCValueMember(writer, operand, .{ .identifier = "tag" }); |
| ... | ... | @@ -6780,7 +6940,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6780 | 6940 | const writer = f.object.writer(); |
| 6781 | 6941 | const local = try f.allocLocal(inst, inst_ty); |
| 6782 | 6942 | const v = try Vectorize.start(f, inst, writer, inst_ty); |
| 6783 | | const a = try Assignment.init(f, inst_scalar_ty); |
| 6943 | const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete)); |
| 6784 | 6944 | try f.writeCValue(writer, local, .Other); |
| 6785 | 6945 | try v.elem(f, writer); |
| 6786 | 6946 | try a.assign(f, writer); |
| ... | ... | @@ -7033,7 +7193,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7033 | 7193 | const local = try f.allocLocal(inst, inst_ty); |
| 7034 | 7194 | switch (ip.indexToKey(inst_ty.toIntern())) { |
| 7035 | 7195 | inline .array_type, .vector_type => |info, tag| { |
| 7036 | | const a = try Assignment.init(f, Type.fromInterned(info.child)); |
| 7196 | const a: Assignment = .{ |
| 7197 | .ctype = try f.ctypeFromType(Type.fromInterned(info.child), .complete), |
| 7198 | }; |
| 7037 | 7199 | for (resolved_elements, 0..) |element, i| { |
| 7038 | 7200 | try a.restart(f, writer); |
| 7039 | 7201 | try f.writeCValue(writer, local, .Other); |
| ... | ... | @@ -7060,7 +7222,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7060 | 7222 | const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); |
| 7061 | 7223 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; |
| 7062 | 7224 | |
| 7063 | | const a = try Assignment.start(f, writer, field_ty); |
| 7225 | const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete)); |
| 7064 | 7226 | try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name| |
| 7065 | 7227 | .{ .identifier = field_name.toSlice(ip) } |
| 7066 | 7228 | else |
| ... | ... | @@ -7140,7 +7302,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7140 | 7302 | const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]); |
| 7141 | 7303 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; |
| 7142 | 7304 | |
| 7143 | | const a = try Assignment.start(f, writer, field_ty); |
| 7305 | const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete)); |
| 7144 | 7306 | try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name| |
| 7145 | 7307 | .{ .identifier = field_name.toSlice(ip) } |
| 7146 | 7308 | else |
| ... | ... | @@ -7170,13 +7332,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7170 | 7332 | |
| 7171 | 7333 | const writer = f.object.writer(); |
| 7172 | 7334 | const local = try f.allocLocal(inst, union_ty); |
| 7173 | | if (loaded_union.getLayout(ip) == .@"packed") { |
| 7174 | | try f.writeCValue(writer, local, .Other); |
| 7175 | | try writer.writeAll(" = "); |
| 7176 | | try f.writeCValue(writer, payload, .Initializer); |
| 7177 | | try writer.writeAll(";\n"); |
| 7178 | | return local; |
| 7179 | | } |
| 7335 | if (loaded_union.getLayout(ip) == .@"packed") return f.moveCValue(inst, union_ty, payload); |
| 7180 | 7336 | |
| 7181 | 7337 | const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: { |
| 7182 | 7338 | const layout = union_ty.unionGetLayout(zcu); |
| ... | ... | @@ -7184,7 +7340,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7184 | 7340 | const field_index = tag_ty.enumFieldIndex(field_name, zcu).?; |
| 7185 | 7341 | const tag_val = try zcu.enumValueFieldIndex(tag_ty, field_index); |
| 7186 | 7342 | |
| 7187 | | const a = try Assignment.start(f, writer, tag_ty); |
| 7343 | const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete)); |
| 7188 | 7344 | try f.writeCValueMember(writer, local, .{ .identifier = "tag" }); |
| 7189 | 7345 | try a.assign(f, writer); |
| 7190 | 7346 | try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, zcu))}); |
| ... | ... | @@ -7193,7 +7349,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7193 | 7349 | break :field .{ .payload_identifier = field_name.toSlice(ip) }; |
| 7194 | 7350 | } else .{ .identifier = field_name.toSlice(ip) }; |
| 7195 | 7351 | |
| 7196 | | const a = try Assignment.start(f, writer, payload_ty); |
| 7352 | const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete)); |
| 7197 | 7353 | try f.writeCValueMember(writer, local, field); |
| 7198 | 7354 | try a.assign(f, writer); |
| 7199 | 7355 | try f.writeCValue(writer, payload, .Other); |
| ... | ... | @@ -7648,11 +7804,13 @@ fn StringLiteral(comptime WriterType: type) type { |
| 7648 | 7804 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal, |
| 7649 | 7805 | // regardless of the length of the string literal initializing it. Array initializer syntax is |
| 7650 | 7806 | // used instead. |
| 7651 | | const max_string_initializer_len = 65535; |
| 7807 | // C99 only requires 4095. |
| 7808 | const max_string_initializer_len = @min(65535, 4095); |
| 7652 | 7809 | |
| 7653 | 7810 | // MSVC has a length limit of 16380 per string literal (before concatenation) |
| 7811 | // C99 only requires 4095. |
| 7654 | 7812 | const max_char_len = 4; |
| 7655 | | const max_literal_len = 16380 - max_char_len; |
| 7813 | const max_literal_len = @min(16380 - max_char_len, 4095); |
| 7656 | 7814 | |
| 7657 | 7815 | return struct { |
| 7658 | 7816 | len: u64, |
| ... | ... | @@ -7824,13 +7982,13 @@ fn formatIntLiteral( |
| 7824 | 7982 | } = switch (data.ctype.info(ctype_pool)) { |
| 7825 | 7983 | .basic => |basic_info| switch (basic_info) { |
| 7826 | 7984 | else => .{ |
| 7827 | | .ctype = .{ .index = .void }, |
| 7985 | .ctype = CType.void, |
| 7828 | 7986 | .count = 1, |
| 7829 | 7987 | .endian = .little, |
| 7830 | 7988 | .homogeneous = true, |
| 7831 | 7989 | }, |
| 7832 | 7990 | .zig_u128, .zig_i128 => .{ |
| 7833 | | .ctype = .{ .index = .uint64_t }, |
| 7991 | .ctype = CType.u64, |
| 7834 | 7992 | .count = 2, |
| 7835 | 7993 | .endian = .big, |
| 7836 | 7994 | .homogeneous = false, |
| ... | ... | @@ -7946,28 +8104,12 @@ fn formatIntLiteral( |
| 7946 | 8104 | const Materialize = struct { |
| 7947 | 8105 | local: CValue, |
| 7948 | 8106 | |
| 7949 | | pub fn start( |
| 7950 | | f: *Function, |
| 7951 | | inst: Air.Inst.Index, |
| 7952 | | writer: anytype, |
| 7953 | | ty: Type, |
| 7954 | | value: CValue, |
| 7955 | | ) !Materialize { |
| 7956 | | switch (value) { |
| 7957 | | .local_ref, .constant, .decl_ref, .undef => { |
| 7958 | | const local = try f.allocLocal(inst, ty); |
| 7959 | | |
| 7960 | | const a = try Assignment.start(f, writer, ty); |
| 7961 | | try f.writeCValue(writer, local, .Other); |
| 7962 | | try a.assign(f, writer); |
| 7963 | | try f.writeCValue(writer, value, .Other); |
| 7964 | | try a.end(f, writer); |
| 7965 | | |
| 7966 | | return .{ .local = local }; |
| 7967 | | }, |
| 7968 | | .new_local => |local| return .{ .local = .{ .local = local } }, |
| 7969 | | else => return .{ .local = value }, |
| 7970 | | } |
| 8107 | pub fn start(f: *Function, inst: Air.Inst.Index, ty: Type, value: CValue) !Materialize { |
| 8108 | return .{ .local = switch (value) { |
| 8109 | .local_ref, .constant, .decl_ref, .undef => try f.moveCValue(inst, ty, value), |
| 8110 | .new_local => |local| .{ .local = local }, |
| 8111 | else => value, |
| 8112 | } }; |
| 7971 | 8113 | } |
| 7972 | 8114 | |
| 7973 | 8115 | pub fn mat(self: Materialize, f: *Function, writer: anytype) !void { |
| ... | ... | @@ -7975,22 +8117,15 @@ const Materialize = struct { |
| 7975 | 8117 | } |
| 7976 | 8118 | |
| 7977 | 8119 | pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void { |
| 7978 | | switch (self.local) { |
| 7979 | | .new_local => |local| try freeLocal(f, inst, local, null), |
| 7980 | | else => {}, |
| 7981 | | } |
| 8120 | try f.freeCValue(inst, self.local); |
| 7982 | 8121 | } |
| 7983 | 8122 | }; |
| 7984 | 8123 | |
| 7985 | 8124 | const Assignment = struct { |
| 7986 | 8125 | ctype: CType, |
| 7987 | 8126 | |
| 7988 | | pub fn init(f: *Function, ty: Type) !Assignment { |
| 7989 | | return .{ .ctype = try f.ctypeFromType(ty, .complete) }; |
| 7990 | | } |
| 7991 | | |
| 7992 | | pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment { |
| 7993 | | const self = try init(f, ty); |
| 8127 | pub fn start(f: *Function, writer: anytype, ctype: CType) !Assignment { |
| 8128 | const self: Assignment = .{ .ctype = ctype }; |
| 7994 | 8129 | try self.restart(f, writer); |
| 7995 | 8130 | return self; |
| 7996 | 8131 | } |