| ... | @@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix; | ... | @@ -23,7 +23,6 @@ const libcFloatSuffix = target_util.libcFloatSuffix; |
| 23 | const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev; | 23 | const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev; |
| 24 | const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; | 24 | const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; |
| 25 | | 25 | |
| 26 | const Mutability = enum { @"const", mut }; | | |
| 27 | const BigIntLimb = std.math.big.Limb; | 26 | const BigIntLimb = std.math.big.Limb; |
| 28 | const BigInt = std.math.big.int; | 27 | const BigInt = std.math.big.int; |
| 29 | | 28 | |
| ... | @@ -55,6 +54,8 @@ pub const CValue = union(enum) { | ... | @@ -55,6 +54,8 @@ pub const CValue = union(enum) { |
| 55 | /// Render these bytes literally. | 54 | /// Render these bytes literally. |
| 56 | /// TODO make this a [*:0]const u8 to save memory | 55 | /// TODO make this a [*:0]const u8 to save memory |
| 57 | bytes: []const u8, | 56 | bytes: []const u8, |
| | 57 | /// A deferred call_always_tail |
| | 58 | call_always_tail: void, |
| 58 | }; | 59 | }; |
| 59 | | 60 | |
| 60 | const BlockData = struct { | 61 | const BlockData = struct { |
| ... | @@ -62,21 +63,22 @@ const BlockData = struct { | ... | @@ -62,21 +63,22 @@ const BlockData = struct { |
| 62 | result: CValue, | 63 | result: CValue, |
| 63 | }; | 64 | }; |
| 64 | | 65 | |
| 65 | const TypedefKind = enum { | | |
| 66 | Forward, | | |
| 67 | Complete, | | |
| 68 | }; | | |
| 69 | | | |
| 70 | pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); | 66 | pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); |
| 71 | | 67 | |
| 72 | pub const LazyFnKey = union(enum) { | 68 | pub const LazyFnKey = union(enum) { |
| 73 | tag_name: Decl.Index, | 69 | tag_name: Decl.Index, |
| | 70 | never_tail: Decl.Index, |
| | 71 | never_inline: Decl.Index, |
| 74 | }; | 72 | }; |
| 75 | pub const LazyFnValue = struct { | 73 | pub const LazyFnValue = struct { |
| 76 | fn_name: []const u8, | 74 | fn_name: []const u8, |
| 77 | data: union { | 75 | data: Data, |
| | 76 | |
| | 77 | pub const Data = union { |
| 78 | tag_name: Type, | 78 | tag_name: Type, |
| 79 | }, | 79 | never_tail: void, |
| | 80 | never_inline: void, |
| | 81 | }; |
| 80 | }; | 82 | }; |
| 81 | pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue); | 83 | pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue); |
| 82 | | 84 | |
| ... | @@ -314,7 +316,7 @@ pub const Function = struct { | ... | @@ -314,7 +316,7 @@ pub const Function = struct { |
| 314 | const gpa = f.object.dg.gpa; | 316 | const gpa = f.object.dg.gpa; |
| 315 | try f.allocs.put(gpa, decl_c_value.new_local, true); | 317 | try f.allocs.put(gpa, decl_c_value.new_local, true); |
| 316 | try writer.writeAll("static "); | 318 | try writer.writeAll("static "); |
| 317 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .@"const", alignment, .Complete); | 319 | try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete); |
| 318 | try writer.writeAll(" = "); | 320 | try writer.writeAll(" = "); |
| 319 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); | 321 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); |
| 320 | try writer.writeAll(";\n "); | 322 | try writer.writeAll(";\n "); |
| ... | @@ -348,15 +350,13 @@ pub const Function = struct { | ... | @@ -348,15 +350,13 @@ pub const Function = struct { |
| 348 | } | 350 | } |
| 349 | | 351 | |
| 350 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { | 352 | fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue { |
| 351 | const result = try f.allocAlignedLocal(ty, .mut, 0); | 353 | const result = try f.allocAlignedLocal(ty, .{}, 0); |
| 352 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); | 354 | log.debug("%{d}: allocating t{d}", .{ inst, result.new_local }); |
| 353 | return result; | 355 | return result; |
| 354 | } | 356 | } |
| 355 | | 357 | |
| 356 | /// Only allocates the local; does not print anything. | 358 | /// Only allocates the local; does not print anything. |
| 357 | fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue { | 359 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue { |
| 358 | _ = mutability; | | |
| 359 | | | |
| 360 | if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| { | 360 | if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| { |
| 361 | for (locals_list.items, 0..) |local_index, i| { | 361 | for (locals_list.items, 0..) |local_index, i| { |
| 362 | const local = &f.locals.items[local_index]; | 362 | const local = &f.locals.items[local_index]; |
| ... | @@ -451,11 +451,9 @@ pub const Function = struct { | ... | @@ -451,11 +451,9 @@ pub const Function = struct { |
| 451 | return f.object.dg.fmtIntLiteral(ty, val); | 451 | return f.object.dg.fmtIntLiteral(ty, val); |
| 452 | } | 452 | } |
| 453 | | 453 | |
| 454 | fn getTagNameFn(f: *Function, enum_ty: Type) ![]const u8 { | 454 | fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 { |
| 455 | const gpa = f.object.dg.gpa; | 455 | const gpa = f.object.dg.gpa; |
| 456 | const owner_decl = enum_ty.getOwnerDecl(); | 456 | const gop = try f.lazy_fns.getOrPut(gpa, key); |
| 457 | | | |
| 458 | const gop = try f.lazy_fns.getOrPut(gpa, .{ .tag_name = owner_decl }); | | |
| 459 | if (!gop.found_existing) { | 457 | if (!gop.found_existing) { |
| 460 | errdefer _ = f.lazy_fns.pop(); | 458 | errdefer _ = f.lazy_fns.pop(); |
| 461 | | 459 | |
| ... | @@ -464,11 +462,21 @@ pub const Function = struct { | ... | @@ -464,11 +462,21 @@ pub const Function = struct { |
| 464 | const arena = promoted.arena.allocator(); | 462 | const arena = promoted.arena.allocator(); |
| 465 | | 463 | |
| 466 | gop.value_ptr.* = .{ | 464 | gop.value_ptr.* = .{ |
| 467 | .fn_name = try std.fmt.allocPrint(arena, "zig_tagName_{}__{d}", .{ | 465 | .fn_name = switch (key) { |
| 468 | fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)), | 466 | .tag_name, |
| 469 | @enumToInt(owner_decl), | 467 | .never_tail, |
| 470 | }), | 468 | .never_inline, |
| 471 | .data = .{ .tag_name = try enum_ty.copy(arena) }, | 469 | => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{ |
| | 470 | @tagName(key), |
| | 471 | fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)), |
| | 472 | @enumToInt(owner_decl), |
| | 473 | }), |
| | 474 | }, |
| | 475 | .data = switch (key) { |
| | 476 | .tag_name => .{ .tag_name = try data.tag_name.copy(arena) }, |
| | 477 | .never_tail => .{ .never_tail = data.never_tail }, |
| | 478 | .never_inline => .{ .never_inline = data.never_inline }, |
| | 479 | }, |
| 472 | }; | 480 | }; |
| 473 | } | 481 | } |
| 474 | return gop.value_ptr.fn_name; | 482 | return gop.value_ptr.fn_name; |
| ... | @@ -1457,24 +1465,31 @@ pub const DeclGen = struct { | ... | @@ -1457,24 +1465,31 @@ pub const DeclGen = struct { |
| 1457 | } | 1465 | } |
| 1458 | } | 1466 | } |
| 1459 | | 1467 | |
| 1460 | fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void { | 1468 | fn renderFunctionSignature( |
| | 1469 | dg: *DeclGen, |
| | 1470 | w: anytype, |
| | 1471 | fn_decl_index: Decl.Index, |
| | 1472 | kind: CType.Kind, |
| | 1473 | name: union(enum) { |
| | 1474 | export_index: u32, |
| | 1475 | string: []const u8, |
| | 1476 | }, |
| | 1477 | ) !void { |
| 1461 | const store = &dg.ctypes.set; | 1478 | const store = &dg.ctypes.set; |
| 1462 | const module = dg.module; | 1479 | const module = dg.module; |
| 1463 | | 1480 | |
| 1464 | const fn_ty = dg.decl.?.ty; | 1481 | const fn_decl = module.declPtr(fn_decl_index); |
| 1465 | const fn_cty_idx = try dg.typeToIndex(fn_ty, switch (kind) { | 1482 | const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind); |
| 1466 | .Forward => .forward, | | |
| 1467 | .Complete => .complete, | | |
| 1468 | }); | | |
| 1469 | | 1483 | |
| 1470 | const fn_info = fn_ty.fnInfo(); | 1484 | const fn_info = fn_decl.ty.fnInfo(); |
| 1471 | if (fn_info.cc == .Naked) { | 1485 | if (fn_info.cc == .Naked) { |
| 1472 | switch (kind) { | 1486 | switch (kind) { |
| 1473 | .Forward => try w.writeAll("zig_naked_decl "), | 1487 | .forward => try w.writeAll("zig_naked_decl "), |
| 1474 | .Complete => try w.writeAll("zig_naked "), | 1488 | .complete => try w.writeAll("zig_naked "), |
| | 1489 | else => unreachable, |
| 1475 | } | 1490 | } |
| 1476 | } | 1491 | } |
| 1477 | if (dg.decl.?.val.castTag(.function)) |func_payload| | 1492 | if (fn_decl.val.castTag(.function)) |func_payload| |
| 1478 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); | 1493 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); |
| 1479 | if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn "); | 1494 | if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn "); |
| 1480 | | 1495 | |
| ... | @@ -1485,7 +1500,7 @@ pub const DeclGen = struct { | ... | @@ -1485,7 +1500,7 @@ pub const DeclGen = struct { |
| 1485 | w, | 1500 | w, |
| 1486 | fn_cty_idx, | 1501 | fn_cty_idx, |
| 1487 | .suffix, | 1502 | .suffix, |
| 1488 | CQualifiers.init(.{}), | 1503 | .{}, |
| 1489 | ); | 1504 | ); |
| 1490 | try w.print("{}", .{trailing}); | 1505 | try w.print("{}", .{trailing}); |
| 1491 | | 1506 | |
| ... | @@ -1493,16 +1508,37 @@ pub const DeclGen = struct { | ... | @@ -1493,16 +1508,37 @@ pub const DeclGen = struct { |
| 1493 | try w.print("zig_callconv({s}) ", .{call_conv}); | 1508 | try w.print("zig_callconv({s}) ", .{call_conv}); |
| 1494 | } | 1509 | } |
| 1495 | | 1510 | |
| 1496 | if (fn_info.alignment > 0 and kind == .Complete) { | 1511 | switch (kind) { |
| 1497 | try w.print(" zig_align_fn({})", .{fn_info.alignment}); | 1512 | .forward => {}, |
| | 1513 | .complete => if (fn_info.alignment > 0) |
| | 1514 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), |
| | 1515 | else => unreachable, |
| 1498 | } | 1516 | } |
| 1499 | | 1517 | |
| 1500 | try dg.renderDeclName(w, dg.decl_index.unwrap().?, export_index); | 1518 | switch (name) { |
| | 1519 | .export_index => |export_index| try dg.renderDeclName(w, fn_decl_index, export_index), |
| | 1520 | .string => |string| try w.writeAll(string), |
| | 1521 | } |
| 1501 | | 1522 | |
| 1502 | try renderTypeSuffix(dg.decl_index, store.*, module, w, fn_cty_idx, .suffix); | 1523 | try renderTypeSuffix( |
| | 1524 | dg.decl_index, |
| | 1525 | store.*, |
| | 1526 | module, |
| | 1527 | w, |
| | 1528 | fn_cty_idx, |
| | 1529 | .suffix, |
| | 1530 | CQualifiers.init(.{ .@"const" = switch (kind) { |
| | 1531 | .forward => false, |
| | 1532 | .complete => true, |
| | 1533 | else => unreachable, |
| | 1534 | } }), |
| | 1535 | ); |
| 1503 | | 1536 | |
| 1504 | if (fn_info.alignment > 0 and kind == .Forward) { | 1537 | switch (kind) { |
| 1505 | try w.print(" zig_align_fn({})", .{fn_info.alignment}); | 1538 | .forward => if (fn_info.alignment > 0) |
| | 1539 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), |
| | 1540 | .complete => {}, |
| | 1541 | else => unreachable, |
| 1506 | } | 1542 | } |
| 1507 | } | 1543 | } |
| 1508 | | 1544 | |
| ... | @@ -1533,16 +1569,8 @@ pub const DeclGen = struct { | ... | @@ -1533,16 +1569,8 @@ pub const DeclGen = struct { |
| 1533 | const store = &dg.ctypes.set; | 1569 | const store = &dg.ctypes.set; |
| 1534 | const module = dg.module; | 1570 | const module = dg.module; |
| 1535 | const idx = try dg.typeToIndex(t, .complete); | 1571 | const idx = try dg.typeToIndex(t, .complete); |
| 1536 | _ = try renderTypePrefix( | 1572 | _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); |
| 1537 | dg.decl_index, | 1573 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); |
| 1538 | store.*, | | |
| 1539 | module, | | |
| 1540 | w, | | |
| 1541 | idx, | | |
| 1542 | .suffix, | | |
| 1543 | CQualifiers.init(.{}), | | |
| 1544 | ); | | |
| 1545 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix); | | |
| 1546 | } | 1574 | } |
| 1547 | | 1575 | |
| 1548 | const IntCastContext = union(enum) { | 1576 | const IntCastContext = union(enum) { |
| ... | @@ -1655,9 +1683,9 @@ pub const DeclGen = struct { | ... | @@ -1655,9 +1683,9 @@ pub const DeclGen = struct { |
| 1655 | w: anytype, | 1683 | w: anytype, |
| 1656 | ty: Type, | 1684 | ty: Type, |
| 1657 | name: CValue, | 1685 | name: CValue, |
| 1658 | mutability: Mutability, | 1686 | qualifiers: CQualifiers, |
| 1659 | alignment: u32, | 1687 | alignment: u32, |
| 1660 | _: TypedefKind, | 1688 | kind: CType.Kind, |
| 1661 | ) error{ OutOfMemory, AnalysisFail }!void { | 1689 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1662 | const store = &dg.ctypes.set; | 1690 | const store = &dg.ctypes.set; |
| 1663 | const module = dg.module; | 1691 | const module = dg.module; |
| ... | @@ -1668,71 +1696,12 @@ pub const DeclGen = struct { | ... | @@ -1668,71 +1696,12 @@ pub const DeclGen = struct { |
| 1668 | .gt => try w.print("zig_align({}) ", .{alignment}), | 1696 | .gt => try w.print("zig_align({}) ", .{alignment}), |
| 1669 | }; | 1697 | }; |
| 1670 | | 1698 | |
| 1671 | const idx = try dg.typeToIndex(ty, .complete); | 1699 | const idx = try dg.typeToIndex(ty, kind); |
| 1672 | const trailing = try renderTypePrefix( | 1700 | const trailing = |
| 1673 | dg.decl_index, | 1701 | try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, qualifiers); |
| 1674 | store.*, | | |
| 1675 | module, | | |
| 1676 | w, | | |
| 1677 | idx, | | |
| 1678 | .suffix, | | |
| 1679 | CQualifiers.init(.{ .@"const" = mutability == .@"const" }), | | |
| 1680 | ); | | |
| 1681 | try w.print("{}", .{trailing}); | 1702 | try w.print("{}", .{trailing}); |
| 1682 | try dg.writeCValue(w, name); | 1703 | try dg.writeCValue(w, name); |
| 1683 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix); | 1704 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); |
| 1684 | } | | |
| 1685 | | | |
| 1686 | fn renderTagNameFn(dg: *DeclGen, w: anytype, fn_name: []const u8, enum_ty: Type) !void { | | |
| 1687 | const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | | |
| 1688 | | | |
| 1689 | try w.writeAll("static "); | | |
| 1690 | try dg.renderType(w, name_slice_ty); | | |
| 1691 | try w.writeByte(' '); | | |
| 1692 | try w.writeAll(fn_name); | | |
| 1693 | try w.writeByte('('); | | |
| 1694 | try dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, .@"const", 0, .Complete); | | |
| 1695 | try w.writeAll(") {\n switch (tag) {\n"); | | |
| 1696 | for (enum_ty.enumFields().keys(), 0..) |name, index| { | | |
| 1697 | const name_z = try dg.gpa.dupeZ(u8, name); | | |
| 1698 | defer dg.gpa.free(name_z); | | |
| 1699 | const name_bytes = name_z[0 .. name_z.len + 1]; | | |
| 1700 | | | |
| 1701 | var tag_pl: Value.Payload.U32 = .{ | | |
| 1702 | .base = .{ .tag = .enum_field_index }, | | |
| 1703 | .data = @intCast(u32, index), | | |
| 1704 | }; | | |
| 1705 | const tag_val = Value.initPayload(&tag_pl.base); | | |
| 1706 | | | |
| 1707 | var int_pl: Value.Payload.U64 = undefined; | | |
| 1708 | const int_val = tag_val.enumToInt(enum_ty, &int_pl); | | |
| 1709 | | | |
| 1710 | var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len }; | | |
| 1711 | const name_ty = Type.initPayload(&name_ty_pl.base); | | |
| 1712 | | | |
| 1713 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes }; | | |
| 1714 | const name_val = Value.initPayload(&name_pl.base); | | |
| 1715 | | | |
| 1716 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; | | |
| 1717 | const len_val = Value.initPayload(&len_pl.base); | | |
| 1718 | | | |
| 1719 | try w.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)}); | | |
| 1720 | try dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, .@"const", 0, .Complete); | | |
| 1721 | try w.writeAll(" = "); | | |
| 1722 | try dg.renderValue(w, name_ty, name_val, .Initializer); | | |
| 1723 | try w.writeAll(";\n return ("); | | |
| 1724 | try dg.renderType(w, name_slice_ty); | | |
| 1725 | try w.print("){{{}, {}}};\n", .{ | | |
| 1726 | fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val), | | |
| 1727 | }); | | |
| 1728 | | | |
| 1729 | try w.writeAll(" }\n"); | | |
| 1730 | } | | |
| 1731 | try w.writeAll(" }\n while ("); | | |
| 1732 | try dg.renderValue(w, Type.bool, Value.true, .Other); | | |
| 1733 | try w.writeAll(") "); | | |
| 1734 | _ = try airBreakpoint(w); | | |
| 1735 | try w.writeAll("}\n"); | | |
| 1736 | } | 1705 | } |
| 1737 | | 1706 | |
| 1738 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { | 1707 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { |
| ... | @@ -1771,6 +1740,7 @@ pub const DeclGen = struct { | ... | @@ -1771,6 +1740,7 @@ pub const DeclGen = struct { |
| 1771 | fmtIdent(ident), | 1740 | fmtIdent(ident), |
| 1772 | }), | 1741 | }), |
| 1773 | .bytes => |bytes| return w.writeAll(bytes), | 1742 | .bytes => |bytes| return w.writeAll(bytes), |
| | 1743 | .call_always_tail => return dg.fail("CBE: the result of @call(.always_tail, ...) must be returned directly", .{}), |
| 1774 | } | 1744 | } |
| 1775 | } | 1745 | } |
| 1776 | | 1746 | |
| ... | @@ -1804,6 +1774,7 @@ pub const DeclGen = struct { | ... | @@ -1804,6 +1774,7 @@ pub const DeclGen = struct { |
| 1804 | try w.writeAll(bytes); | 1774 | try w.writeAll(bytes); |
| 1805 | return w.writeByte(')'); | 1775 | return w.writeByte(')'); |
| 1806 | }, | 1776 | }, |
| | 1777 | .call_always_tail => return dg.writeCValue(w, c_value), |
| 1807 | } | 1778 | } |
| 1808 | } | 1779 | } |
| 1809 | | 1780 | |
| ... | @@ -1816,7 +1787,16 @@ pub const DeclGen = struct { | ... | @@ -1816,7 +1787,16 @@ pub const DeclGen = struct { |
| 1816 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | 1787 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 1817 | switch (c_value) { | 1788 | switch (c_value) { |
| 1818 | .none, .constant, .field, .undef => unreachable, | 1789 | .none, .constant, .field, .undef => unreachable, |
| 1819 | .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => { | 1790 | .new_local, |
| | 1791 | .local, |
| | 1792 | .arg, |
| | 1793 | .arg_array, |
| | 1794 | .decl, |
| | 1795 | .identifier, |
| | 1796 | .payload_identifier, |
| | 1797 | .bytes, |
| | 1798 | .call_always_tail, |
| | 1799 | => { |
| 1820 | try dg.writeCValue(writer, c_value); | 1800 | try dg.writeCValue(writer, c_value); |
| 1821 | try writer.writeAll("->"); | 1801 | try writer.writeAll("->"); |
| 1822 | }, | 1802 | }, |
| ... | @@ -1945,7 +1925,8 @@ pub const DeclGen = struct { | ... | @@ -1945,7 +1925,8 @@ pub const DeclGen = struct { |
| 1945 | | 1925 | |
| 1946 | const CTypeFix = enum { prefix, suffix }; | 1926 | const CTypeFix = enum { prefix, suffix }; |
| 1947 | const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict }); | 1927 | const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict }); |
| 1948 | const CTypeRenderTrailing = enum { | 1928 | const Const = CQualifiers.init(.{ .@"const" = true }); |
| | 1929 | const RenderCTypeTrailing = enum { |
| 1949 | no_space, | 1930 | no_space, |
| 1950 | maybe_space, | 1931 | maybe_space, |
| 1951 | | 1932 | |
| ... | @@ -2004,8 +1985,8 @@ fn renderTypePrefix( | ... | @@ -2004,8 +1985,8 @@ fn renderTypePrefix( |
| 2004 | idx: CType.Index, | 1985 | idx: CType.Index, |
| 2005 | parent_fix: CTypeFix, | 1986 | parent_fix: CTypeFix, |
| 2006 | qualifiers: CQualifiers, | 1987 | qualifiers: CQualifiers, |
| 2007 | ) @TypeOf(w).Error!CTypeRenderTrailing { | 1988 | ) @TypeOf(w).Error!RenderCTypeTrailing { |
| 2008 | var trailing = CTypeRenderTrailing.maybe_space; | 1989 | var trailing = RenderCTypeTrailing.maybe_space; |
| 2009 | | 1990 | |
| 2010 | const cty = store.indexToCType(idx); | 1991 | const cty = store.indexToCType(idx); |
| 2011 | switch (cty.tag()) { | 1992 | switch (cty.tag()) { |
| ... | @@ -2147,7 +2128,7 @@ fn renderTypePrefix( | ... | @@ -2147,7 +2128,7 @@ fn renderTypePrefix( |
| 2147 | w, | 2128 | w, |
| 2148 | cty.cast(CType.Payload.Function).?.data.return_type, | 2129 | cty.cast(CType.Payload.Function).?.data.return_type, |
| 2149 | .suffix, | 2130 | .suffix, |
| 2150 | CQualifiers.init(.{}), | 2131 | .{}, |
| 2151 | ); | 2132 | ); |
| 2152 | switch (parent_fix) { | 2133 | switch (parent_fix) { |
| 2153 | .prefix => { | 2134 | .prefix => { |
| ... | @@ -2174,6 +2155,7 @@ fn renderTypeSuffix( | ... | @@ -2174,6 +2155,7 @@ fn renderTypeSuffix( |
| 2174 | w: anytype, | 2155 | w: anytype, |
| 2175 | idx: CType.Index, | 2156 | idx: CType.Index, |
| 2176 | parent_fix: CTypeFix, | 2157 | parent_fix: CTypeFix, |
| | 2158 | qualifiers: CQualifiers, |
| 2177 | ) @TypeOf(w).Error!void { | 2159 | ) @TypeOf(w).Error!void { |
| 2178 | const cty = store.indexToCType(idx); | 2160 | const cty = store.indexToCType(idx); |
| 2179 | switch (cty.tag()) { | 2161 | switch (cty.tag()) { |
| ... | @@ -2220,7 +2202,15 @@ fn renderTypeSuffix( | ... | @@ -2220,7 +2202,15 @@ fn renderTypeSuffix( |
| 2220 | .pointer_const, | 2202 | .pointer_const, |
| 2221 | .pointer_volatile, | 2203 | .pointer_volatile, |
| 2222 | .pointer_const_volatile, | 2204 | .pointer_const_volatile, |
| 2223 | => try renderTypeSuffix(decl, store, mod, w, cty.cast(CType.Payload.Child).?.data, .prefix), | 2205 | => try renderTypeSuffix( |
| | 2206 | decl, |
| | 2207 | store, |
| | 2208 | mod, |
| | 2209 | w, |
| | 2210 | cty.cast(CType.Payload.Child).?.data, |
| | 2211 | .prefix, |
| | 2212 | .{}, |
| | 2213 | ), |
| 2224 | | 2214 | |
| 2225 | .array, | 2215 | .array, |
| 2226 | .vector, | 2216 | .vector, |
| ... | @@ -2238,6 +2228,7 @@ fn renderTypeSuffix( | ... | @@ -2238,6 +2228,7 @@ fn renderTypeSuffix( |
| 2238 | w, | 2228 | w, |
| 2239 | cty.cast(CType.Payload.Sequence).?.data.elem_type, | 2229 | cty.cast(CType.Payload.Sequence).?.data.elem_type, |
| 2240 | .suffix, | 2230 | .suffix, |
| | 2231 | .{}, |
| 2241 | ); | 2232 | ); |
| 2242 | }, | 2233 | }, |
| 2243 | | 2234 | |
| ... | @@ -2272,17 +2263,10 @@ fn renderTypeSuffix( | ... | @@ -2272,17 +2263,10 @@ fn renderTypeSuffix( |
| 2272 | for (data.param_types, 0..) |param_type, param_i| { | 2263 | for (data.param_types, 0..) |param_type, param_i| { |
| 2273 | if (need_comma) try w.writeAll(", "); | 2264 | if (need_comma) try w.writeAll(", "); |
| 2274 | need_comma = true; | 2265 | need_comma = true; |
| 2275 | const trailing = try renderTypePrefix( | 2266 | const trailing = |
| 2276 | decl, | 2267 | try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers); |
| 2277 | store, | 2268 | if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i }); |
| 2278 | mod, | 2269 | try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{}); |
| 2279 | w, | | |
| 2280 | param_type, | | |
| 2281 | .suffix, | | |
| 2282 | CQualifiers.init(.{ .@"const" = true }), | | |
| 2283 | ); | | |
| 2284 | try w.print("{}a{d}", .{ trailing, param_i }); | | |
| 2285 | try renderTypeSuffix(decl, store, mod, w, param_type, .suffix); | | |
| 2286 | } | 2270 | } |
| 2287 | switch (tag) { | 2271 | switch (tag) { |
| 2288 | .function => {}, | 2272 | .function => {}, |
| ... | @@ -2296,7 +2280,7 @@ fn renderTypeSuffix( | ... | @@ -2296,7 +2280,7 @@ fn renderTypeSuffix( |
| 2296 | if (!need_comma) try w.writeAll("void"); | 2280 | if (!need_comma) try w.writeAll("void"); |
| 2297 | try w.writeByte(')'); | 2281 | try w.writeByte(')'); |
| 2298 | | 2282 | |
| 2299 | try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix); | 2283 | try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix, .{}); |
| 2300 | }, | 2284 | }, |
| 2301 | } | 2285 | } |
| 2302 | } | 2286 | } |
| ... | @@ -2316,17 +2300,9 @@ fn renderAggregateFields( | ... | @@ -2316,17 +2300,9 @@ fn renderAggregateFields( |
| 2316 | .eq => {}, | 2300 | .eq => {}, |
| 2317 | .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}), | 2301 | .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}), |
| 2318 | } | 2302 | } |
| 2319 | const trailing = try renderTypePrefix( | 2303 | const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{}); |
| 2320 | .none, | | |
| 2321 | store, | | |
| 2322 | mod, | | |
| 2323 | writer, | | |
| 2324 | field.type, | | |
| 2325 | .suffix, | | |
| 2326 | CQualifiers.init(.{}), | | |
| 2327 | ); | | |
| 2328 | try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) }); | 2304 | try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) }); |
| 2329 | try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix); | 2305 | try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix, .{}); |
| 2330 | try writer.writeAll(";\n"); | 2306 | try writer.writeAll(";\n"); |
| 2331 | } | 2307 | } |
| 2332 | try writer.writeByteNTimes(' ', indent); | 2308 | try writer.writeByteNTimes(' ', indent); |
| ... | @@ -2347,25 +2323,9 @@ pub fn genTypeDecl( | ... | @@ -2347,25 +2323,9 @@ pub fn genTypeDecl( |
| 2347 | switch (global_cty.tag()) { | 2323 | switch (global_cty.tag()) { |
| 2348 | .fwd_anon_struct => if (decl != .none) { | 2324 | .fwd_anon_struct => if (decl != .none) { |
| 2349 | try writer.writeAll("typedef "); | 2325 | try writer.writeAll("typedef "); |
| 2350 | _ = try renderTypePrefix( | 2326 | _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{}); |
| 2351 | .none, | | |
| 2352 | global_store, | | |
| 2353 | mod, | | |
| 2354 | writer, | | |
| 2355 | global_idx, | | |
| 2356 | .suffix, | | |
| 2357 | CQualifiers.init(.{}), | | |
| 2358 | ); | | |
| 2359 | try writer.writeByte(' '); | 2327 | try writer.writeByte(' '); |
| 2360 | _ = try renderTypePrefix( | 2328 | _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{}); |
| 2361 | decl, | | |
| 2362 | decl_store, | | |
| 2363 | mod, | | |
| 2364 | writer, | | |
| 2365 | decl_idx, | | |
| 2366 | .suffix, | | |
| 2367 | CQualifiers.init(.{}), | | |
| 2368 | ); | | |
| 2369 | try writer.writeAll(";\n"); | 2329 | try writer.writeAll(";\n"); |
| 2370 | }, | 2330 | }, |
| 2371 | | 2331 | |
| ... | @@ -2383,15 +2343,7 @@ pub fn genTypeDecl( | ... | @@ -2383,15 +2343,7 @@ pub fn genTypeDecl( |
| 2383 | .fwd_union, | 2343 | .fwd_union, |
| 2384 | => { | 2344 | => { |
| 2385 | const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data; | 2345 | const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data; |
| 2386 | _ = try renderTypePrefix( | 2346 | _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{}); |
| 2387 | .none, | | |
| 2388 | global_store, | | |
| 2389 | mod, | | |
| 2390 | writer, | | |
| 2391 | global_idx, | | |
| 2392 | .suffix, | | |
| 2393 | CQualifiers.init(.{}), | | |
| 2394 | ); | | |
| 2395 | try writer.writeAll("; // "); | 2347 | try writer.writeAll("; // "); |
| 2396 | try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer); | 2348 | try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer); |
| 2397 | try writer.writeByte('\n'); | 2349 | try writer.writeByte('\n'); |
| ... | @@ -2467,7 +2419,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2467,7 +2419,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2467 | const name_val = Value.initPayload(&name_pl.base); | 2419 | const name_val = Value.initPayload(&name_pl.base); |
| 2468 | | 2420 | |
| 2469 | try writer.writeAll("static "); | 2421 | try writer.writeAll("static "); |
| 2470 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .@"const", 0, .Complete); | 2422 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); |
| 2471 | try writer.writeAll(" = "); | 2423 | try writer.writeAll(" = "); |
| 2472 | try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer); | 2424 | try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer); |
| 2473 | try writer.writeAll(";\n"); | 2425 | try writer.writeAll(";\n"); |
| ... | @@ -2480,7 +2432,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2480,7 +2432,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2480 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); | 2432 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); |
| 2481 | | 2433 | |
| 2482 | try writer.writeAll("static "); | 2434 | try writer.writeAll("static "); |
| 2483 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .@"const", 0, .Complete); | 2435 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, Const, 0, .complete); |
| 2484 | try writer.writeAll(" = {"); | 2436 | try writer.writeAll(" = {"); |
| 2485 | for (o.dg.module.error_name_list.items, 0..) |name, value| { | 2437 | for (o.dg.module.error_name_list.items, 0..) |name, value| { |
| 2486 | if (value != 0) try writer.writeByte(','); | 2438 | if (value != 0) try writer.writeByte(','); |
| ... | @@ -2503,7 +2455,7 @@ fn genExports(o: *Object) !void { | ... | @@ -2503,7 +2455,7 @@ fn genExports(o: *Object) !void { |
| 2503 | if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { | 2455 | if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { |
| 2504 | for (exports.items[1..], 1..) |@"export", i| { | 2456 | for (exports.items[1..], 1..) |@"export", i| { |
| 2505 | try fwd_decl_writer.writeAll("zig_export("); | 2457 | try fwd_decl_writer.writeAll("zig_export("); |
| 2506 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, i)); | 2458 | try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) }); |
| 2507 | try fwd_decl_writer.print(", {s}, {s});\n", .{ | 2459 | try fwd_decl_writer.print(", {s}, {s});\n", .{ |
| 2508 | fmtStringLiteral(exports.items[0].options.name), | 2460 | fmtStringLiteral(exports.items[0].options.name), |
| 2509 | fmtStringLiteral(@"export".options.name), | 2461 | fmtStringLiteral(@"export".options.name), |
| ... | @@ -2513,13 +2465,85 @@ fn genExports(o: *Object) !void { | ... | @@ -2513,13 +2465,85 @@ fn genExports(o: *Object) !void { |
| 2513 | } | 2465 | } |
| 2514 | | 2466 | |
| 2515 | pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | 2467 | pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2516 | const writer = o.writer(); | 2468 | const w = o.writer(); |
| 2517 | switch (lazy_fn.key_ptr.*) { | 2469 | const key = lazy_fn.key_ptr.*; |
| 2518 | .tag_name => _ = try o.dg.renderTagNameFn( | 2470 | const val = lazy_fn.value_ptr; |
| 2519 | writer, | 2471 | const fn_name = val.fn_name; |
| 2520 | lazy_fn.value_ptr.fn_name, | 2472 | switch (key) { |
| 2521 | lazy_fn.value_ptr.data.tag_name, | 2473 | .tag_name => { |
| 2522 | ), | 2474 | const enum_ty = val.data.tag_name; |
| | 2475 | |
| | 2476 | const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| | 2477 | |
| | 2478 | try w.writeAll("static "); |
| | 2479 | try o.dg.renderType(w, name_slice_ty); |
| | 2480 | try w.writeByte(' '); |
| | 2481 | try w.writeAll(fn_name); |
| | 2482 | try w.writeByte('('); |
| | 2483 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); |
| | 2484 | try w.writeAll(") {\n switch (tag) {\n"); |
| | 2485 | for (enum_ty.enumFields().keys(), 0..) |name, index| { |
| | 2486 | const name_z = try o.dg.gpa.dupeZ(u8, name); |
| | 2487 | defer o.dg.gpa.free(name_z); |
| | 2488 | const name_bytes = name_z[0 .. name_z.len + 1]; |
| | 2489 | |
| | 2490 | var tag_pl: Value.Payload.U32 = .{ |
| | 2491 | .base = .{ .tag = .enum_field_index }, |
| | 2492 | .data = @intCast(u32, index), |
| | 2493 | }; |
| | 2494 | const tag_val = Value.initPayload(&tag_pl.base); |
| | 2495 | |
| | 2496 | var int_pl: Value.Payload.U64 = undefined; |
| | 2497 | const int_val = tag_val.enumToInt(enum_ty, &int_pl); |
| | 2498 | |
| | 2499 | var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len }; |
| | 2500 | const name_ty = Type.initPayload(&name_ty_pl.base); |
| | 2501 | |
| | 2502 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes }; |
| | 2503 | const name_val = Value.initPayload(&name_pl.base); |
| | 2504 | |
| | 2505 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; |
| | 2506 | const len_val = Value.initPayload(&len_pl.base); |
| | 2507 | |
| | 2508 | try w.print(" case {}: {{\n static ", .{try o.dg.fmtIntLiteral(enum_ty, int_val)}); |
| | 2509 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); |
| | 2510 | try w.writeAll(" = "); |
| | 2511 | try o.dg.renderValue(w, name_ty, name_val, .Initializer); |
| | 2512 | try w.writeAll(";\n return ("); |
| | 2513 | try o.dg.renderType(w, name_slice_ty); |
| | 2514 | try w.print("){{{}, {}}};\n", .{ |
| | 2515 | fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val), |
| | 2516 | }); |
| | 2517 | |
| | 2518 | try w.writeAll(" }\n"); |
| | 2519 | } |
| | 2520 | try w.writeAll(" }\n while ("); |
| | 2521 | try o.dg.renderValue(w, Type.bool, Value.true, .Other); |
| | 2522 | try w.writeAll(") "); |
| | 2523 | _ = try airBreakpoint(w); |
| | 2524 | try w.writeAll("}\n"); |
| | 2525 | }, |
| | 2526 | .never_tail, .never_inline => |fn_decl_index| { |
| | 2527 | const fn_decl = o.dg.module.declPtr(fn_decl_index); |
| | 2528 | const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete); |
| | 2529 | const fn_info = fn_cty.cast(CType.Payload.Function).?.data; |
| | 2530 | |
| | 2531 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| | 2532 | try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)}); |
| | 2533 | try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ .string = fn_name }); |
| | 2534 | try fwd_decl_writer.writeAll(";\n"); |
| | 2535 | |
| | 2536 | try w.print("static zig_{s} ", .{@tagName(key)}); |
| | 2537 | try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .string = fn_name }); |
| | 2538 | try w.writeAll(" {\n return "); |
| | 2539 | try o.dg.renderDeclName(w, fn_decl_index, 0); |
| | 2540 | try w.writeByte('('); |
| | 2541 | for (0..fn_info.param_types.len) |arg| { |
| | 2542 | if (arg > 0) try w.writeAll(", "); |
| | 2543 | try o.dg.writeCValue(w, .{ .arg = arg }); |
| | 2544 | } |
| | 2545 | try w.writeAll(");\n}\n"); |
| | 2546 | }, |
| 2523 | } | 2547 | } |
| 2524 | } | 2548 | } |
| 2525 | | 2549 | |
| ... | @@ -2529,6 +2553,7 @@ pub fn genFunc(f: *Function) !void { | ... | @@ -2529,6 +2553,7 @@ pub fn genFunc(f: *Function) !void { |
| 2529 | | 2553 | |
| 2530 | const o = &f.object; | 2554 | const o = &f.object; |
| 2531 | const gpa = o.dg.gpa; | 2555 | const gpa = o.dg.gpa; |
| | 2556 | const decl_index = o.dg.decl_index.unwrap().?; |
| 2532 | const tv: TypedValue = .{ | 2557 | const tv: TypedValue = .{ |
| 2533 | .ty = o.dg.decl.?.ty, | 2558 | .ty = o.dg.decl.?.ty, |
| 2534 | .val = o.dg.decl.?.val, | 2559 | .val = o.dg.decl.?.val, |
| ... | @@ -2540,13 +2565,13 @@ pub fn genFunc(f: *Function) !void { | ... | @@ -2540,13 +2565,13 @@ pub fn genFunc(f: *Function) !void { |
| 2540 | const is_global = o.dg.declIsGlobal(tv); | 2565 | const is_global = o.dg.declIsGlobal(tv); |
| 2541 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2566 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2542 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | 2567 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); |
| 2543 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0); | 2568 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 }); |
| 2544 | try fwd_decl_writer.writeAll(";\n"); | 2569 | try fwd_decl_writer.writeAll(";\n"); |
| 2545 | try genExports(o); | 2570 | try genExports(o); |
| 2546 | | 2571 | |
| 2547 | try o.indent_writer.insertNewline(); | 2572 | try o.indent_writer.insertNewline(); |
| 2548 | if (!is_global) try o.writer().writeAll("static "); | 2573 | if (!is_global) try o.writer().writeAll("static "); |
| 2549 | try o.dg.renderFunctionSignature(o.writer(), .Complete, 0); | 2574 | try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 }); |
| 2550 | try o.writer().writeByte(' '); | 2575 | try o.writer().writeByte(' '); |
| 2551 | | 2576 | |
| 2552 | // In case we need to use the header, populate it with a copy of the function | 2577 | // In case we need to use the header, populate it with a copy of the function |
| ... | @@ -2600,9 +2625,9 @@ pub fn genFunc(f: *Function) !void { | ... | @@ -2600,9 +2625,9 @@ pub fn genFunc(f: *Function) !void { |
| 2600 | w, | 2625 | w, |
| 2601 | local.ty, | 2626 | local.ty, |
| 2602 | .{ .local = local_index }, | 2627 | .{ .local = local_index }, |
| 2603 | .mut, | 2628 | .{}, |
| 2604 | local.alignment, | 2629 | local.alignment, |
| 2605 | .Complete, | 2630 | .complete, |
| 2606 | ); | 2631 | ); |
| 2607 | try w.writeAll(";\n "); | 2632 | try w.writeAll(";\n "); |
| 2608 | } | 2633 | } |
| ... | @@ -2628,7 +2653,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2628,7 +2653,7 @@ pub fn genDecl(o: *Object) !void { |
| 2628 | if (tv.val.tag() == .extern_fn) { | 2653 | if (tv.val.tag() == .extern_fn) { |
| 2629 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2654 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2630 | try fwd_decl_writer.writeAll("zig_extern "); | 2655 | try fwd_decl_writer.writeAll("zig_extern "); |
| 2631 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0); | 2656 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 }); |
| 2632 | try fwd_decl_writer.writeAll(";\n"); | 2657 | try fwd_decl_writer.writeAll(";\n"); |
| 2633 | try genExports(o); | 2658 | try genExports(o); |
| 2634 | } else if (tv.val.castTag(.variable)) |var_payload| { | 2659 | } else if (tv.val.castTag(.variable)) |var_payload| { |
| ... | @@ -2639,7 +2664,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2639,7 +2664,7 @@ pub fn genDecl(o: *Object) !void { |
| 2639 | | 2664 | |
| 2640 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | 2665 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); |
| 2641 | if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal "); | 2666 | if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal "); |
| 2642 | try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .mut, decl.@"align", .Complete); | 2667 | try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .{}, decl.@"align", .complete); |
| 2643 | try fwd_decl_writer.writeAll(";\n"); | 2668 | try fwd_decl_writer.writeAll(";\n"); |
| 2644 | try genExports(o); | 2669 | try genExports(o); |
| 2645 | | 2670 | |
| ... | @@ -2649,7 +2674,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2649,7 +2674,7 @@ pub fn genDecl(o: *Object) !void { |
| 2649 | if (!is_global) try w.writeAll("static "); | 2674 | if (!is_global) try w.writeAll("static "); |
| 2650 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); | 2675 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2651 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); | 2676 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); |
| 2652 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .mut, decl.@"align", .Complete); | 2677 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete); |
| 2653 | if (decl.@"linksection" != null) try w.writeAll(", read, write)"); | 2678 | if (decl.@"linksection" != null) try w.writeAll(", read, write)"); |
| 2654 | try w.writeAll(" = "); | 2679 | try w.writeAll(" = "); |
| 2655 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); | 2680 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); |
| ... | @@ -2660,13 +2685,13 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2660,13 +2685,13 @@ pub fn genDecl(o: *Object) !void { |
| 2660 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2685 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2661 | | 2686 | |
| 2662 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | 2687 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); |
| 2663 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete); | 2688 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.@"align", .complete); |
| 2664 | try fwd_decl_writer.writeAll(";\n"); | 2689 | try fwd_decl_writer.writeAll(";\n"); |
| 2665 | | 2690 | |
| 2666 | const w = o.writer(); | 2691 | const w = o.writer(); |
| 2667 | if (!is_global) try w.writeAll("static "); | 2692 | if (!is_global) try w.writeAll("static "); |
| 2668 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); | 2693 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); |
| 2669 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .@"const", decl.@"align", .Complete); | 2694 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete); |
| 2670 | if (decl.@"linksection" != null) try w.writeAll(", read)"); | 2695 | if (decl.@"linksection" != null) try w.writeAll(", read)"); |
| 2671 | try w.writeAll(" = "); | 2696 | try w.writeAll(" = "); |
| 2672 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); | 2697 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); |
| ... | @@ -2689,7 +2714,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { | ... | @@ -2689,7 +2714,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 2689 | const is_global = dg.declIsGlobal(tv); | 2714 | const is_global = dg.declIsGlobal(tv); |
| 2690 | if (is_global) { | 2715 | if (is_global) { |
| 2691 | try writer.writeAll("zig_extern "); | 2716 | try writer.writeAll("zig_extern "); |
| 2692 | try dg.renderFunctionSignature(writer, .Complete, 0); | 2717 | try dg.renderFunctionSignature(writer, dg.decl_index.unwrap().?, .complete, .{ .export_index = 0 }); |
| 2693 | try dg.fwd_decl.appendSlice(";\n"); | 2718 | try dg.fwd_decl.appendSlice(";\n"); |
| 2694 | } | 2719 | } |
| 2695 | }, | 2720 | }, |
| ... | @@ -2879,10 +2904,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2879,10 +2904,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2879 | | 2904 | |
| 2880 | .dbg_block_begin, | 2905 | .dbg_block_begin, |
| 2881 | .dbg_block_end, | 2906 | .dbg_block_end, |
| 2882 | => CValue{ .none = {} }, | 2907 | => .none, |
| 2883 | | 2908 | |
| 2884 | .call => try airCall(f, inst, .auto), | 2909 | .call => try airCall(f, inst, .auto), |
| 2885 | .call_always_tail => try airCall(f, inst, .always_tail), | 2910 | .call_always_tail => .call_always_tail, |
| 2886 | .call_never_tail => try airCall(f, inst, .never_tail), | 2911 | .call_never_tail => try airCall(f, inst, .never_tail), |
| 2887 | .call_never_inline => try airCall(f, inst, .never_inline), | 2912 | .call_never_inline => try airCall(f, inst, .never_inline), |
| 2888 | | 2913 | |
| ... | @@ -3199,9 +3224,12 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3199,9 +3224,12 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3199 | return CValue{ .undef = inst_ty }; | 3224 | return CValue{ .undef = inst_ty }; |
| 3200 | } | 3225 | } |
| 3201 | | 3226 | |
| 3202 | const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut; | | |
| 3203 | const target = f.object.dg.module.getTarget(); | 3227 | const target = f.object.dg.module.getTarget(); |
| 3204 | const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target)); | 3228 | const local = try f.allocAlignedLocal( |
| | 3229 | elem_type, |
| | 3230 | CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }), |
| | 3231 | inst_ty.ptrAlignment(target), |
| | 3232 | ); |
| 3205 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); | 3233 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3206 | const gpa = f.object.dg.module.gpa; | 3234 | const gpa = f.object.dg.module.gpa; |
| 3207 | try f.allocs.put(gpa, local.new_local, false); | 3235 | try f.allocs.put(gpa, local.new_local, false); |
| ... | @@ -3216,9 +3244,12 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3216,9 +3244,12 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3216 | return CValue{ .undef = inst_ty }; | 3244 | return CValue{ .undef = inst_ty }; |
| 3217 | } | 3245 | } |
| 3218 | | 3246 | |
| 3219 | const mutability: Mutability = if (inst_ty.isConstPtr()) .@"const" else .mut; | | |
| 3220 | const target = f.object.dg.module.getTarget(); | 3247 | const target = f.object.dg.module.getTarget(); |
| 3221 | const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target)); | 3248 | const local = try f.allocAlignedLocal( |
| | 3249 | elem_ty, |
| | 3250 | CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }), |
| | 3251 | inst_ty.ptrAlignment(target), |
| | 3252 | ); |
| 3222 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); | 3253 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3223 | const gpa = f.object.dg.module.gpa; | 3254 | const gpa = f.object.dg.module.gpa; |
| 3224 | try f.allocs.put(gpa, local.new_local, false); | 3255 | try f.allocs.put(gpa, local.new_local, false); |
| ... | @@ -3336,10 +3367,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | ... | @@ -3336,10 +3367,19 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3336 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 3367 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| 3337 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | 3368 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| 3338 | | 3369 | |
| 3339 | if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { | 3370 | const is_naked = if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() == .Naked else false; |
| 3340 | var deref = is_ptr; | 3371 | const peek_operand = f.value_map.get(un_op); |
| | 3372 | if (if (peek_operand) |operand| operand == .call_always_tail else false) { |
| | 3373 | try reap(f, inst, &.{un_op}); |
| | 3374 | if (is_naked) { |
| | 3375 | try f.writeCValue(writer, peek_operand.?, .Other); |
| | 3376 | unreachable; |
| | 3377 | } |
| | 3378 | _ = try airCall(f, Air.refToIndex(un_op).?, .always_tail); |
| | 3379 | } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3341 | const operand = try f.resolveInst(un_op); | 3380 | const operand = try f.resolveInst(un_op); |
| 3342 | try reap(f, inst, &.{un_op}); | 3381 | try reap(f, inst, &.{un_op}); |
| | 3382 | var deref = is_ptr; |
| 3343 | const is_array = lowersToArray(ret_ty, target); | 3383 | const is_array = lowersToArray(ret_ty, target); |
| 3344 | const ret_val = if (is_array) ret_val: { | 3384 | const ret_val = if (is_array) ret_val: { |
| 3345 | const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator())); | 3385 | const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator())); |
| ... | @@ -3368,9 +3408,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | ... | @@ -3368,9 +3408,8 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3368 | } | 3408 | } |
| 3369 | } else { | 3409 | } else { |
| 3370 | try reap(f, inst, &.{un_op}); | 3410 | try reap(f, inst, &.{un_op}); |
| 3371 | if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() != .Naked) | 3411 | // Not even allowed to return void in a naked function. |
| 3372 | // Not even allowed to return void in a naked function. | 3412 | if (!is_naked) try writer.writeAll("return;\n"); |
| 3373 | try writer.writeAll("return;\n"); | | |
| 3374 | } | 3413 | } |
| 3375 | return CValue.none; | 3414 | return CValue.none; |
| 3376 | } | 3415 | } |
| ... | @@ -4004,13 +4043,6 @@ fn airCall( | ... | @@ -4004,13 +4043,6 @@ fn airCall( |
| 4004 | const target = module.getTarget(); | 4043 | const target = module.getTarget(); |
| 4005 | const writer = f.object.writer(); | 4044 | const writer = f.object.writer(); |
| 4006 | | 4045 | |
| 4007 | switch (modifier) { | | |
| 4008 | .auto => {}, | | |
| 4009 | .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}), | | |
| 4010 | .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}), | | |
| 4011 | .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}), | | |
| 4012 | else => unreachable, | | |
| 4013 | } | | |
| 4014 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4046 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4015 | const extra = f.air.extraData(Air.Call, pl_op.payload); | 4047 | const extra = f.air.extraData(Air.Call, pl_op.payload); |
| 4016 | const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); | 4048 | const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]); |
| ... | @@ -4060,7 +4092,10 @@ fn airCall( | ... | @@ -4060,7 +4092,10 @@ fn airCall( |
| 4060 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 4092 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; |
| 4061 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | 4093 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); |
| 4062 | | 4094 | |
| 4063 | const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) | 4095 | const result_local: CValue = if (modifier == .always_tail) r: { |
| | 4096 | try writer.writeAll("zig_always_tail return "); |
| | 4097 | break :r .none; |
| | 4098 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 4064 | .none | 4099 | .none |
| 4065 | else if (f.liveness.isUnused(inst)) r: { | 4100 | else if (f.liveness.isUnused(inst)) r: { |
| 4066 | try writer.writeByte('('); | 4101 | try writer.writeByte('('); |
| ... | @@ -4074,26 +4109,33 @@ fn airCall( | ... | @@ -4074,26 +4109,33 @@ fn airCall( |
| 4074 | break :r local; | 4109 | break :r local; |
| 4075 | }; | 4110 | }; |
| 4076 | | 4111 | |
| 4077 | var is_extern = false; | | |
| 4078 | var name: [*:0]const u8 = ""; | | |
| 4079 | callee: { | 4112 | callee: { |
| 4080 | known: { | 4113 | known: { |
| 4081 | const fn_decl = fn_decl: { | 4114 | const fn_decl = fn_decl: { |
| 4082 | const callee_val = f.air.value(pl_op.operand) orelse break :known; | 4115 | const callee_val = f.air.value(pl_op.operand) orelse break :known; |
| 4083 | break :fn_decl switch (callee_val.tag()) { | 4116 | break :fn_decl switch (callee_val.tag()) { |
| 4084 | .extern_fn => blk: { | 4117 | .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, |
| 4085 | is_extern = true; | | |
| 4086 | break :blk callee_val.castTag(.extern_fn).?.data.owner_decl; | | |
| 4087 | }, | | |
| 4088 | .function => callee_val.castTag(.function).?.data.owner_decl, | 4118 | .function => callee_val.castTag(.function).?.data.owner_decl, |
| 4089 | .decl_ref => callee_val.castTag(.decl_ref).?.data, | 4119 | .decl_ref => callee_val.castTag(.decl_ref).?.data, |
| 4090 | else => break :known, | 4120 | else => break :known, |
| 4091 | }; | 4121 | }; |
| 4092 | }; | 4122 | }; |
| 4093 | name = module.declPtr(fn_decl).name; | 4123 | switch (modifier) { |
| 4094 | try f.object.dg.renderDeclName(writer, fn_decl, 0); | 4124 | .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0), |
| | 4125 | inline .never_tail, .never_inline => |mod| try writer.writeAll(try f.getLazyFnName( |
| | 4126 | @unionInit(LazyFnKey, @tagName(mod), fn_decl), |
| | 4127 | @unionInit(LazyFnValue.Data, @tagName(mod), {}), |
| | 4128 | )), |
| | 4129 | else => unreachable, |
| | 4130 | } |
| 4095 | break :callee; | 4131 | break :callee; |
| 4096 | } | 4132 | } |
| | 4133 | switch (modifier) { |
| | 4134 | .auto, .always_tail => {}, |
| | 4135 | .never_tail => return f.fail("CBE: runtime callee with never_tail attribute unsupported", .{}), |
| | 4136 | .never_inline => return f.fail("CBE: runtime callee with never_inline attribute unsupported", .{}), |
| | 4137 | else => unreachable, |
| | 4138 | } |
| 4097 | // Fall back to function pointer call. | 4139 | // Fall back to function pointer call. |
| 4098 | try f.writeCValue(writer, callee, .Other); | 4140 | try f.writeCValue(writer, callee, .Other); |
| 4099 | } | 4141 | } |
| ... | @@ -4704,14 +4746,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4704,14 +4746,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4704 | try writer.writeAll("register "); | 4746 | try writer.writeAll("register "); |
| 4705 | const alignment = 0; | 4747 | const alignment = 0; |
| 4706 | const local_value = try f.allocLocalValue(output_ty, alignment); | 4748 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| 4707 | try f.object.dg.renderTypeAndName( | 4749 | try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete); |
| 4708 | writer, | | |
| 4709 | output_ty, | | |
| 4710 | local_value, | | |
| 4711 | .mut, | | |
| 4712 | alignment, | | |
| 4713 | .Complete, | | |
| 4714 | ); | | |
| 4715 | try writer.writeAll(" __asm(\""); | 4750 | try writer.writeAll(" __asm(\""); |
| 4716 | try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); | 4751 | try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); |
| 4717 | try writer.writeAll("\")"); | 4752 | try writer.writeAll("\")"); |
| ... | @@ -4743,14 +4778,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4743,14 +4778,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4743 | if (is_reg) try writer.writeAll("register "); | 4778 | if (is_reg) try writer.writeAll("register "); |
| 4744 | const alignment = 0; | 4779 | const alignment = 0; |
| 4745 | const local_value = try f.allocLocalValue(input_ty, alignment); | 4780 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| 4746 | try f.object.dg.renderTypeAndName( | 4781 | try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete); |
| 4747 | writer, | | |
| 4748 | input_ty, | | |
| 4749 | local_value, | | |
| 4750 | .@"const", | | |
| 4751 | alignment, | | |
| 4752 | .Complete, | | |
| 4753 | ); | | |
| 4754 | if (is_reg) { | 4782 | if (is_reg) { |
| 4755 | try writer.writeAll(" __asm(\""); | 4783 | try writer.writeAll(" __asm(\""); |
| 4756 | try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); | 4784 | try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); |
| ... | @@ -6278,7 +6306,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6278,7 +6306,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6278 | const writer = f.object.writer(); | 6306 | const writer = f.object.writer(); |
| 6279 | const local = try f.allocLocal(inst, inst_ty); | 6307 | const local = try f.allocLocal(inst, inst_ty); |
| 6280 | try f.writeCValue(writer, local, .Other); | 6308 | try f.writeCValue(writer, local, .Other); |
| 6281 | try writer.print(" = {s}(", .{try f.getTagNameFn(enum_ty)}); | 6309 | try writer.print(" = {s}(", .{ |
| | 6310 | try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl() }, .{ .tag_name = enum_ty }), |
| | 6311 | }); |
| 6282 | try f.writeCValue(writer, operand, .Other); | 6312 | try f.writeCValue(writer, operand, .Other); |
| 6283 | try writer.writeAll(");\n"); | 6313 | try writer.writeAll(");\n"); |
| 6284 | | 6314 | |