authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-05 01:29:15-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-25 05:11:28-04:00
log6f3654ad694946876e3aac971fd284230424c915
treed1a935b258e4cabf9ef47396faa1b381340169f8
parentc8d0e71de6c0e59b8f103526204b990fafe41f54

c: implement @errorName


3 files changed, 145 insertions(+), 92 deletions(-)

src/codegen/c.zig+64-5
...@@ -1580,6 +1580,66 @@ pub const DeclGen = struct {...@@ -1580,6 +1580,66 @@ pub const DeclGen = struct {
1580 }1580 }
1581};1581};
15821582
1583pub fn genErrDecls(o: *Object) !void {
1584 if (o.dg.module.global_error_set.size == 0) return;
1585 const writer = o.writer();
1586
1587 try writer.writeAll("enum {\n");
1588 o.indent_writer.pushIndent();
1589 var max_name_len: usize = 0;
1590 for (o.dg.module.error_name_list.items) |name, value| {
1591 max_name_len = std.math.max(name.len, max_name_len);
1592 var err_val_payload = Value.Payload.Error{ .data = .{ .name = name } };
1593 try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_val_payload.base), .Other);
1594 try writer.print(" = {d}u,\n", .{value});
1595 }
1596 o.indent_writer.popIndent();
1597 try writer.writeAll("};\n");
1598
1599 const name_prefix = "zig_errorName_";
1600 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len + 1);
1601 defer o.dg.gpa.free(name_buf);
1602
1603 std.mem.copy(u8, name_buf, name_prefix);
1604 for (o.dg.module.error_name_list.items) |name| {
1605 std.mem.copy(u8, name_buf[name_prefix.len..], name);
1606 name_buf[name_prefix.len + name.len] = 0;
1607
1608 const identifier = name_buf[0 .. name_prefix.len + name.len :0];
1609 const nameZ = identifier[name_prefix.len..];
1610
1611 var name_ty_payload = Type.Payload.Len{
1612 .base = .{ .tag = .array_u8_sentinel_0 },
1613 .data = name.len,
1614 };
1615 const name_ty = Type.initPayload(&name_ty_payload.base);
1616
1617 var name_val_payload = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = nameZ };
1618 const name_val = Value.initPayload(&name_val_payload.base);
1619
1620 try writer.writeAll("static ");
1621 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0);
1622 try writer.writeAll(" = ");
1623 try o.dg.renderValue(writer, name_ty, name_val, .Other);
1624 try writer.writeAll(";\n");
1625 }
1626
1627 var name_array_ty_payload = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{
1628 .len = o.dg.module.error_name_list.items.len,
1629 .elem_type = Type.initTag(.const_slice_u8_sentinel_0),
1630 } };
1631 const name_array_ty = Type.initPayload(&name_array_ty_payload.base);
1632
1633 try writer.writeAll("static ");
1634 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = "zig_errorName" }, .Const, 0);
1635 try writer.writeAll(" = {");
1636 for (o.dg.module.error_name_list.items) |name, value| {
1637 if (value != 0) try writer.writeByte(',');
1638 try writer.print("{{zig_errorName_{}, {d}u}}", .{ fmtIdent(name), name.len });
1639 }
1640 try writer.writeAll("};\n");
1641}
1642
1583pub fn genFunc(f: *Function) !void {1643pub fn genFunc(f: *Function) !void {
1584 const tracy = trace(@src());1644 const tracy = trace(@src());
1585 defer tracy.end();1645 defer tracy.end();
...@@ -3982,11 +4042,10 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3982,11 +4042,10 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
3982 const operand = try f.resolveInst(un_op);4042 const operand = try f.resolveInst(un_op);
3983 const local = try f.allocLocal(inst_ty, .Const);4043 const local = try f.allocLocal(inst_ty, .Const);
39844044
3985 try writer.writeAll(" = ");4045 try writer.writeAll(" = zig_errorName[");
39864046 try f.writeCValue(writer, operand);
3987 _ = operand;4047 try writer.writeAll("];\n");
3988 _ = local;4048 return local;
3989 return f.fail("TODO: C backend: implement airErrorName", .{});
3990}4049}
39914050
3992fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {4051fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
src/link/C.zig+81-85
...@@ -260,30 +260,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -260,30 +260,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
260 var f: Flush = .{};260 var f: Flush = .{};
261 defer f.deinit(gpa);261 defer f.deinit(gpa);
262262
263 // Covers zig.h and err_typedef_item.263 // Covers zig.h and typedef.
264 try f.all_buffers.ensureUnusedCapacity(gpa, 2);264 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
265265
266 if (zig_h.len != 0) {266 f.appendBufAssumeCapacity(zig_h);
267 f.all_buffers.appendAssumeCapacity(.{
268 .iov_base = zig_h,
269 .iov_len = zig_h.len,
270 });
271 f.file_size += zig_h.len;
272 }
273267
274 const err_typedef_writer = f.err_typedef_buf.writer(gpa);268 const typedef_index = f.all_buffers.items.len;
275 const err_typedef_index = f.all_buffers.items.len;
276 f.all_buffers.items.len += 1;269 f.all_buffers.items.len += 1;
277270
278 if (module.global_error_set.size > 0) {271 try self.flushErrDecls(&f);
279 try err_typedef_writer.writeAll("enum {\n");
280 var it = module.global_error_set.iterator();
281 while (it.next()) |entry| try err_typedef_writer.print(" zig_error_{s} = {d},\n", .{
282 codegen.fmtIdent(entry.key_ptr.*),
283 entry.value_ptr.*,
284 });
285 try err_typedef_writer.writeAll("};\n");
286 }
287272
288 // Typedefs, forward decls, and non-functions first.273 // Typedefs, forward decls, and non-functions first.
289 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore274 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore
...@@ -301,38 +286,20 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -301,38 +286,20 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
301286
302 while (f.remaining_decls.popOrNull()) |kv| {287 while (f.remaining_decls.popOrNull()) |kv| {
303 const decl_index = kv.key;288 const decl_index = kv.key;
304 try flushDecl(self, &f, decl_index);289 try self.flushDecl(&f, decl_index);
305 }290 }
306291
307 if (f.err_typedef_buf.items.len == 0) {292 f.all_buffers.items[typedef_index] = .{
308 f.all_buffers.items[err_typedef_index] = .{293 .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "",
309 .iov_base = "",294 .iov_len = f.typedef_buf.items.len,
310 .iov_len = 0,295 };
311 };296 f.file_size += f.typedef_buf.items.len;
312 } else {
313 f.all_buffers.items[err_typedef_index] = .{
314 .iov_base = f.err_typedef_buf.items.ptr,
315 .iov_len = f.err_typedef_buf.items.len,
316 };
317 f.file_size += f.err_typedef_buf.items.len;
318 }
319297
320 // Now the function bodies.298 // Now the function bodies.
321 try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count);299 try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count);
322 for (decl_keys) |decl_index, i| {300 for (decl_keys) |decl_index, i|
323 const decl = module.declPtr(decl_index);301 if (module.declPtr(decl_index).getFunction() != null)
324 if (decl.getFunction() != null) {302 f.appendBufAssumeCapacity(decl_values[i].code.items);
325 const decl_block = &decl_values[i];
326 const buf = decl_block.code.items;
327 if (buf.len != 0) {
328 f.all_buffers.appendAssumeCapacity(.{
329 .iov_base = buf.ptr,
330 .iov_len = buf.len,
331 });
332 f.file_size += buf.len;
333 }
334 }
335 }
336303
337 const file = self.base.file.?;304 const file = self.base.file.?;
338 try file.setEndPos(f.file_size);305 try file.setEndPos(f.file_size);
...@@ -342,7 +309,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -342,7 +309,8 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
342const Flush = struct {309const Flush = struct {
343 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},310 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
344 typedefs: Typedefs = .{},311 typedefs: Typedefs = .{},
345 err_typedef_buf: std.ArrayListUnmanaged(u8) = .{},312 typedef_buf: std.ArrayListUnmanaged(u8) = .{},
313 err_buf: std.ArrayListUnmanaged(u8) = .{},
346 /// We collect a list of buffers to write, and write them all at once with pwritev 😎314 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
347 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},315 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
348 /// Keeps track of the total bytes of `all_buffers`.316 /// Keeps track of the total bytes of `all_buffers`.
...@@ -356,9 +324,16 @@ const Flush = struct {...@@ -356,9 +324,16 @@ const Flush = struct {
356 std.hash_map.default_max_load_percentage,324 std.hash_map.default_max_load_percentage,
357 );325 );
358326
327 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
328 if (buf.len == 0) return;
329 f.all_buffers.appendAssumeCapacity(.{ .iov_base = buf.ptr, .iov_len = buf.len });
330 f.file_size += buf.len;
331 }
332
359 fn deinit(f: *Flush, gpa: Allocator) void {333 fn deinit(f: *Flush, gpa: Allocator) void {
360 f.all_buffers.deinit(gpa);334 f.all_buffers.deinit(gpa);
361 f.err_typedef_buf.deinit(gpa);335 f.err_buf.deinit(gpa);
336 f.typedef_buf.deinit(gpa);
362 f.typedefs.deinit(gpa);337 f.typedefs.deinit(gpa);
363 f.remaining_decls.deinit(gpa);338 f.remaining_decls.deinit(gpa);
364 }339 }
...@@ -368,6 +343,57 @@ const FlushDeclError = error{...@@ -368,6 +343,57 @@ const FlushDeclError = error{
368 OutOfMemory,343 OutOfMemory,
369};344};
370345
346fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void {
347 if (typedefs.count() == 0) return;
348 const gpa = self.base.allocator;
349 const module = self.base.options.module.?;
350
351 try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{
352 .mod = module,
353 });
354 var it = typedefs.iterator();
355 while (it.next()) |new| {
356 const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{
357 .mod = module,
358 });
359 if (!gop.found_existing) {
360 try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered);
361 }
362 }
363}
364
365fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
366 const gpa = self.base.allocator;
367 const module = self.base.options.module.?;
368
369 var object = codegen.Object{
370 .dg = .{
371 .gpa = gpa,
372 .module = module,
373 .error_msg = null,
374 .decl_index = undefined,
375 .decl = undefined,
376 .fwd_decl = undefined,
377 .typedefs = codegen.TypedefMap.initContext(gpa, .{ .mod = module }),
378 .typedefs_arena = gpa,
379 },
380 .code = f.err_buf.toManaged(gpa),
381 .indent_writer = undefined, // set later so we can get a pointer to object.code
382 };
383 object.indent_writer = .{ .underlying_writer = object.code.writer() };
384 defer object.dg.typedefs.deinit();
385 defer f.err_buf = object.code.moveToUnmanaged();
386
387 codegen.genErrDecls(&object) catch |err| switch (err) {
388 error.AnalysisFail => unreachable,
389 else => |e| return e,
390 };
391
392 try self.flushTypedefs(f, object.dg.typedefs.unmanaged);
393 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
394 f.appendBufAssumeCapacity(object.code.items);
395}
396
371/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.397/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
372fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void {398fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void {
373 const module = self.base.options.module.?;399 const module = self.base.options.module.?;
...@@ -384,43 +410,13 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!...@@ -384,43 +410,13 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!
384 const decl_block = self.decl_table.getPtr(decl_index).?;410 const decl_block = self.decl_table.getPtr(decl_index).?;
385 const gpa = self.base.allocator;411 const gpa = self.base.allocator;
386412
387 if (decl_block.typedefs.count() != 0) {413 try self.flushTypedefs(f, decl_block.typedefs);
388 try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, decl_block.typedefs.count()), .{414 try f.all_buffers.ensureUnusedCapacity(gpa, 2);
389 .mod = module,415 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);
390 });416 if (decl.getFunction()) |_|
391 var it = decl_block.typedefs.iterator();417 f.fn_count += 1
392 while (it.next()) |new| {418 else
393 const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{419 f.appendBufAssumeCapacity(decl_block.code.items);
394 .mod = module,
395 });
396 if (!gop.found_existing) {
397 try f.err_typedef_buf.appendSlice(gpa, new.value_ptr.rendered);
398 }
399 }
400 }
401
402 if (decl_block.fwd_decl.items.len != 0) {
403 const buf = decl_block.fwd_decl.items;
404 if (buf.len != 0) {
405 try f.all_buffers.append(gpa, .{
406 .iov_base = buf.ptr,
407 .iov_len = buf.len,
408 });
409 f.file_size += buf.len;
410 }
411 }
412 if (decl.getFunction() != null) {
413 f.fn_count += 1;
414 } else if (decl_block.code.items.len != 0) {
415 const buf = decl_block.code.items;
416 if (buf.len != 0) {
417 try f.all_buffers.append(gpa, .{
418 .iov_base = buf.ptr,
419 .iov_len = buf.len,
420 });
421 f.file_size += buf.len;
422 }
423 }
424}420}
425421
426pub fn flushEmitH(module: *Module) !void {422pub fn flushEmitH(module: *Module) !void {
test/behavior/error.zig-2
...@@ -556,7 +556,6 @@ test "error union comptime caching" {...@@ -556,7 +556,6 @@ test "error union comptime caching" {
556}556}
557557
558test "@errorName" {558test "@errorName" {
559 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
560 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;559 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
561 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
562 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;561 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
...@@ -570,7 +569,6 @@ fn gimmeItBroke() anyerror {...@@ -570,7 +569,6 @@ fn gimmeItBroke() anyerror {
570}569}
571570
572test "@errorName sentinel length matches slice length" {571test "@errorName sentinel length matches slice length" {
573 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
574 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;572 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
575 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;574 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;