| ... | ... | @@ -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, |
| ... | ... | @@ -1382,26 +1384,17 @@ pub const DeclGen = struct { |
| 1382 | 1384 | try buffer.appendSlice("typedef struct {\n"); |
| 1383 | 1385 | { |
| 1384 | 1386 | const fields = t.tupleFields(); |
| 1385 | | var empty = true; |
| 1387 | var field_id: usize = 0; |
| 1386 | 1388 | for (fields.types) |field_ty, i| { |
| 1387 | | if (!field_ty.hasRuntimeBits()) continue; |
| 1388 | | const val = fields.values[i]; |
| 1389 | | if (val.tag() != .unreachable_value) continue; |
| 1390 | | |
| 1391 | | var field_name_buf: []const u8 = &.{}; |
| 1392 | | defer dg.typedefs.allocator.free(field_name_buf); |
| 1393 | | const field_name = if (t.isTuple()) field_name: { |
| 1394 | | field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); |
| 1395 | | break :field_name field_name_buf; |
| 1396 | | } else t.structFieldName(i); |
| 1389 | if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue; |
| 1397 | 1390 | |
| 1398 | 1391 | try buffer.append(' '); |
| 1399 | | 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); |
| 1400 | 1393 | try buffer.appendSlice(";\n"); |
| 1401 | 1394 | |
| 1402 | | empty = false; |
| 1395 | field_id += 1; |
| 1403 | 1396 | } |
| 1404 | | if (empty) try buffer.appendSlice(" char empty_tuple;\n"); |
| 1397 | if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n"); |
| 1405 | 1398 | } |
| 1406 | 1399 | const name_begin = buffer.items.len + "} ".len; |
| 1407 | 1400 | try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); |
| ... | ... | @@ -1755,12 +1748,38 @@ pub const DeclGen = struct { |
| 1755 | 1748 | }, |
| 1756 | 1749 | .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) |
| 1757 | 1750 | try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) |
| 1758 | | 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) { |
| 1759 | 1781 | const name = dg.getTypedefName(t) orelse switch (tag) { |
| 1760 | | .Struct => if (t.isTupleOrAnonStruct()) |
| 1761 | | try dg.renderTupleTypedef(t) |
| 1762 | | else |
| 1763 | | try dg.renderStructTypedef(t), |
| 1782 | .Struct => try dg.renderStructTypedef(t), |
| 1764 | 1783 | .Union => try dg.renderUnionTypedef(t), |
| 1765 | 1784 | else => unreachable, |
| 1766 | 1785 | }; |
| ... | ... | @@ -1980,6 +1999,7 @@ pub const DeclGen = struct { |
| 1980 | 1999 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 1981 | 2000 | .constant => unreachable, |
| 1982 | 2001 | .arg => |i| return w.print("a{d}", .{i}), |
| 2002 | .field => |i| return w.print("f{d}", .{i}), |
| 1983 | 2003 | .decl => |decl| return dg.renderDeclName(w, decl), |
| 1984 | 2004 | .decl_ref => |decl| { |
| 1985 | 2005 | try w.writeByte('&'); |
| ... | ... | @@ -1998,6 +2018,7 @@ pub const DeclGen = struct { |
| 1998 | 2018 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 1999 | 2019 | .constant => unreachable, |
| 2000 | 2020 | .arg => |i| return w.print("(*a{d})", .{i}), |
| 2021 | .field => |i| return w.print("f{d}", .{i}), |
| 2001 | 2022 | .decl => |decl| { |
| 2002 | 2023 | try w.writeAll("(*"); |
| 2003 | 2024 | try dg.renderDeclName(w, decl); |
| ... | ... | @@ -2022,7 +2043,7 @@ pub const DeclGen = struct { |
| 2022 | 2043 | |
| 2023 | 2044 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2024 | 2045 | switch (c_value) { |
| 2025 | | .none, .constant, .undef => unreachable, |
| 2046 | .none, .constant, .field, .undef => unreachable, |
| 2026 | 2047 | .local, .arg, .decl, .identifier, .bytes => { |
| 2027 | 2048 | try dg.writeCValue(writer, c_value); |
| 2028 | 2049 | try writer.writeAll("->"); |
| ... | ... | @@ -2868,7 +2889,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 2868 | 2889 | const array_local = try f.allocLocal(lowered_ret_ty, .Mut); |
| 2869 | 2890 | try writer.writeAll(";\n"); |
| 2870 | 2891 | try writer.writeAll("memcpy("); |
| 2871 | | try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); |
| 2892 | try f.writeCValueMember(writer, array_local, .{ .field = 0 }); |
| 2872 | 2893 | try writer.writeAll(", "); |
| 2873 | 2894 | if (deref) |
| 2874 | 2895 | try f.writeCValueDeref(writer, operand) |
| ... | ... | @@ -3114,13 +3135,13 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3114 | 3135 | const local = try f.allocLocal(inst_ty, .Mut); |
| 3115 | 3136 | try w.writeAll(";\n"); |
| 3116 | 3137 | |
| 3117 | | try f.writeCValue(w, local, .Other); |
| 3118 | | try w.writeAll(".field_1 = zig_"); |
| 3138 | try f.writeCValueMember(w, local, .{ .field = 1 }); |
| 3139 | try w.writeAll(" = zig_"); |
| 3119 | 3140 | try w.writeAll(operation); |
| 3120 | 3141 | try w.writeAll("o_"); |
| 3121 | 3142 | try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); |
| 3122 | 3143 | try w.writeAll("(&"); |
| 3123 | | try f.writeCValueMember(w, local, .{ .identifier = "field_0" }); |
| 3144 | try f.writeCValueMember(w, local, .{ .field = 0 }); |
| 3124 | 3145 | try w.writeAll(", "); |
| 3125 | 3146 | try f.writeCValue(w, lhs, .FunctionArgument); |
| 3126 | 3147 | try w.writeAll(", "); |
| ... | ... | @@ -3480,7 +3501,7 @@ fn airCall( |
| 3480 | 3501 | try writer.writeAll("memcpy("); |
| 3481 | 3502 | try f.writeCValue(writer, array_local, .FunctionArgument); |
| 3482 | 3503 | try writer.writeAll(", "); |
| 3483 | | try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); |
| 3504 | try f.writeCValueMember(writer, result_local, .{ .field = 0 }); |
| 3484 | 3505 | try writer.writeAll(", sizeof("); |
| 3485 | 3506 | try f.renderTypecast(writer, ret_ty); |
| 3486 | 3507 | try writer.writeAll("));\n"); |
| ... | ... | @@ -4232,16 +4253,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 4232 | 4253 | try f.renderTypecast(writer, field_ptr_ty); |
| 4233 | 4254 | try writer.writeByte(')'); |
| 4234 | 4255 | |
| 4235 | | const extra_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 4236 | | .union_tagged, .union_safety_tagged => "payload", |
| 4237 | | else => null, |
| 4256 | const extra_name: CValue = switch (struct_ty.tag()) { |
| 4257 | .union_tagged, .union_safety_tagged => .{ .identifier = "payload" }, |
| 4258 | else => .none, |
| 4238 | 4259 | }; |
| 4239 | 4260 | |
| 4240 | | var field_name_buf: []const u8 = &.{}; |
| 4241 | | defer f.object.dg.gpa.free(field_name_buf); |
| 4242 | | const field_name: ?[]const u8 = switch (struct_ty.tag()) { |
| 4261 | const field_name: CValue = switch (struct_ty.tag()) { |
| 4243 | 4262 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4244 | | .Auto, .Extern => struct_ty.structFieldName(index), |
| 4263 | .Auto, .Extern => CValue{ .identifier = struct_ty.structFieldName(index) }, |
| 4245 | 4264 | .Packed => if (field_ptr_info.data.host_size == 0) { |
| 4246 | 4265 | const target = f.object.dg.module.getTarget(); |
| 4247 | 4266 | |
| ... | ... | @@ -4262,29 +4281,35 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 4262 | 4281 | try f.writeCValue(writer, struct_ptr, .Other); |
| 4263 | 4282 | try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); |
| 4264 | 4283 | return local; |
| 4265 | | } else null, |
| 4284 | } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug |
| 4266 | 4285 | }, |
| 4267 | | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index], |
| 4268 | | .tuple, .anon_struct => |tag| field_name: { |
| 4286 | .@"union", .union_safety_tagged, .union_tagged => .{ |
| 4287 | .identifier = struct_ty.unionFields().keys()[index], |
| 4288 | }, |
| 4289 | .tuple, .anon_struct => field_name: { |
| 4269 | 4290 | const tuple = struct_ty.tupleFields(); |
| 4270 | 4291 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; |
| 4271 | 4292 | |
| 4272 | | if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index); |
| 4273 | | |
| 4274 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 4275 | | 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 }; |
| 4276 | 4297 | }, |
| 4277 | 4298 | else => unreachable, |
| 4278 | 4299 | }; |
| 4279 | 4300 | |
| 4280 | 4301 | if (field_ty.hasRuntimeBitsIgnoreComptime()) { |
| 4281 | 4302 | try writer.writeByte('&'); |
| 4282 | | if (extra_name orelse field_name) |name| |
| 4283 | | 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) |
| 4284 | 4311 | else |
| 4285 | 4312 | try f.writeCValueDeref(writer, struct_ptr); |
| 4286 | | if (extra_name) |_| if (field_name) |name| |
| 4287 | | try writer.print(".{ }", .{fmtIdent(name)}); |
| 4288 | 4313 | } else try f.writeCValue(writer, struct_ptr, .Other); |
| 4289 | 4314 | try writer.writeAll(";\n"); |
| 4290 | 4315 | return local; |
| ... | ... | @@ -4307,11 +4332,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4307 | 4332 | // Ensure complete type definition is visible before accessing fields. |
| 4308 | 4333 | try f.renderType(std.io.null_writer, struct_ty); |
| 4309 | 4334 | |
| 4310 | | var field_name_buf: []const u8 = ""; |
| 4311 | | defer f.object.dg.gpa.free(field_name_buf); |
| 4312 | | 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()) { |
| 4313 | 4341 | .@"struct" => switch (struct_ty.containerLayout()) { |
| 4314 | | .Auto, .Extern => struct_ty.structFieldName(extra.field_index), |
| 4342 | .Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) }, |
| 4315 | 4343 | .Packed => { |
| 4316 | 4344 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 4317 | 4345 | const int_info = struct_ty.intInfo(target); |
| ... | ... | @@ -4369,19 +4397,20 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4369 | 4397 | return local; |
| 4370 | 4398 | }, |
| 4371 | 4399 | }, |
| 4372 | | .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], |
| 4373 | | .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: { |
| 4374 | 4404 | const tuple = struct_ty.tupleFields(); |
| 4375 | 4405 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; |
| 4376 | 4406 | |
| 4377 | | if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index); |
| 4378 | | |
| 4379 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); |
| 4380 | | 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 }; |
| 4381 | 4411 | }, |
| 4382 | 4412 | else => unreachable, |
| 4383 | 4413 | }; |
| 4384 | | const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; |
| 4385 | 4414 | |
| 4386 | 4415 | const is_array = lowersToArray(inst_ty, target); |
| 4387 | 4416 | const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); |
| ... | ... | @@ -4390,15 +4419,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4390 | 4419 | try writer.writeAll("memcpy("); |
| 4391 | 4420 | try f.writeCValue(writer, local, .FunctionArgument); |
| 4392 | 4421 | try writer.writeAll(", "); |
| 4393 | | try f.writeCValue(writer, struct_byval, .Other); |
| 4394 | | 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("); |
| 4395 | 4430 | try f.renderTypecast(writer, inst_ty); |
| 4396 | | try writer.writeAll("));\n"); |
| 4397 | | } else { |
| 4398 | | try writer.writeAll(" = "); |
| 4399 | | try f.writeCValue(writer, struct_byval, .Other); |
| 4400 | | try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); |
| 4431 | try writer.writeAll("))"); |
| 4401 | 4432 | } |
| 4433 | try writer.writeAll(";\n"); |
| 4402 | 4434 | return local; |
| 4403 | 4435 | } |
| 4404 | 4436 | |
| ... | ... | @@ -5180,27 +5212,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5180 | 5212 | if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); |
| 5181 | 5213 | try writer.writeAll("};\n"); |
| 5182 | 5214 | |
| 5215 | var field_id: usize = 0; |
| 5183 | 5216 | for (elements) |element, index| { |
| 5184 | 5217 | if (inst_ty.structFieldValueComptime(index)) |_| continue; |
| 5185 | 5218 | |
| 5186 | 5219 | const element_ty = f.air.typeOf(element); |
| 5187 | 5220 | if (element_ty.zigTypeTag() != .Array) continue; |
| 5188 | 5221 | |
| 5189 | | var field_name_buf: []u8 = &.{}; |
| 5190 | | defer f.object.dg.gpa.free(field_name_buf); |
| 5191 | | const field_name = if (inst_ty.isTuple()) field_name: { |
| 5192 | | field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); |
| 5193 | | break :field_name field_name_buf; |
| 5194 | | } 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) }; |
| 5195 | 5226 | |
| 5196 | 5227 | try writer.writeAll(";\n"); |
| 5197 | 5228 | try writer.writeAll("memcpy("); |
| 5198 | | try f.writeCValue(writer, local, .Other); |
| 5199 | | try writer.print(".{ }, ", .{fmtIdent(field_name)}); |
| 5229 | try f.writeCValueMember(writer, local, field_name); |
| 5230 | try writer.writeAll(", "); |
| 5200 | 5231 | try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); |
| 5201 | 5232 | try writer.writeAll(", sizeof("); |
| 5202 | 5233 | try f.renderTypecast(writer, element_ty); |
| 5203 | 5234 | try writer.writeAll("));\n"); |
| 5235 | |
| 5236 | field_id += 1; |
| 5204 | 5237 | } |
| 5205 | 5238 | }, |
| 5206 | 5239 | .Packed => { |
| ... | ... | @@ -5746,10 +5779,9 @@ fn isByRef(ty: Type) bool { |
| 5746 | 5779 | } |
| 5747 | 5780 | |
| 5748 | 5781 | const LowerFnRetTyBuffer = struct { |
| 5749 | | const names = [1][]const u8{"array"}; |
| 5750 | 5782 | types: [1]Type, |
| 5751 | 5783 | values: [1]Value, |
| 5752 | | payload: Type.Payload.AnonStruct, |
| 5784 | payload: Type.Payload.Tuple, |
| 5753 | 5785 | }; |
| 5754 | 5786 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { |
| 5755 | 5787 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); |
| ... | ... | @@ -5758,7 +5790,6 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) T |
| 5758 | 5790 | buffer.types = [1]Type{ret_ty}; |
| 5759 | 5791 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; |
| 5760 | 5792 | buffer.payload = .{ .data = .{ |
| 5761 | | .names = &LowerFnRetTyBuffer.names, |
| 5762 | 5793 | .types = &buffer.types, |
| 5763 | 5794 | .values = &buffer.values, |
| 5764 | 5795 | } }; |