| ... | ... | @@ -32,6 +32,8 @@ pub const CValue = union(enum) { |
| 32 | 32 | constant: Air.Inst.Ref, |
| 33 | 33 | /// Index into the parameters |
| 34 | 34 | arg: usize, |
| 35 | /// Index into a tuple's fields |
| 36 | field: usize, |
| 35 | 37 | /// By-value |
| 36 | 38 | decl: Decl.Index, |
| 37 | 39 | decl_ref: Decl.Index, |
| ... | ... | @@ -79,7 +81,6 @@ const BuiltinInfo = enum { |
| 79 | 81 | Bits, |
| 80 | 82 | }; |
| 81 | 83 | |
| 82 | | /// TODO make this not cut off at 128 bytes |
| 83 | 84 | fn formatTypeAsCIdentifier( |
| 84 | 85 | data: FormatTypeAsCIdentContext, |
| 85 | 86 | comptime fmt: []const u8, |
| ... | ... | @@ -1297,7 +1298,8 @@ pub const DeclGen = struct { |
| 1297 | 1298 | var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1298 | 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 | 1303 | try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer()); |
| 1302 | 1304 | |
| 1303 | 1305 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| ... | ... | @@ -1309,7 +1311,11 @@ pub const DeclGen = struct { |
| 1309 | 1311 | else => unreachable, |
| 1310 | 1312 | }; |
| 1311 | 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 | 1319 | const name_end = buffer.items.len - " ".len; |
| 1314 | 1320 | try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len); |
| 1315 | 1321 | buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]); |
| ... | ... | @@ -1378,26 +1384,17 @@ pub const DeclGen = struct { |
| 1378 | 1384 | try buffer.appendSlice("typedef struct {\n"); |
| 1379 | 1385 | { |
| 1380 | 1386 | const fields = t.tupleFields(); |
| 1381 | | var empty = true; |
| 1387 | var field_id: usize = 0; |
| 1382 | 1388 | for (fields.types) |field_ty, i| { |
| 1383 | | if (!field_ty.hasRuntimeBits()) 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); |
| 1389 | if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue; |
| 1393 | 1390 | |
| 1394 | 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 | 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 | 1399 | const name_begin = buffer.items.len + "} ".len; |
| 1403 | 1400 | try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); |
| ... | ... | @@ -1751,12 +1748,38 @@ pub const DeclGen = struct { |
| 1751 | 1748 | }, |
| 1752 | 1749 | .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) |
| 1753 | 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 | 1781 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1756 | | .Struct => if (t.isTupleOrAnonStruct()) |
| 1757 | | try dg.renderTupleTypedef(t) |
| 1758 | | else |
| 1759 | | try dg.renderStructTypedef(t), |
| 1782 | .Struct => try dg.renderStructTypedef(t), |
| 1760 | 1783 | .Union => try dg.renderUnionTypedef(t), |
| 1761 | 1784 | else => unreachable, |
| 1762 | 1785 | }; |
| ... | ... | @@ -1976,6 +1999,7 @@ pub const DeclGen = struct { |
| 1976 | 1999 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 1977 | 2000 | .constant => unreachable, |
| 1978 | 2001 | .arg => |i| return w.print("a{d}", .{i}), |
| 2002 | .field => |i| return w.print("f{d}", .{i}), |
| 1979 | 2003 | .decl => |decl| return dg.renderDeclName(w, decl), |
| 1980 | 2004 | .decl_ref => |decl| { |
| 1981 | 2005 | try w.writeByte('&'); |
| ... | ... | @@ -1994,6 +2018,7 @@ pub const DeclGen = struct { |
| 1994 | 2018 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 1995 | 2019 | .constant => unreachable, |
| 1996 | 2020 | .arg => |i| return w.print("(*a{d})", .{i}), |
| 2021 | .field => |i| return w.print("f{d}", .{i}), |
| 1997 | 2022 | .decl => |decl| { |
| 1998 | 2023 | try w.writeAll("(*"); |
| 1999 | 2024 | try dg.renderDeclName(w, decl); |
| ... | ... | @@ -2018,7 +2043,7 @@ pub const DeclGen = struct { |
| 2018 | 2043 | |
| 2019 | 2044 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2020 | 2045 | switch (c_value) { |
| 2021 | | .none, .constant, .undef => unreachable, |
| 2046 | .none, .constant, .field, .undef => unreachable, |
| 2022 | 2047 | .local, .arg, .decl, .identifier, .bytes => { |
| 2023 | 2048 | try dg.writeCValue(writer, c_value); |
| 2024 | 2049 | try writer.writeAll("->"); |
| ... | ... | @@ -2236,12 +2261,6 @@ pub fn genDecl(o: *Object) !void { |
| 2236 | 2261 | const variable: *Module.Var = var_payload.data; |
| 2237 | 2262 | const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; |
| 2238 | 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 | 2265 | const decl_c_value: CValue = if (is_global) .{ |
| 2247 | 2266 | .bytes = mem.span(o.dg.decl.name), |
| ... | ... | @@ -2249,6 +2268,8 @@ pub fn genDecl(o: *Object) !void { |
| 2249 | 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 | 2273 | try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2253 | 2274 | try fwd_decl_writer.writeAll(";\n"); |
| 2254 | 2275 | |
| ... | ... | @@ -2257,6 +2278,7 @@ pub fn genDecl(o: *Object) !void { |
| 2257 | 2278 | } |
| 2258 | 2279 | |
| 2259 | 2280 | const w = o.writer(); |
| 2281 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2260 | 2282 | try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); |
| 2261 | 2283 | try w.writeAll(" = "); |
| 2262 | 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 | 2617 | } |
| 2596 | 2618 | |
| 2597 | 2619 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2620 | const inst_ty = f.air.typeOfIndex(inst); |
| 2598 | 2621 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2599 | 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 | 2626 | const ptr = try f.resolveInst(bin_op.lhs); |
| 2603 | 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 | 2633 | const writer = f.object.writer(); |
| 2605 | | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 2606 | | try writer.writeAll(" = "); |
| 2634 | if (is_array) { |
| 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 | 2640 | try f.writeCValue(writer, ptr, .Other); |
| 2608 | 2641 | try writer.writeByte('['); |
| 2609 | 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 | 2650 | return local; |
| 2612 | 2651 | } |
| 2613 | 2652 | |
| ... | ... | @@ -2637,19 +2676,36 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2637 | 2676 | } |
| 2638 | 2677 | |
| 2639 | 2678 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2679 | const inst_ty = f.air.typeOfIndex(inst); |
| 2640 | 2680 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2641 | 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 | 2685 | const slice = try f.resolveInst(bin_op.lhs); |
| 2645 | 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 | 2692 | const writer = f.object.writer(); |
| 2647 | | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 2648 | | try writer.writeAll(" = "); |
| 2693 | if (is_array) { |
| 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 | 2699 | try f.writeCValue(writer, slice, .Other); |
| 2650 | 2700 | try writer.writeAll(".ptr["); |
| 2651 | 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 | 2709 | return local; |
| 2654 | 2710 | } |
| 2655 | 2711 | |
| ... | ... | @@ -2672,18 +2728,34 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2672 | 2728 | } |
| 2673 | 2729 | |
| 2674 | 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 | 2734 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2678 | 2735 | const array = try f.resolveInst(bin_op.lhs); |
| 2679 | 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 | 2742 | const writer = f.object.writer(); |
| 2681 | | const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); |
| 2682 | | try writer.writeAll(" = "); |
| 2743 | if (is_array) { |
| 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 | 2749 | try f.writeCValue(writer, array, .Other); |
| 2684 | 2750 | try writer.writeByte('['); |
| 2685 | 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 | 2759 | return local; |
| 2688 | 2760 | } |
| 2689 | 2761 | |
| ... | ... | @@ -2817,7 +2889,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 2817 | 2889 | const array_local = try f.allocLocal(lowered_ret_ty, .Mut); |
| 2818 | 2890 | try writer.writeAll(";\n"); |
| 2819 | 2891 | try writer.writeAll("memcpy("); |
| 2820 | | try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); |
| 2892 | try f.writeCValueMember(writer, array_local, .{ .field = 0 }); |
| 2821 | 2893 | try writer.writeAll(", "); |
| 2822 | 2894 | if (deref) |
| 2823 | 2895 | try f.writeCValueDeref(writer, operand) |
| ... | ... | @@ -3063,13 +3135,13 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3063 | 3135 | const local = try f.allocLocal(inst_ty, .Mut); |
| 3064 | 3136 | try w.writeAll(";\n"); |
| 3065 | 3137 | |
| 3066 | | try f.writeCValue(w, local, .Other); |
| 3067 | | try w.writeAll(".field_1 = zig_"); |
| 3138 | try f.writeCValueMember(w, local, .{ .field = 1 }); |
| 3139 | try w.writeAll(" = zig_"); |
| 3068 | 3140 | try w.writeAll(operation); |
| 3069 | 3141 | try w.writeAll("o_"); |
| 3070 | 3142 | try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); |
| 3071 | 3143 | try w.writeAll("(&"); |
| 3072 | | try f.writeCValueMember(w, local, .{ .identifier = "field_0" }); |
| 3144 | try f.writeCValueMember(w, local, .{ .field = 0 }); |
| 3073 | 3145 | try w.writeAll(", "); |
| 3074 | 3146 | try f.writeCValue(w, lhs, .FunctionArgument); |
| 3075 | 3147 | try w.writeAll(", "); |
| ... | ... | @@ -3191,7 +3263,7 @@ fn airEquality( |
| 3191 | 3263 | |
| 3192 | 3264 | try writer.writeAll(" = "); |
| 3193 | 3265 | |
| 3194 | | if (operand_ty.tag() == .optional) { |
| 3266 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 3195 | 3267 | // (A && B) || (C && (A == B)) |
| 3196 | 3268 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| 3197 | 3269 | |
| ... | ... | @@ -3429,7 +3501,7 @@ fn airCall( |
| 3429 | 3501 | try writer.writeAll("memcpy("); |
| 3430 | 3502 | try f.writeCValue(writer, array_local, .FunctionArgument); |
| 3431 | 3503 | try writer.writeAll(", "); |
| 3432 | | try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); |
| 3504 | try f.writeCValueMember(writer, result_local, .{ .field = 0 }); |
| 3433 | 3505 | try writer.writeAll(", sizeof("); |
| 3434 | 3506 | try f.renderTypecast(writer, ret_ty); |
| 3435 | 3507 | try writer.writeAll("));\n"); |
| ... | ... | @@ -3590,25 +3662,39 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3590 | 3662 | // If result is .none then the value of the block is unused. |
| 3591 | 3663 | if (result != .none) { |
| 3592 | 3664 | const operand = try f.resolveInst(branch.operand); |
| 3593 | | try f.writeCValue(writer, result, .Other); |
| 3594 | | try writer.writeAll(" = "); |
| 3595 | | try f.writeCValue(writer, operand, .Other); |
| 3665 | |
| 3666 | const operand_ty = f.air.typeOf(branch.operand); |
| 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 | 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 | 3685 | return CValue.none; |
| 3601 | 3686 | } |
| 3602 | 3687 | |
| 3603 | 3688 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3604 | | if (f.liveness.isUnused(inst)) |
| 3605 | | return CValue.none; |
| 3689 | const inst_ty = f.air.typeOfIndex(inst); |
| 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 | 3694 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3608 | 3695 | const operand = try f.resolveInst(ty_op.operand); |
| 3609 | 3696 | |
| 3610 | 3697 | const writer = f.object.writer(); |
| 3611 | | const inst_ty = f.air.typeOfIndex(inst); |
| 3612 | 3698 | if (inst_ty.isPtrAtRuntime() and |
| 3613 | 3699 | f.air.typeOf(ty_op.operand).isPtrAtRuntime()) |
| 3614 | 3700 | { |
| ... | ... | @@ -3982,9 +4068,9 @@ fn airIsNull( |
| 3982 | 4068 | |
| 3983 | 4069 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) |
| 3984 | 4070 | TypedValue{ .ty = Type.bool, .val = Value.@"true" } |
| 3985 | | else if (operand_ty.isPtrLikeOptional()) |
| 4071 | else if (optional_ty.isPtrLikeOptional()) |
| 3986 | 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 | 4074 | else if (payload_ty.zigTypeTag() == .ErrorSet) |
| 3989 | 4075 | TypedValue{ .ty = payload_ty, .val = Value.zero } |
| 3990 | 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 | 4093 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4008 | 4094 | |
| 4009 | 4095 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4010 | | const writer = f.object.writer(); |
| 4011 | 4096 | const operand = try f.resolveInst(ty_op.operand); |
| 4012 | 4097 | const opt_ty = f.air.typeOf(ty_op.operand); |
| 4013 | 4098 | |
| 4014 | 4099 | var buf: Type.Payload.ElemType = undefined; |
| 4015 | 4100 | const payload_ty = opt_ty.optionalChild(&buf); |
| 4016 | 4101 | |
| 4017 | | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4018 | | return CValue.none; |
| 4019 | | } |
| 4020 | | |
| 4021 | | if (opt_ty.optionalReprIsPayload()) { |
| 4022 | | return operand; |
| 4023 | | } |
| 4102 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 4103 | if (opt_ty.optionalReprIsPayload()) return operand; |
| 4024 | 4104 | |
| 4025 | 4105 | const inst_ty = f.air.typeOfIndex(inst); |
| 4026 | | const local = try f.allocLocal(inst_ty, .Const); |
| 4027 | | try writer.writeAll(" = ("); |
| 4028 | | try f.writeCValue(writer, operand, .Other); |
| 4029 | | try writer.writeAll(").payload;\n"); |
| 4106 | const target = f.object.dg.module.getTarget(); |
| 4107 | const is_array = lowersToArray(inst_ty, target); |
| 4108 | |
| 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 | 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 | 4253 | try f.renderTypecast(writer, field_ptr_ty); |
| 4160 | 4254 | try writer.writeByte(')'); |
| 4161 | 4255 | |
| 4162 | | const extra_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 4163 | | .union_tagged, .union_safety_tagged => "payload", |
| 4164 | | else => null, |
| 4256 | const extra_name: CValue = switch (struct_ty.tag()) { |
| 4257 | .union_tagged, .union_safety_tagged => .{ .identifier = "payload" }, |
| 4258 | else => .none, |
| 4165 | 4259 | }; |
| 4166 | 4260 | |
| 4167 | | var field_name_buf: []const u8 = &.{}; |
| 4168 | | defer f.object.dg.gpa.free(field_name_buf); |
| 4169 | | const field_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 4261 | const field_name: CValue = switch (struct_ty.tag()) { |
| 4170 | 4262 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4171 | | .Auto, .Extern => struct_ty.structFieldName(index), |
| 4263 | .Auto, .Extern => CValue{ .identifier = struct_ty.structFieldName(index) }, |
| 4172 | 4264 | .Packed => if (field_ptr_info.data.host_size == 0) { |
| 4173 | 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 | 4281 | try f.writeCValue(writer, struct_ptr, .Other); |
| 4190 | 4282 | try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| 4191 | 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], |
| 4195 | | .tuple, .anon_struct => |tag| field_name: { |
| 4289 | .tuple, .anon_struct => field_name: { |
| 4196 | 4290 | const tuple = struct_ty.tupleFields(); |
| 4197 | 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); |
| 4200 | | |
| 4201 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 4202 | | break :field_name field_name_buf; |
| 4293 | var id: usize = 0; |
| 4294 | for (tuple.values[0..index]) |value| |
| 4295 | id += @boolToInt(value.tag() == .unreachable_value); |
| 4296 | break :field_name .{ .field = id }; |
| 4203 | 4297 | }, |
| 4204 | 4298 | else => unreachable, |
| 4205 | 4299 | }; |
| 4206 | 4300 | |
| 4207 | 4301 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4208 | 4302 | try writer.writeByte('&'); |
| 4209 | | if (extra_name orelse field_name) |name| |
| 4210 | | try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name }) |
| 4303 | if (extra_name != .none) { |
| 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 | 4311 | else |
| 4212 | 4312 | try f.writeCValueDeref(writer, struct_ptr); |
| 4213 | | if (extra_name) |_| if (field_name) |name| |
| 4214 | | try writer.print(".{ }", .{fmtIdent(name)}); |
| 4215 | 4313 | } else try f.writeCValue(writer, struct_ptr, .Other); |
| 4216 | 4314 | try writer.writeAll(";\n"); |
| 4217 | 4315 | return local; |
| ... | ... | @@ -4221,9 +4319,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4221 | 4319 | if (f.liveness.isUnused(inst)) |
| 4222 | 4320 | return CValue.none; |
| 4223 | 4321 | |
| 4322 | const inst_ty = f.air.typeOfIndex(inst); |
| 4323 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none; |
| 4324 | |
| 4224 | 4325 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4225 | 4326 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; |
| 4226 | | const inst_ty = f.air.typeOfIndex(inst); |
| 4227 | 4327 | const target = f.object.dg.module.getTarget(); |
| 4228 | 4328 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 4229 | 4329 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| ... | ... | @@ -4232,11 +4332,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4232 | 4332 | // Ensure complete type definition is visible before accessing fields. |
| 4233 | 4333 | try f.renderType(std.io.null_writer, struct_ty); |
| 4234 | 4334 | |
| 4235 | | var field_name_buf: []const u8 = ""; |
| 4236 | | defer f.object.dg.gpa.free(field_name_buf); |
| 4237 | | const field_name = switch (struct_ty.tag()) { |
| 4335 | const extra_name: CValue = switch (struct_ty.tag()) { |
| 4336 | .union_tagged, .union_safety_tagged => .{ .identifier = "payload" }, |
| 4337 | else => .none, |
| 4338 | }; |
| 4339 | |
| 4340 | const field_name: CValue = switch (struct_ty.tag()) { |
| 4238 | 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 | 4343 | .Packed => { |
| 4241 | 4344 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 4242 | 4345 | const int_info = struct_ty.intInfo(target); |
| ... | ... | @@ -4294,19 +4397,20 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4294 | 4397 | return local; |
| 4295 | 4398 | }, |
| 4296 | 4399 | }, |
| 4297 | | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], |
| 4298 | | .tuple, .anon_struct => |tag| blk: { |
| 4400 | .@"union", .union_safety_tagged, .union_tagged => .{ |
| 4401 | .identifier = struct_ty.unionFields().keys()[extra.field_index], |
| 4402 | }, |
| 4403 | .tuple, .anon_struct => blk: { |
| 4299 | 4404 | const tuple = struct_ty.tupleFields(); |
| 4300 | 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); |
| 4303 | | |
| 4304 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); |
| 4305 | | break :blk field_name_buf; |
| 4407 | var id: usize = 0; |
| 4408 | for (tuple.values[0..extra.field_index]) |value| |
| 4409 | id += @boolToInt(value.tag() == .unreachable_value); |
| 4410 | break :blk .{ .field = id }; |
| 4306 | 4411 | }, |
| 4307 | 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 | 4415 | const is_array = lowersToArray(inst_ty, target); |
| 4312 | 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 | 4419 | try writer.writeAll("memcpy("); |
| 4316 | 4420 | try f.writeCValue(writer, local, .FunctionArgument); |
| 4317 | 4421 | try writer.writeAll(", "); |
| 4318 | | try f.writeCValue(writer, struct_byval, .Other); |
| 4319 | | try writer.print(".{s}{ }, sizeof(", .{ payload, fmtIdent(field_name) }); |
| 4422 | } else try writer.writeAll(" = "); |
| 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 | 4430 | try f.renderTypecast(writer, inst_ty); |
| 4321 | | try writer.writeAll("));\n"); |
| 4322 | | } else { |
| 4323 | | try writer.writeAll(" = "); |
| 4324 | | try f.writeCValue(writer, struct_byval, .Other); |
| 4325 | | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 4431 | try writer.writeAll("))"); |
| 4326 | 4432 | } |
| 4433 | try writer.writeAll(";\n"); |
| 4327 | 4434 | return local; |
| 4328 | 4435 | } |
| 4329 | 4436 | |
| ... | ... | @@ -4383,25 +4490,33 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 4383 | 4490 | } |
| 4384 | 4491 | |
| 4385 | 4492 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4386 | | if (f.liveness.isUnused(inst)) |
| 4387 | | return CValue.none; |
| 4493 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4388 | 4494 | |
| 4495 | const inst_ty = f.air.typeOfIndex(inst); |
| 4389 | 4496 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4390 | | const writer = f.object.writer(); |
| 4391 | | const operand = try f.resolveInst(ty_op.operand); |
| 4497 | const payload = try f.resolveInst(ty_op.operand); |
| 4498 | if (inst_ty.optionalReprIsPayload()) return payload; |
| 4392 | 4499 | |
| 4393 | | const inst_ty = f.air.typeOfIndex(inst); |
| 4394 | | if (inst_ty.optionalReprIsPayload()) { |
| 4395 | | return operand; |
| 4396 | | } |
| 4500 | const payload_ty = f.air.typeOf(ty_op.operand); |
| 4501 | const target = f.object.dg.module.getTarget(); |
| 4502 | const is_array = lowersToArray(payload_ty, target); |
| 4397 | 4503 | |
| 4398 | | // .wrap_optional is used to convert non-optionals into optionals so it can never be null. |
| 4399 | | const local = try f.allocLocal(inst_ty, .Const); |
| 4504 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4505 | const writer = f.object.writer(); |
| 4400 | 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 | 4508 | try writer.writeAll(", .is_null = "); |
| 4403 | 4509 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); |
| 4404 | 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 | 4520 | return local; |
| 4406 | 4521 | } |
| 4407 | 4522 | |
| ... | ... | @@ -4473,35 +4588,33 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4473 | 4588 | } |
| 4474 | 4589 | |
| 4475 | 4590 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4476 | | if (f.liveness.isUnused(inst)) |
| 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); |
| 4591 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4482 | 4592 | |
| 4483 | 4593 | const inst_ty = f.air.typeOfIndex(inst); |
| 4484 | | const payload_ty = inst_ty.errorUnionPayload(); |
| 4485 | 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 | 4599 | const target = f.object.dg.module.getTarget(); |
| 4487 | 4600 | const is_array = lowersToArray(payload_ty, target); |
| 4601 | |
| 4488 | 4602 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| 4603 | const writer = f.object.writer(); |
| 4489 | 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 | 4606 | try writer.writeAll(", .error = "); |
| 4492 | 4607 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); |
| 4493 | 4608 | try writer.writeAll(" };\n"); |
| 4494 | | |
| 4495 | 4609 | if (is_array) { |
| 4496 | 4610 | try writer.writeAll("memcpy("); |
| 4497 | | try f.writeCValue(writer, local, .Other); |
| 4498 | | try writer.writeAll(".payload, "); |
| 4499 | | try f.writeCValue(writer, operand, .FunctionArgument); |
| 4611 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 4612 | try writer.writeAll(", "); |
| 4613 | try f.writeCValue(writer, payload, .FunctionArgument); |
| 4500 | 4614 | try writer.writeAll(", sizeof("); |
| 4501 | 4615 | try f.renderTypecast(writer, payload_ty); |
| 4502 | 4616 | try writer.writeAll("));\n"); |
| 4503 | 4617 | } |
| 4504 | | |
| 4505 | 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 | 4958 | fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4846 | 4959 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4847 | 4960 | const extra = f.air.extraData(Air.Bin, pl_op.payload).data; |
| 4961 | const dest_ty = f.air.typeOf(pl_op.operand); |
| 4848 | 4962 | const dest_ptr = try f.resolveInst(pl_op.operand); |
| 4849 | 4963 | const value = try f.resolveInst(extra.lhs); |
| 4850 | 4964 | const len = try f.resolveInst(extra.rhs); |
| 4965 | |
| 4851 | 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 | 4997 | try writer.writeAll("memset("); |
| 4854 | 4998 | try f.writeCValue(writer, dest_ptr, .FunctionArgument); |
| ... | ... | @@ -5068,27 +5212,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5068 | 5212 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 5069 | 5213 | try writer.writeAll("};\n"); |
| 5070 | 5214 | |
| 5215 | var field_id: usize = 0; |
| 5071 | 5216 | for (elements) |element, index| { |
| 5072 | 5217 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 5073 | 5218 | |
| 5074 | 5219 | const element_ty = f.air.typeOf(element); |
| 5075 | 5220 | if (element_ty.zigTypeTag() != .Array) continue; |
| 5076 | 5221 | |
| 5077 | | var field_name_buf: []u8 = &.{}; |
| 5078 | | defer f.object.dg.gpa.free(field_name_buf); |
| 5079 | | const field_name = if (inst_ty.isTuple()) field_name: { |
| 5080 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 5081 | | break :field_name field_name_buf; |
| 5082 | | } else inst_ty.structFieldName(index); |
| 5222 | const field_name = if (inst_ty.isTupleOrAnonStruct()) |
| 5223 | CValue{ .field = field_id } |
| 5224 | else |
| 5225 | CValue{ .identifier = inst_ty.structFieldName(index) }; |
| 5083 | 5226 | |
| 5084 | 5227 | try writer.writeAll(";\n"); |
| 5085 | 5228 | try writer.writeAll("memcpy("); |
| 5086 | | try f.writeCValue(writer, local, .Other); |
| 5087 | | try writer.print(".{ }, ", .{fmtIdent(field_name)}); |
| 5229 | try f.writeCValueMember(writer, local, field_name); |
| 5230 | try writer.writeAll(", "); |
| 5088 | 5231 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); |
| 5089 | 5232 | try writer.writeAll(", sizeof("); |
| 5090 | 5233 | try f.renderTypecast(writer, element_ty); |
| 5091 | 5234 | try writer.writeAll("));\n"); |
| 5235 | |
| 5236 | field_id += 1; |
| 5092 | 5237 | } |
| 5093 | 5238 | }, |
| 5094 | 5239 | .Packed => { |
| ... | ... | @@ -5634,10 +5779,9 @@ fn isByRef(ty: Type) bool { |
| 5634 | 5779 | } |
| 5635 | 5780 | |
| 5636 | 5781 | const LowerFnRetTyBuffer = struct { |
| 5637 | | const names = [1][]const u8{"array"}; |
| 5638 | 5782 | types: [1]Type, |
| 5639 | 5783 | values: [1]Value, |
| 5640 | | payload: Type.Payload.AnonStruct, |
| 5784 | payload: Type.Payload.Tuple, |
| 5641 | 5785 | }; |
| 5642 | 5786 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { |
| 5643 | 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 | 5790 | buffer.types = [1]Type{ret_ty}; |
| 5647 | 5791 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; |
| 5648 | 5792 | buffer.payload = .{ .data = .{ |
| 5649 | | .names = &LowerFnRetTyBuffer.names, |
| 5650 | 5793 | .types = &buffer.types, |
| 5651 | 5794 | .values = &buffer.values, |
| 5652 | 5795 | } }; |