| ... | @@ -32,6 +32,8 @@ pub const CValue = union(enum) { | ... | @@ -32,6 +32,8 @@ pub const CValue = union(enum) { |
| 32 | constant: Air.Inst.Ref, | 32 | constant: Air.Inst.Ref, |
| 33 | /// Index into the parameters | 33 | /// Index into the parameters |
| 34 | arg: usize, | 34 | arg: usize, |
| | 35 | /// Index into a tuple's fields |
| | 36 | field: usize, |
| 35 | /// By-value | 37 | /// By-value |
| 36 | decl: Decl.Index, | 38 | decl: Decl.Index, |
| 37 | decl_ref: Decl.Index, | 39 | decl_ref: Decl.Index, |
| ... | @@ -79,7 +81,6 @@ const BuiltinInfo = enum { | ... | @@ -79,7 +81,6 @@ const BuiltinInfo = enum { |
| 79 | Bits, | 81 | Bits, |
| 80 | }; | 82 | }; |
| 81 | | 83 | |
| 82 | /// TODO make this not cut off at 128 bytes | | |
| 83 | fn formatTypeAsCIdentifier( | 84 | fn formatTypeAsCIdentifier( |
| 84 | data: FormatTypeAsCIdentContext, | 85 | data: FormatTypeAsCIdentContext, |
| 85 | comptime fmt: []const u8, | 86 | comptime fmt: []const u8, |
| ... | @@ -1297,7 +1298,8 @@ pub const DeclGen = struct { | ... | @@ -1297,7 +1298,8 @@ pub const DeclGen = struct { |
| 1297 | var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator); | 1298 | var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1298 | defer fqn_buf.deinit(); | 1299 | defer fqn_buf.deinit(); |
| 1299 | | 1300 | |
| 1300 | const owner_decl = dg.module.declPtr(child_ty.getOwnerDecl()); | 1301 | const owner_decl_index = child_ty.getOwnerDecl(); |
| | 1302 | const owner_decl = dg.module.declPtr(owner_decl_index); |
| 1301 | try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer()); | 1303 | try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer()); |
| 1302 | | 1304 | |
| 1303 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 1305 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| ... | @@ -1309,7 +1311,11 @@ pub const DeclGen = struct { | ... | @@ -1309,7 +1311,11 @@ pub const DeclGen = struct { |
| 1309 | else => unreachable, | 1311 | else => unreachable, |
| 1310 | }; | 1312 | }; |
| 1311 | const name_begin = buffer.items.len + "typedef ".len + tag.len; | 1313 | const name_begin = buffer.items.len + "typedef ".len + tag.len; |
| 1312 | try buffer.writer().print("typedef {s}zig_S_{} ", .{ tag, fmtIdent(fqn_buf.items) }); | 1314 | try buffer.writer().print("typedef {s}zig_S_{}__{d} ", .{ |
| | 1315 | tag, |
| | 1316 | fmtIdent(fqn_buf.items), |
| | 1317 | @enumToInt(owner_decl_index), |
| | 1318 | }); |
| 1313 | const name_end = buffer.items.len - " ".len; | 1319 | const name_end = buffer.items.len - " ".len; |
| 1314 | try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len); | 1320 | try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len); |
| 1315 | buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]); | 1321 | buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]); |
| ... | @@ -1378,26 +1384,17 @@ pub const DeclGen = struct { | ... | @@ -1378,26 +1384,17 @@ pub const DeclGen = struct { |
| 1378 | try buffer.appendSlice("typedef struct {\n"); | 1384 | try buffer.appendSlice("typedef struct {\n"); |
| 1379 | { | 1385 | { |
| 1380 | const fields = t.tupleFields(); | 1386 | const fields = t.tupleFields(); |
| 1381 | var empty = true; | 1387 | var field_id: usize = 0; |
| 1382 | for (fields.types) |field_ty, i| { | 1388 | for (fields.types) |field_ty, i| { |
| 1383 | if (!field_ty.hasRuntimeBits()) continue; | 1389 | if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue; |
| 1384 | const val = fields.values[i]; | | |
| 1385 | if (val.tag() != .unreachable_value) continue; | | |
| 1386 | | | |
| 1387 | var field_name_buf: []const u8 = &.{}; | | |
| 1388 | defer dg.typedefs.allocator.free(field_name_buf); | | |
| 1389 | const field_name = if (t.isTuple()) field_name: { | | |
| 1390 | field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); | | |
| 1391 | break :field_name field_name_buf; | | |
| 1392 | } else t.structFieldName(i); | | |
| 1393 | | 1390 | |
| 1394 | try buffer.append(' '); | 1391 | try buffer.append(' '); |
| 1395 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); | 1392 | try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete); |
| 1396 | try buffer.appendSlice(";\n"); | 1393 | try buffer.appendSlice(";\n"); |
| 1397 | | 1394 | |
| 1398 | empty = false; | 1395 | field_id += 1; |
| 1399 | } | 1396 | } |
| 1400 | if (empty) try buffer.appendSlice(" char empty_tuple;\n"); | 1397 | if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n"); |
| 1401 | } | 1398 | } |
| 1402 | const name_begin = buffer.items.len + "} ".len; | 1399 | const name_begin = buffer.items.len + "} ".len; |
| 1403 | try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); | 1400 | try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); |
| ... | @@ -1751,12 +1748,38 @@ pub const DeclGen = struct { | ... | @@ -1751,12 +1748,38 @@ pub const DeclGen = struct { |
| 1751 | }, | 1748 | }, |
| 1752 | .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) | 1749 | .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) |
| 1753 | try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) | 1750 | try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) |
| 1754 | else if (kind == .Complete or t.isTupleOrAnonStruct()) { | 1751 | else if (t.isTupleOrAnonStruct()) { |
| | 1752 | const ExpectedContents = struct { types: [8]Type, values: [8]Value }; |
| | 1753 | var stack align(@alignOf(ExpectedContents)) = |
| | 1754 | std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa); |
| | 1755 | const allocator = stack.get(); |
| | 1756 | |
| | 1757 | var tuple_storage = std.MultiArrayList(struct { type: Type, value: Value }){}; |
| | 1758 | defer tuple_storage.deinit(allocator); |
| | 1759 | try tuple_storage.ensureTotalCapacity(allocator, t.structFieldCount()); |
| | 1760 | |
| | 1761 | const fields = t.tupleFields(); |
| | 1762 | for (fields.values) |value, index| |
| | 1763 | if (value.tag() == .unreachable_value) |
| | 1764 | tuple_storage.appendAssumeCapacity(.{ |
| | 1765 | .type = fields.types[index], |
| | 1766 | .value = value, |
| | 1767 | }); |
| | 1768 | |
| | 1769 | const tuple_slice = tuple_storage.slice(); |
| | 1770 | var tuple_pl = Type.Payload.Tuple{ .data = .{ |
| | 1771 | .types = tuple_slice.items(.type), |
| | 1772 | .values = tuple_slice.items(.value), |
| | 1773 | } }; |
| | 1774 | const tuple_ty = Type.initPayload(&tuple_pl.base); |
| | 1775 | |
| | 1776 | const name = dg.getTypedefName(tuple_ty) orelse |
| | 1777 | try dg.renderTupleTypedef(tuple_ty); |
| | 1778 | |
| | 1779 | try w.writeAll(name); |
| | 1780 | } else if (kind == .Complete) { |
| 1755 | const name = dg.getTypedefName(t) orelse switch (tag) { | 1781 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1756 | .Struct => if (t.isTupleOrAnonStruct()) | 1782 | .Struct => try dg.renderStructTypedef(t), |
| 1757 | try dg.renderTupleTypedef(t) | | |
| 1758 | else | | |
| 1759 | try dg.renderStructTypedef(t), | | |
| 1760 | .Union => try dg.renderUnionTypedef(t), | 1783 | .Union => try dg.renderUnionTypedef(t), |
| 1761 | else => unreachable, | 1784 | else => unreachable, |
| 1762 | }; | 1785 | }; |
| ... | @@ -1976,6 +1999,7 @@ pub const DeclGen = struct { | ... | @@ -1976,6 +1999,7 @@ pub const DeclGen = struct { |
| 1976 | .local_ref => |i| return w.print("&t{d}", .{i}), | 1999 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 1977 | .constant => unreachable, | 2000 | .constant => unreachable, |
| 1978 | .arg => |i| return w.print("a{d}", .{i}), | 2001 | .arg => |i| return w.print("a{d}", .{i}), |
| | 2002 | .field => |i| return w.print("f{d}", .{i}), |
| 1979 | .decl => |decl| return dg.renderDeclName(w, decl), | 2003 | .decl => |decl| return dg.renderDeclName(w, decl), |
| 1980 | .decl_ref => |decl| { | 2004 | .decl_ref => |decl| { |
| 1981 | try w.writeByte('&'); | 2005 | try w.writeByte('&'); |
| ... | @@ -1994,6 +2018,7 @@ pub const DeclGen = struct { | ... | @@ -1994,6 +2018,7 @@ pub const DeclGen = struct { |
| 1994 | .local_ref => |i| return w.print("t{d}", .{i}), | 2018 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 1995 | .constant => unreachable, | 2019 | .constant => unreachable, |
| 1996 | .arg => |i| return w.print("(*a{d})", .{i}), | 2020 | .arg => |i| return w.print("(*a{d})", .{i}), |
| | 2021 | .field => |i| return w.print("f{d}", .{i}), |
| 1997 | .decl => |decl| { | 2022 | .decl => |decl| { |
| 1998 | try w.writeAll("(*"); | 2023 | try w.writeAll("(*"); |
| 1999 | try dg.renderDeclName(w, decl); | 2024 | try dg.renderDeclName(w, decl); |
| ... | @@ -2018,7 +2043,7 @@ pub const DeclGen = struct { | ... | @@ -2018,7 +2043,7 @@ pub const DeclGen = struct { |
| 2018 | | 2043 | |
| 2019 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | 2044 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2020 | switch (c_value) { | 2045 | switch (c_value) { |
| 2021 | .none, .constant, .undef => unreachable, | 2046 | .none, .constant, .field, .undef => unreachable, |
| 2022 | .local, .arg, .decl, .identifier, .bytes => { | 2047 | .local, .arg, .decl, .identifier, .bytes => { |
| 2023 | try dg.writeCValue(writer, c_value); | 2048 | try dg.writeCValue(writer, c_value); |
| 2024 | try writer.writeAll("->"); | 2049 | try writer.writeAll("->"); |
| ... | @@ -2236,12 +2261,6 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2236,12 +2261,6 @@ pub fn genDecl(o: *Object) !void { |
| 2236 | const variable: *Module.Var = var_payload.data; | 2261 | const variable: *Module.Var = var_payload.data; |
| 2237 | const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; | 2262 | const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; |
| 2238 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2263 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2239 | if (is_global) { | | |
| 2240 | try fwd_decl_writer.writeAll("zig_extern_c "); | | |
| 2241 | } | | |
| 2242 | if (variable.is_threadlocal) { | | |
| 2243 | try fwd_decl_writer.writeAll("zig_threadlocal "); | | |
| 2244 | } | | |
| 2245 | | 2264 | |
| 2246 | const decl_c_value: CValue = if (is_global) .{ | 2265 | const decl_c_value: CValue = if (is_global) .{ |
| 2247 | .bytes = mem.span(o.dg.decl.name), | 2266 | .bytes = mem.span(o.dg.decl.name), |
| ... | @@ -2249,6 +2268,8 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2249,6 +2268,8 @@ pub fn genDecl(o: *Object) !void { |
| 2249 | .decl = o.dg.decl_index, | 2268 | .decl = o.dg.decl_index, |
| 2250 | }; | 2269 | }; |
| 2251 | | 2270 | |
| | 2271 | if (is_global) try fwd_decl_writer.writeAll("zig_extern_c "); |
| | 2272 | if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal "); |
| 2252 | try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); | 2273 | try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2253 | try fwd_decl_writer.writeAll(";\n"); | 2274 | try fwd_decl_writer.writeAll(";\n"); |
| 2254 | | 2275 | |
| ... | @@ -2257,6 +2278,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2257,6 +2278,7 @@ pub fn genDecl(o: *Object) !void { |
| 2257 | } | 2278 | } |
| 2258 | | 2279 | |
| 2259 | const w = o.writer(); | 2280 | const w = o.writer(); |
| | 2281 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2260 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); | 2282 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2261 | try w.writeAll(" = "); | 2283 | try w.writeAll(" = "); |
| 2262 | if (variable.init.tag() != .unreachable_value) { | 2284 | if (variable.init.tag() != .unreachable_value) { |
| ... | @@ -2595,19 +2617,36 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ | ... | @@ -2595,19 +2617,36 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ |
| 2595 | } | 2617 | } |
| 2596 | | 2618 | |
| 2597 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 2619 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| | 2620 | const inst_ty = f.air.typeOfIndex(inst); |
| 2598 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2621 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2599 | const ptr_ty = f.air.typeOf(bin_op.lhs); | 2622 | const ptr_ty = f.air.typeOf(bin_op.lhs); |
| 2600 | if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; | 2623 | if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or |
| | 2624 | !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 2601 | | 2625 | |
| 2602 | const ptr = try f.resolveInst(bin_op.lhs); | 2626 | const ptr = try f.resolveInst(bin_op.lhs); |
| 2603 | const index = try f.resolveInst(bin_op.rhs); | 2627 | const index = try f.resolveInst(bin_op.rhs); |
| | 2628 | |
| | 2629 | const target = f.object.dg.module.getTarget(); |
| | 2630 | const is_array = lowersToArray(inst_ty, target); |
| | 2631 | |
| | 2632 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 2604 | const writer = f.object.writer(); | 2633 | const writer = f.object.writer(); |
| 2605 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 2634 | if (is_array) { |
| 2606 | try writer.writeAll(" = "); | 2635 | try writer.writeAll(";\n"); |
| | 2636 | try writer.writeAll("memcpy("); |
| | 2637 | try f.writeCValue(writer, local, .FunctionArgument); |
| | 2638 | try writer.writeAll(", "); |
| | 2639 | } else try writer.writeAll(" = "); |
| 2607 | try f.writeCValue(writer, ptr, .Other); | 2640 | try f.writeCValue(writer, ptr, .Other); |
| 2608 | try writer.writeByte('['); | 2641 | try writer.writeByte('['); |
| 2609 | try f.writeCValue(writer, index, .Other); | 2642 | try f.writeCValue(writer, index, .Other); |
| 2610 | try writer.writeAll("];\n"); | 2643 | try writer.writeByte(']'); |
| | 2644 | if (is_array) { |
| | 2645 | try writer.writeAll(", sizeof("); |
| | 2646 | try f.renderTypecast(writer, inst_ty); |
| | 2647 | try writer.writeAll("))"); |
| | 2648 | } |
| | 2649 | try writer.writeAll(";\n"); |
| 2611 | return local; | 2650 | return local; |
| 2612 | } | 2651 | } |
| 2613 | | 2652 | |
| ... | @@ -2637,19 +2676,36 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2637,19 +2676,36 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2637 | } | 2676 | } |
| 2638 | | 2677 | |
| 2639 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 2678 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| | 2679 | const inst_ty = f.air.typeOfIndex(inst); |
| 2640 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2680 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2641 | const slice_ty = f.air.typeOf(bin_op.lhs); | 2681 | const slice_ty = f.air.typeOf(bin_op.lhs); |
| 2642 | if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none; | 2682 | if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or |
| | 2683 | !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 2643 | | 2684 | |
| 2644 | const slice = try f.resolveInst(bin_op.lhs); | 2685 | const slice = try f.resolveInst(bin_op.lhs); |
| 2645 | const index = try f.resolveInst(bin_op.rhs); | 2686 | const index = try f.resolveInst(bin_op.rhs); |
| | 2687 | |
| | 2688 | const target = f.object.dg.module.getTarget(); |
| | 2689 | const is_array = lowersToArray(inst_ty, target); |
| | 2690 | |
| | 2691 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 2646 | const writer = f.object.writer(); | 2692 | const writer = f.object.writer(); |
| 2647 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 2693 | if (is_array) { |
| 2648 | try writer.writeAll(" = "); | 2694 | try writer.writeAll(";\n"); |
| | 2695 | try writer.writeAll("memcpy("); |
| | 2696 | try f.writeCValue(writer, local, .FunctionArgument); |
| | 2697 | try writer.writeAll(", "); |
| | 2698 | } else try writer.writeAll(" = "); |
| 2649 | try f.writeCValue(writer, slice, .Other); | 2699 | try f.writeCValue(writer, slice, .Other); |
| 2650 | try writer.writeAll(".ptr["); | 2700 | try writer.writeAll(".ptr["); |
| 2651 | try f.writeCValue(writer, index, .Other); | 2701 | try f.writeCValue(writer, index, .Other); |
| 2652 | try writer.writeAll("];\n"); | 2702 | try writer.writeByte(']'); |
| | 2703 | if (is_array) { |
| | 2704 | try writer.writeAll(", sizeof("); |
| | 2705 | try f.renderTypecast(writer, inst_ty); |
| | 2706 | try writer.writeAll("))"); |
| | 2707 | } |
| | 2708 | try writer.writeAll(";\n"); |
| 2653 | return local; | 2709 | return local; |
| 2654 | } | 2710 | } |
| 2655 | | 2711 | |
| ... | @@ -2672,18 +2728,34 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2672,18 +2728,34 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2672 | } | 2728 | } |
| 2673 | | 2729 | |
| 2674 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 2730 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2675 | if (f.liveness.isUnused(inst)) return CValue.none; | 2731 | const inst_ty = f.air.typeOfIndex(inst); |
| | 2732 | if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 2676 | | 2733 | |
| 2677 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2734 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2678 | const array = try f.resolveInst(bin_op.lhs); | 2735 | const array = try f.resolveInst(bin_op.lhs); |
| 2679 | const index = try f.resolveInst(bin_op.rhs); | 2736 | const index = try f.resolveInst(bin_op.rhs); |
| | 2737 | |
| | 2738 | const target = f.object.dg.module.getTarget(); |
| | 2739 | const is_array = lowersToArray(inst_ty, target); |
| | 2740 | |
| | 2741 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 2680 | const writer = f.object.writer(); | 2742 | const writer = f.object.writer(); |
| 2681 | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); | 2743 | if (is_array) { |
| 2682 | try writer.writeAll(" = "); | 2744 | try writer.writeAll(";\n"); |
| | 2745 | try writer.writeAll("memcpy("); |
| | 2746 | try f.writeCValue(writer, local, .FunctionArgument); |
| | 2747 | try writer.writeAll(", "); |
| | 2748 | } else try writer.writeAll(" = "); |
| 2683 | try f.writeCValue(writer, array, .Other); | 2749 | try f.writeCValue(writer, array, .Other); |
| 2684 | try writer.writeByte('['); | 2750 | try writer.writeByte('['); |
| 2685 | try f.writeCValue(writer, index, .Other); | 2751 | try f.writeCValue(writer, index, .Other); |
| 2686 | try writer.writeAll("];\n"); | 2752 | try writer.writeByte(']'); |
| | 2753 | if (is_array) { |
| | 2754 | try writer.writeAll(", sizeof("); |
| | 2755 | try f.renderTypecast(writer, inst_ty); |
| | 2756 | try writer.writeAll("))"); |
| | 2757 | } |
| | 2758 | try writer.writeAll(";\n"); |
| 2687 | return local; | 2759 | return local; |
| 2688 | } | 2760 | } |
| 2689 | | 2761 | |
| ... | @@ -2817,7 +2889,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | ... | @@ -2817,7 +2889,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 2817 | const array_local = try f.allocLocal(lowered_ret_ty, .Mut); | 2889 | const array_local = try f.allocLocal(lowered_ret_ty, .Mut); |
| 2818 | try writer.writeAll(";\n"); | 2890 | try writer.writeAll(";\n"); |
| 2819 | try writer.writeAll("memcpy("); | 2891 | try writer.writeAll("memcpy("); |
| 2820 | try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); | 2892 | try f.writeCValueMember(writer, array_local, .{ .field = 0 }); |
| 2821 | try writer.writeAll(", "); | 2893 | try writer.writeAll(", "); |
| 2822 | if (deref) | 2894 | if (deref) |
| 2823 | try f.writeCValueDeref(writer, operand) | 2895 | try f.writeCValueDeref(writer, operand) |
| ... | @@ -3063,13 +3135,13 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3063,13 +3135,13 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3063 | const local = try f.allocLocal(inst_ty, .Mut); | 3135 | const local = try f.allocLocal(inst_ty, .Mut); |
| 3064 | try w.writeAll(";\n"); | 3136 | try w.writeAll(";\n"); |
| 3065 | | 3137 | |
| 3066 | try f.writeCValue(w, local, .Other); | 3138 | try f.writeCValueMember(w, local, .{ .field = 1 }); |
| 3067 | try w.writeAll(".field_1 = zig_"); | 3139 | try w.writeAll(" = zig_"); |
| 3068 | try w.writeAll(operation); | 3140 | try w.writeAll(operation); |
| 3069 | try w.writeAll("o_"); | 3141 | try w.writeAll("o_"); |
| 3070 | try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); | 3142 | try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); |
| 3071 | try w.writeAll("(&"); | 3143 | try w.writeAll("(&"); |
| 3072 | try f.writeCValueMember(w, local, .{ .identifier = "field_0" }); | 3144 | try f.writeCValueMember(w, local, .{ .field = 0 }); |
| 3073 | try w.writeAll(", "); | 3145 | try w.writeAll(", "); |
| 3074 | try f.writeCValue(w, lhs, .FunctionArgument); | 3146 | try f.writeCValue(w, lhs, .FunctionArgument); |
| 3075 | try w.writeAll(", "); | 3147 | try w.writeAll(", "); |
| ... | @@ -3191,7 +3263,7 @@ fn airEquality( | ... | @@ -3191,7 +3263,7 @@ fn airEquality( |
| 3191 | | 3263 | |
| 3192 | try writer.writeAll(" = "); | 3264 | try writer.writeAll(" = "); |
| 3193 | | 3265 | |
| 3194 | if (operand_ty.tag() == .optional) { | 3266 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 3195 | // (A && B) || (C && (A == B)) | 3267 | // (A && B) || (C && (A == B)) |
| 3196 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload | 3268 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| 3197 | | 3269 | |
| ... | @@ -3429,7 +3501,7 @@ fn airCall( | ... | @@ -3429,7 +3501,7 @@ fn airCall( |
| 3429 | try writer.writeAll("memcpy("); | 3501 | try writer.writeAll("memcpy("); |
| 3430 | try f.writeCValue(writer, array_local, .FunctionArgument); | 3502 | try f.writeCValue(writer, array_local, .FunctionArgument); |
| 3431 | try writer.writeAll(", "); | 3503 | try writer.writeAll(", "); |
| 3432 | try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); | 3504 | try f.writeCValueMember(writer, result_local, .{ .field = 0 }); |
| 3433 | try writer.writeAll(", sizeof("); | 3505 | try writer.writeAll(", sizeof("); |
| 3434 | try f.renderTypecast(writer, ret_ty); | 3506 | try f.renderTypecast(writer, ret_ty); |
| 3435 | try writer.writeAll("));\n"); | 3507 | try writer.writeAll("));\n"); |
| ... | @@ -3590,25 +3662,39 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3590,25 +3662,39 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3590 | // If result is .none then the value of the block is unused. | 3662 | // If result is .none then the value of the block is unused. |
| 3591 | if (result != .none) { | 3663 | if (result != .none) { |
| 3592 | const operand = try f.resolveInst(branch.operand); | 3664 | const operand = try f.resolveInst(branch.operand); |
| 3593 | try f.writeCValue(writer, result, .Other); | 3665 | |
| 3594 | try writer.writeAll(" = "); | 3666 | const operand_ty = f.air.typeOf(branch.operand); |
| 3595 | try f.writeCValue(writer, operand, .Other); | 3667 | const target = f.object.dg.module.getTarget(); |
| | 3668 | if (lowersToArray(operand_ty, target)) { |
| | 3669 | try writer.writeAll("memcpy("); |
| | 3670 | try f.writeCValue(writer, result, .FunctionArgument); |
| | 3671 | try writer.writeAll(", "); |
| | 3672 | try f.writeCValue(writer, operand, .FunctionArgument); |
| | 3673 | try writer.writeAll(", sizeof("); |
| | 3674 | try f.renderTypecast(writer, operand_ty); |
| | 3675 | try writer.writeAll("))"); |
| | 3676 | } else { |
| | 3677 | try f.writeCValue(writer, result, .Other); |
| | 3678 | try writer.writeAll(" = "); |
| | 3679 | try f.writeCValue(writer, operand, .Other); |
| | 3680 | } |
| 3596 | try writer.writeAll(";\n"); | 3681 | try writer.writeAll(";\n"); |
| 3597 | } | 3682 | } |
| 3598 | | 3683 | |
| 3599 | try f.object.writer().print("goto zig_block_{d};\n", .{block.block_id}); | 3684 | try writer.print("goto zig_block_{d};\n", .{block.block_id}); |
| 3600 | return CValue.none; | 3685 | return CValue.none; |
| 3601 | } | 3686 | } |
| 3602 | | 3687 | |
| 3603 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | 3688 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3604 | if (f.liveness.isUnused(inst)) | 3689 | const inst_ty = f.air.typeOfIndex(inst); |
| 3605 | return CValue.none; | 3690 | // No IgnoreComptime until Sema stops giving us garbage Air. |
| | 3691 | // https://github.com/ziglang/zig/issues/13410 |
| | 3692 | if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none; |
| 3606 | | 3693 | |
| 3607 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3694 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3608 | const operand = try f.resolveInst(ty_op.operand); | 3695 | const operand = try f.resolveInst(ty_op.operand); |
| 3609 | | 3696 | |
| 3610 | const writer = f.object.writer(); | 3697 | const writer = f.object.writer(); |
| 3611 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3612 | if (inst_ty.isPtrAtRuntime() and | 3698 | if (inst_ty.isPtrAtRuntime() and |
| 3613 | f.air.typeOf(ty_op.operand).isPtrAtRuntime()) | 3699 | f.air.typeOf(ty_op.operand).isPtrAtRuntime()) |
| 3614 | { | 3700 | { |
| ... | @@ -3982,9 +4068,9 @@ fn airIsNull( | ... | @@ -3982,9 +4068,9 @@ fn airIsNull( |
| 3982 | | 4068 | |
| 3983 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | 4069 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) |
| 3984 | TypedValue{ .ty = Type.bool, .val = Value.@"true" } | 4070 | TypedValue{ .ty = Type.bool, .val = Value.@"true" } |
| 3985 | else if (operand_ty.isPtrLikeOptional()) | 4071 | else if (optional_ty.isPtrLikeOptional()) |
| 3986 | // operand is a regular pointer, test `operand !=/== NULL` | 4072 | // operand is a regular pointer, test `operand !=/== NULL` |
| 3987 | TypedValue{ .ty = operand_ty, .val = Value.@"null" } | 4073 | TypedValue{ .ty = optional_ty, .val = Value.@"null" } |
| 3988 | else if (payload_ty.zigTypeTag() == .ErrorSet) | 4074 | else if (payload_ty.zigTypeTag() == .ErrorSet) |
| 3989 | TypedValue{ .ty = payload_ty, .val = Value.zero } | 4075 | TypedValue{ .ty = payload_ty, .val = Value.zero } |
| 3990 | else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: { | 4076 | else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: { |
| ... | @@ -4007,26 +4093,34 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4007,26 +4093,34 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4007 | if (f.liveness.isUnused(inst)) return CValue.none; | 4093 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4008 | | 4094 | |
| 4009 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 4095 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4010 | const writer = f.object.writer(); | | |
| 4011 | const operand = try f.resolveInst(ty_op.operand); | 4096 | const operand = try f.resolveInst(ty_op.operand); |
| 4012 | const opt_ty = f.air.typeOf(ty_op.operand); | 4097 | const opt_ty = f.air.typeOf(ty_op.operand); |
| 4013 | | 4098 | |
| 4014 | var buf: Type.Payload.ElemType = undefined; | 4099 | var buf: Type.Payload.ElemType = undefined; |
| 4015 | const payload_ty = opt_ty.optionalChild(&buf); | 4100 | const payload_ty = opt_ty.optionalChild(&buf); |
| 4016 | | 4101 | |
| 4017 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4102 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 4018 | return CValue.none; | 4103 | if (opt_ty.optionalReprIsPayload()) return operand; |
| 4019 | } | | |
| 4020 | | | |
| 4021 | if (opt_ty.optionalReprIsPayload()) { | | |
| 4022 | return operand; | | |
| 4023 | } | | |
| 4024 | | 4104 | |
| 4025 | const inst_ty = f.air.typeOfIndex(inst); | 4105 | const inst_ty = f.air.typeOfIndex(inst); |
| 4026 | const local = try f.allocLocal(inst_ty, .Const); | 4106 | const target = f.object.dg.module.getTarget(); |
| 4027 | try writer.writeAll(" = ("); | 4107 | const is_array = lowersToArray(inst_ty, target); |
| 4028 | try f.writeCValue(writer, operand, .Other); | 4108 | |
| 4029 | try writer.writeAll(").payload;\n"); | 4109 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| | 4110 | const writer = f.object.writer(); |
| | 4111 | if (is_array) { |
| | 4112 | try writer.writeAll(";\n"); |
| | 4113 | try writer.writeAll("memcpy("); |
| | 4114 | try f.writeCValue(writer, local, .FunctionArgument); |
| | 4115 | try writer.writeAll(", "); |
| | 4116 | } else try writer.writeAll(" = "); |
| | 4117 | try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); |
| | 4118 | if (is_array) { |
| | 4119 | try writer.writeAll(", sizeof("); |
| | 4120 | try f.renderTypecast(writer, inst_ty); |
| | 4121 | try writer.writeAll("))"); |
| | 4122 | } |
| | 4123 | try writer.writeAll(";\n"); |
| 4030 | return local; | 4124 | return local; |
| 4031 | } | 4125 | } |
| 4032 | | 4126 | |
| ... | @@ -4159,16 +4253,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -4159,16 +4253,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 4159 | try f.renderTypecast(writer, field_ptr_ty); | 4253 | try f.renderTypecast(writer, field_ptr_ty); |
| 4160 | try writer.writeByte(')'); | 4254 | try writer.writeByte(')'); |
| 4161 | | 4255 | |
| 4162 | const extra_name: ?[]const u8 = switch (struct_ty.tag()) { | 4256 | const extra_name: CValue = switch (struct_ty.tag()) { |
| 4163 | .union_tagged, .union_safety_tagged => "payload", | 4257 | .union_tagged, .union_safety_tagged => .{ .identifier = "payload" }, |
| 4164 | else => null, | 4258 | else => .none, |
| 4165 | }; | 4259 | }; |
| 4166 | | 4260 | |
| 4167 | var field_name_buf: []const u8 = &.{}; | 4261 | const field_name: CValue = switch (struct_ty.tag()) { |
| 4168 | defer f.object.dg.gpa.free(field_name_buf); | | |
| 4169 | const field_name: ?[]const u8 = switch (struct_ty.tag()) { | | |
| 4170 | .@"struct" => switch (struct_ty.containerLayout()) { | 4262 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4171 | .Auto, .Extern => struct_ty.structFieldName(index), | 4263 | .Auto, .Extern => CValue{ .identifier = struct_ty.structFieldName(index) }, |
| 4172 | .Packed => if (field_ptr_info.data.host_size == 0) { | 4264 | .Packed => if (field_ptr_info.data.host_size == 0) { |
| 4173 | const target = f.object.dg.module.getTarget(); | 4265 | const target = f.object.dg.module.getTarget(); |
| 4174 | | 4266 | |
| ... | @@ -4189,29 +4281,35 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -4189,29 +4281,35 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 4189 | try f.writeCValue(writer, struct_ptr, .Other); | 4281 | try f.writeCValue(writer, struct_ptr, .Other); |
| 4190 | try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); | 4282 | try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| 4191 | return local; | 4283 | return local; |
| 4192 | } else null, | 4284 | } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug |
| | 4285 | }, |
| | 4286 | .@"union", .union_safety_tagged, .union_tagged => .{ |
| | 4287 | .identifier = struct_ty.unionFields().keys()[index], |
| 4193 | }, | 4288 | }, |
| 4194 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index], | 4289 | .tuple, .anon_struct => field_name: { |
| 4195 | .tuple, .anon_struct => |tag| field_name: { | | |
| 4196 | const tuple = struct_ty.tupleFields(); | 4290 | const tuple = struct_ty.tupleFields(); |
| 4197 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; | 4291 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; |
| 4198 | | 4292 | |
| 4199 | if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index); | 4293 | var id: usize = 0; |
| 4200 | | 4294 | for (tuple.values[0..index]) |value| |
| 4201 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); | 4295 | id += @boolToInt(value.tag() == .unreachable_value); |
| 4202 | break :field_name field_name_buf; | 4296 | break :field_name .{ .field = id }; |
| 4203 | }, | 4297 | }, |
| 4204 | else => unreachable, | 4298 | else => unreachable, |
| 4205 | }; | 4299 | }; |
| 4206 | | 4300 | |
| 4207 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { | 4301 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4208 | try writer.writeByte('&'); | 4302 | try writer.writeByte('&'); |
| 4209 | if (extra_name orelse field_name) |name| | 4303 | if (extra_name != .none) { |
| 4210 | try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name }) | 4304 | try f.writeCValueDerefMember(writer, struct_ptr, extra_name); |
| | 4305 | if (field_name != .none) { |
| | 4306 | try writer.writeByte('.'); |
| | 4307 | try f.writeCValue(writer, field_name, .Other); |
| | 4308 | } |
| | 4309 | } else if (field_name != .none) |
| | 4310 | try f.writeCValueDerefMember(writer, struct_ptr, field_name) |
| 4211 | else | 4311 | else |
| 4212 | try f.writeCValueDeref(writer, struct_ptr); | 4312 | try f.writeCValueDeref(writer, struct_ptr); |
| 4213 | if (extra_name) |_| if (field_name) |name| | | |
| 4214 | try writer.print(".{ }", .{fmtIdent(name)}); | | |
| 4215 | } else try f.writeCValue(writer, struct_ptr, .Other); | 4313 | } else try f.writeCValue(writer, struct_ptr, .Other); |
| 4216 | try writer.writeAll(";\n"); | 4314 | try writer.writeAll(";\n"); |
| 4217 | return local; | 4315 | return local; |
| ... | @@ -4221,9 +4319,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4221,9 +4319,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4221 | if (f.liveness.isUnused(inst)) | 4319 | if (f.liveness.isUnused(inst)) |
| 4222 | return CValue.none; | 4320 | return CValue.none; |
| 4223 | | 4321 | |
| | 4322 | const inst_ty = f.air.typeOfIndex(inst); |
| | 4323 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| | 4324 | |
| 4224 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4325 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4225 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; | 4326 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; |
| 4226 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 4227 | const target = f.object.dg.module.getTarget(); | 4327 | const target = f.object.dg.module.getTarget(); |
| 4228 | const struct_byval = try f.resolveInst(extra.struct_operand); | 4328 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 4229 | const struct_ty = f.air.typeOf(extra.struct_operand); | 4329 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| ... | @@ -4232,11 +4332,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4232,11 +4332,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4232 | // Ensure complete type definition is visible before accessing fields. | 4332 | // Ensure complete type definition is visible before accessing fields. |
| 4233 | try f.renderType(std.io.null_writer, struct_ty); | 4333 | try f.renderType(std.io.null_writer, struct_ty); |
| 4234 | | 4334 | |
| 4235 | var field_name_buf: []const u8 = ""; | 4335 | const extra_name: CValue = switch (struct_ty.tag()) { |
| 4236 | defer f.object.dg.gpa.free(field_name_buf); | 4336 | .union_tagged, .union_safety_tagged => .{ .identifier = "payload" }, |
| 4237 | const field_name = switch (struct_ty.tag()) { | 4337 | else => .none, |
| | 4338 | }; |
| | 4339 | |
| | 4340 | const field_name: CValue = switch (struct_ty.tag()) { |
| 4238 | .@"struct" => switch (struct_ty.containerLayout()) { | 4341 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4239 | .Auto, .Extern => struct_ty.structFieldName(extra.field_index), | 4342 | .Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) }, |
| 4240 | .Packed => { | 4343 | .Packed => { |
| 4241 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 4344 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 4242 | const int_info = struct_ty.intInfo(target); | 4345 | const int_info = struct_ty.intInfo(target); |
| ... | @@ -4294,19 +4397,20 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4294,19 +4397,20 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4294 | return local; | 4397 | return local; |
| 4295 | }, | 4398 | }, |
| 4296 | }, | 4399 | }, |
| 4297 | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], | 4400 | .@"union", .union_safety_tagged, .union_tagged => .{ |
| 4298 | .tuple, .anon_struct => |tag| blk: { | 4401 | .identifier = struct_ty.unionFields().keys()[extra.field_index], |
| | 4402 | }, |
| | 4403 | .tuple, .anon_struct => blk: { |
| 4299 | const tuple = struct_ty.tupleFields(); | 4404 | const tuple = struct_ty.tupleFields(); |
| 4300 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; | 4405 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; |
| 4301 | | 4406 | |
| 4302 | if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index); | 4407 | var id: usize = 0; |
| 4303 | | 4408 | for (tuple.values[0..extra.field_index]) |value| |
| 4304 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); | 4409 | id += @boolToInt(value.tag() == .unreachable_value); |
| 4305 | break :blk field_name_buf; | 4410 | break :blk .{ .field = id }; |
| 4306 | }, | 4411 | }, |
| 4307 | else => unreachable, | 4412 | else => unreachable, |
| 4308 | }; | 4413 | }; |
| 4309 | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; | | |
| 4310 | | 4414 | |
| 4311 | const is_array = lowersToArray(inst_ty, target); | 4415 | const is_array = lowersToArray(inst_ty, target); |
| 4312 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); | 4416 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| ... | @@ -4315,15 +4419,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4315,15 +4419,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4315 | try writer.writeAll("memcpy("); | 4419 | try writer.writeAll("memcpy("); |
| 4316 | try f.writeCValue(writer, local, .FunctionArgument); | 4420 | try f.writeCValue(writer, local, .FunctionArgument); |
| 4317 | try writer.writeAll(", "); | 4421 | try writer.writeAll(", "); |
| 4318 | try f.writeCValue(writer, struct_byval, .Other); | 4422 | } else try writer.writeAll(" = "); |
| 4319 | try writer.print(".{s}{ }, sizeof(", .{ payload, fmtIdent(field_name) }); | 4423 | if (extra_name != .none) { |
| | 4424 | try f.writeCValueMember(writer, struct_byval, extra_name); |
| | 4425 | try writer.writeByte('.'); |
| | 4426 | try f.writeCValue(writer, field_name, .Other); |
| | 4427 | } else try f.writeCValueMember(writer, struct_byval, field_name); |
| | 4428 | if (is_array) { |
| | 4429 | try writer.writeAll(", sizeof("); |
| 4320 | try f.renderTypecast(writer, inst_ty); | 4430 | try f.renderTypecast(writer, inst_ty); |
| 4321 | try writer.writeAll("));\n"); | 4431 | try writer.writeAll("))"); |
| 4322 | } else { | | |
| 4323 | try writer.writeAll(" = "); | | |
| 4324 | try f.writeCValue(writer, struct_byval, .Other); | | |
| 4325 | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); | | |
| 4326 | } | 4432 | } |
| | 4433 | try writer.writeAll(";\n"); |
| 4327 | return local; | 4434 | return local; |
| 4328 | } | 4435 | } |
| 4329 | | 4436 | |
| ... | @@ -4383,25 +4490,33 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu | ... | @@ -4383,25 +4490,33 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 4383 | } | 4490 | } |
| 4384 | | 4491 | |
| 4385 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { | 4492 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4386 | if (f.liveness.isUnused(inst)) | 4493 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4387 | return CValue.none; | | |
| 4388 | | 4494 | |
| | 4495 | const inst_ty = f.air.typeOfIndex(inst); |
| 4389 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 4496 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4390 | const writer = f.object.writer(); | 4497 | const payload = try f.resolveInst(ty_op.operand); |
| 4391 | const operand = try f.resolveInst(ty_op.operand); | 4498 | if (inst_ty.optionalReprIsPayload()) return payload; |
| 4392 | | 4499 | |
| 4393 | const inst_ty = f.air.typeOfIndex(inst); | 4500 | const payload_ty = f.air.typeOf(ty_op.operand); |
| 4394 | if (inst_ty.optionalReprIsPayload()) { | 4501 | const target = f.object.dg.module.getTarget(); |
| 4395 | return operand; | 4502 | const is_array = lowersToArray(payload_ty, target); |
| 4396 | } | | |
| 4397 | | 4503 | |
| 4398 | // .wrap_optional is used to convert non-optionals into optionals so it can never be null. | 4504 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4399 | const local = try f.allocLocal(inst_ty, .Const); | 4505 | const writer = f.object.writer(); |
| 4400 | try writer.writeAll(" = { .payload = "); | 4506 | try writer.writeAll(" = { .payload = "); |
| 4401 | try f.writeCValue(writer, operand, .Initializer); | 4507 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); |
| 4402 | try writer.writeAll(", .is_null = "); | 4508 | try writer.writeAll(", .is_null = "); |
| 4403 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); | 4509 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); |
| 4404 | try writer.writeAll(" };\n"); | 4510 | try writer.writeAll(" };\n"); |
| | 4511 | if (is_array) { |
| | 4512 | try writer.writeAll("memcpy("); |
| | 4513 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| | 4514 | try writer.writeAll(", "); |
| | 4515 | try f.writeCValue(writer, payload, .FunctionArgument); |
| | 4516 | try writer.writeAll(", sizeof("); |
| | 4517 | try f.renderTypecast(writer, payload_ty); |
| | 4518 | try writer.writeAll("));\n"); |
| | 4519 | } |
| 4405 | return local; | 4520 | return local; |
| 4406 | } | 4521 | } |
| 4407 | | 4522 | |
| ... | @@ -4473,35 +4588,33 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4473,35 +4588,33 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4473 | } | 4588 | } |
| 4474 | | 4589 | |
| 4475 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | 4590 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4476 | if (f.liveness.isUnused(inst)) | 4591 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4477 | return CValue.none; | | |
| 4478 | | | |
| 4479 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | | |
| 4480 | const writer = f.object.writer(); | | |
| 4481 | const operand = try f.resolveInst(ty_op.operand); | | |
| 4482 | | 4592 | |
| 4483 | const inst_ty = f.air.typeOfIndex(inst); | 4593 | const inst_ty = f.air.typeOfIndex(inst); |
| 4484 | const payload_ty = inst_ty.errorUnionPayload(); | | |
| 4485 | const error_ty = inst_ty.errorUnionSet(); | 4594 | const error_ty = inst_ty.errorUnionSet(); |
| | 4595 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| | 4596 | const payload_ty = inst_ty.errorUnionPayload(); |
| | 4597 | const payload = try f.resolveInst(ty_op.operand); |
| | 4598 | |
| 4486 | const target = f.object.dg.module.getTarget(); | 4599 | const target = f.object.dg.module.getTarget(); |
| 4487 | const is_array = lowersToArray(payload_ty, target); | 4600 | const is_array = lowersToArray(payload_ty, target); |
| | 4601 | |
| 4488 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); | 4602 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| | 4603 | const writer = f.object.writer(); |
| 4489 | try writer.writeAll(" = { .payload = "); | 4604 | try writer.writeAll(" = { .payload = "); |
| 4490 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer); | 4605 | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); |
| 4491 | try writer.writeAll(", .error = "); | 4606 | try writer.writeAll(", .error = "); |
| 4492 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); | 4607 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); |
| 4493 | try writer.writeAll(" };\n"); | 4608 | try writer.writeAll(" };\n"); |
| 4494 | | | |
| 4495 | if (is_array) { | 4609 | if (is_array) { |
| 4496 | try writer.writeAll("memcpy("); | 4610 | try writer.writeAll("memcpy("); |
| 4497 | try f.writeCValue(writer, local, .Other); | 4611 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 4498 | try writer.writeAll(".payload, "); | 4612 | try writer.writeAll(", "); |
| 4499 | try f.writeCValue(writer, operand, .FunctionArgument); | 4613 | try f.writeCValue(writer, payload, .FunctionArgument); |
| 4500 | try writer.writeAll(", sizeof("); | 4614 | try writer.writeAll(", sizeof("); |
| 4501 | try f.renderTypecast(writer, payload_ty); | 4615 | try f.renderTypecast(writer, payload_ty); |
| 4502 | try writer.writeAll("));\n"); | 4616 | try writer.writeAll("));\n"); |
| 4503 | } | 4617 | } |
| 4504 | | | |
| 4505 | return local; | 4618 | return local; |
| 4506 | } | 4619 | } |
| 4507 | | 4620 | |
| ... | @@ -4845,10 +4958,41 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa | ... | @@ -4845,10 +4958,41 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 4845 | fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { | 4958 | fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4846 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4959 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4847 | const extra = f.air.extraData(Air.Bin, pl_op.payload).data; | 4960 | const extra = f.air.extraData(Air.Bin, pl_op.payload).data; |
| | 4961 | const dest_ty = f.air.typeOf(pl_op.operand); |
| 4848 | const dest_ptr = try f.resolveInst(pl_op.operand); | 4962 | const dest_ptr = try f.resolveInst(pl_op.operand); |
| 4849 | const value = try f.resolveInst(extra.lhs); | 4963 | const value = try f.resolveInst(extra.lhs); |
| 4850 | const len = try f.resolveInst(extra.rhs); | 4964 | const len = try f.resolveInst(extra.rhs); |
| | 4965 | |
| 4851 | const writer = f.object.writer(); | 4966 | const writer = f.object.writer(); |
| | 4967 | if (dest_ty.isVolatilePtr()) { |
| | 4968 | var u8_ptr_pl = dest_ty.ptrInfo(); |
| | 4969 | u8_ptr_pl.data.pointee_type = Type.u8; |
| | 4970 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); |
| | 4971 | |
| | 4972 | try writer.writeAll("for ("); |
| | 4973 | const index = try f.allocLocal(Type.usize, .Mut); |
| | 4974 | try writer.writeAll(" = "); |
| | 4975 | try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer); |
| | 4976 | try writer.writeAll("; "); |
| | 4977 | try f.writeCValue(writer, index, .Other); |
| | 4978 | try writer.writeAll(" != "); |
| | 4979 | try f.writeCValue(writer, len, .Other); |
| | 4980 | try writer.writeAll("; "); |
| | 4981 | try f.writeCValue(writer, index, .Other); |
| | 4982 | try writer.writeAll(" += "); |
| | 4983 | try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other); |
| | 4984 | try writer.writeAll(") (("); |
| | 4985 | try f.renderTypecast(writer, u8_ptr_ty); |
| | 4986 | try writer.writeByte(')'); |
| | 4987 | try f.writeCValue(writer, dest_ptr, .FunctionArgument); |
| | 4988 | try writer.writeAll(")["); |
| | 4989 | try f.writeCValue(writer, index, .Other); |
| | 4990 | try writer.writeAll("] = "); |
| | 4991 | try f.writeCValue(writer, value, .FunctionArgument); |
| | 4992 | try writer.writeAll(";\n"); |
| | 4993 | |
| | 4994 | return CValue.none; |
| | 4995 | } |
| 4852 | | 4996 | |
| 4853 | try writer.writeAll("memset("); | 4997 | try writer.writeAll("memset("); |
| 4854 | try f.writeCValue(writer, dest_ptr, .FunctionArgument); | 4998 | try f.writeCValue(writer, dest_ptr, .FunctionArgument); |
| ... | @@ -5068,27 +5212,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5068,27 +5212,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5068 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); | 5212 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 5069 | try writer.writeAll("};\n"); | 5213 | try writer.writeAll("};\n"); |
| 5070 | | 5214 | |
| | 5215 | var field_id: usize = 0; |
| 5071 | for (elements) |element, index| { | 5216 | for (elements) |element, index| { |
| 5072 | if (inst_ty.structFieldValueComptime(index)) |_| continue; | 5217 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 5073 | | 5218 | |
| 5074 | const element_ty = f.air.typeOf(element); | 5219 | const element_ty = f.air.typeOf(element); |
| 5075 | if (element_ty.zigTypeTag() != .Array) continue; | 5220 | if (element_ty.zigTypeTag() != .Array) continue; |
| 5076 | | 5221 | |
| 5077 | var field_name_buf: []u8 = &.{}; | 5222 | const field_name = if (inst_ty.isTupleOrAnonStruct()) |
| 5078 | defer f.object.dg.gpa.free(field_name_buf); | 5223 | CValue{ .field = field_id } |
| 5079 | const field_name = if (inst_ty.isTuple()) field_name: { | 5224 | else |
| 5080 | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); | 5225 | CValue{ .identifier = inst_ty.structFieldName(index) }; |
| 5081 | break :field_name field_name_buf; | | |
| 5082 | } else inst_ty.structFieldName(index); | | |
| 5083 | | 5226 | |
| 5084 | try writer.writeAll(";\n"); | 5227 | try writer.writeAll(";\n"); |
| 5085 | try writer.writeAll("memcpy("); | 5228 | try writer.writeAll("memcpy("); |
| 5086 | try f.writeCValue(writer, local, .Other); | 5229 | try f.writeCValueMember(writer, local, field_name); |
| 5087 | try writer.print(".{ }, ", .{fmtIdent(field_name)}); | 5230 | try writer.writeAll(", "); |
| 5088 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); | 5231 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); |
| 5089 | try writer.writeAll(", sizeof("); | 5232 | try writer.writeAll(", sizeof("); |
| 5090 | try f.renderTypecast(writer, element_ty); | 5233 | try f.renderTypecast(writer, element_ty); |
| 5091 | try writer.writeAll("));\n"); | 5234 | try writer.writeAll("));\n"); |
| | 5235 | |
| | 5236 | field_id += 1; |
| 5092 | } | 5237 | } |
| 5093 | }, | 5238 | }, |
| 5094 | .Packed => { | 5239 | .Packed => { |
| ... | @@ -5634,10 +5779,9 @@ fn isByRef(ty: Type) bool { | ... | @@ -5634,10 +5779,9 @@ fn isByRef(ty: Type) bool { |
| 5634 | } | 5779 | } |
| 5635 | | 5780 | |
| 5636 | const LowerFnRetTyBuffer = struct { | 5781 | const LowerFnRetTyBuffer = struct { |
| 5637 | const names = [1][]const u8{"array"}; | | |
| 5638 | types: [1]Type, | 5782 | types: [1]Type, |
| 5639 | values: [1]Value, | 5783 | values: [1]Value, |
| 5640 | payload: Type.Payload.AnonStruct, | 5784 | payload: Type.Payload.Tuple, |
| 5641 | }; | 5785 | }; |
| 5642 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { | 5786 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { |
| 5643 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); | 5787 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); |
| ... | @@ -5646,7 +5790,6 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) T | ... | @@ -5646,7 +5790,6 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) T |
| 5646 | buffer.types = [1]Type{ret_ty}; | 5790 | buffer.types = [1]Type{ret_ty}; |
| 5647 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; | 5791 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; |
| 5648 | buffer.payload = .{ .data = .{ | 5792 | buffer.payload = .{ .data = .{ |
| 5649 | .names = &LowerFnRetTyBuffer.names, | | |
| 5650 | .types = &buffer.types, | 5793 | .types = &buffer.types, |
| 5651 | .values = &buffer.values, | 5794 | .values = &buffer.values, |
| 5652 | } }; | 5795 | } }; |