mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 16:24:51 +00:00
cbe: reapply writer changes
This commit is contained in:
parent
69fd07bd50
commit
725dbf295e
@ -56,6 +56,7 @@ pub const Mir = struct {
|
||||
/// less than the natural alignment.
|
||||
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
|
||||
// These remaining fields are essentially just an owned version of `link.C.AvBlock`.
|
||||
code_header: []u8,
|
||||
code: []u8,
|
||||
fwd_decl: []u8,
|
||||
ctype_pool: CType.Pool,
|
||||
@ -63,6 +64,7 @@ pub const Mir = struct {
|
||||
|
||||
pub fn deinit(mir: *Mir, gpa: Allocator) void {
|
||||
mir.uavs.deinit(gpa);
|
||||
gpa.free(mir.code_header);
|
||||
gpa.free(mir.code);
|
||||
gpa.free(mir.fwd_decl);
|
||||
mir.ctype_pool.deinit(gpa);
|
||||
@ -345,23 +347,23 @@ fn isReservedIdent(ident: []const u8) bool {
|
||||
|
||||
fn formatIdent(
|
||||
ident: []const u8,
|
||||
writer: *Writer,
|
||||
w: *Writer,
|
||||
comptime fmt_str: []const u8,
|
||||
) Writer.Error!void {
|
||||
const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
|
||||
if (solo and isReservedIdent(ident)) {
|
||||
try writer.writeAll("zig_e_");
|
||||
try w.writeAll("zig_e_");
|
||||
}
|
||||
for (ident, 0..) |c, i| {
|
||||
switch (c) {
|
||||
'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
|
||||
'.' => try writer.writeByte('_'),
|
||||
'a'...'z', 'A'...'Z', '_' => try w.writeByte(c),
|
||||
'.' => try w.writeByte('_'),
|
||||
'0'...'9' => if (i == 0) {
|
||||
try writer.print("_{x:2}", .{c});
|
||||
try w.print("_{x:2}", .{c});
|
||||
} else {
|
||||
try writer.writeByte(c);
|
||||
try w.writeByte(c);
|
||||
},
|
||||
else => try writer.print("_{x:2}", .{c}),
|
||||
else => try w.print("_{x:2}", .{c}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -375,13 +377,13 @@ const CTypePoolStringFormatData = struct {
|
||||
};
|
||||
fn formatCTypePoolString(
|
||||
data: CTypePoolStringFormatData,
|
||||
writer: *Writer,
|
||||
w: *Writer,
|
||||
comptime fmt_str: []const u8,
|
||||
) Writer.Error!void {
|
||||
if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
|
||||
try formatIdent(slice, writer, fmt_str)
|
||||
try formatIdent(slice, w, fmt_str)
|
||||
else
|
||||
try writer.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
|
||||
try w.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
|
||||
}
|
||||
pub fn fmtCTypePoolString(
|
||||
ctype_pool_string: CType.Pool.String,
|
||||
@ -441,18 +443,18 @@ pub const Function = struct {
|
||||
const ty = f.typeOf(ref);
|
||||
|
||||
const result: CValue = if (lowersToArray(ty, pt)) result: {
|
||||
const writer = &f.object.code_header.buffered_writer;
|
||||
const ch = &f.object.code_header.buffered_writer;
|
||||
const decl_c_value = try f.allocLocalValue(.{
|
||||
.ctype = try f.ctypeFromType(ty, .complete),
|
||||
.alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
|
||||
});
|
||||
const gpa = f.object.dg.gpa;
|
||||
try f.allocs.put(gpa, decl_c_value.new_local, false);
|
||||
try writer.writeAll("static ");
|
||||
try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);
|
||||
try writer.writeAll(" = ");
|
||||
try f.object.dg.renderValue(writer, val, .StaticInitializer);
|
||||
try writer.writeAll(";\n ");
|
||||
try ch.writeAll("static ");
|
||||
try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete);
|
||||
try ch.writeAll(" = ");
|
||||
try f.object.dg.renderValue(ch, val, .StaticInitializer);
|
||||
try ch.writeAll(";\n ");
|
||||
break :result .{ .local = decl_c_value.new_local };
|
||||
} else .{ .constant = val };
|
||||
|
||||
@ -979,7 +981,7 @@ pub const DeclGen = struct {
|
||||
|
||||
fn renderValue(
|
||||
dg: *DeclGen,
|
||||
writer: *Writer,
|
||||
w: *Writer,
|
||||
val: Value,
|
||||
location: ValueRenderLocation,
|
||||
) Error!void {
|
||||
@ -995,7 +997,7 @@ pub const DeclGen = struct {
|
||||
};
|
||||
|
||||
const ty = val.typeOf(zcu);
|
||||
if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);
|
||||
if (val.isUndefDeep(zcu)) return dg.renderUndefValue(w, ty, location);
|
||||
const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
|
||||
switch (ip.indexToKey(val.toIntern())) {
|
||||
// types, not values
|
||||
@ -1028,8 +1030,8 @@ pub const DeclGen = struct {
|
||||
.empty_tuple => unreachable,
|
||||
.@"unreachable" => unreachable,
|
||||
|
||||
.false => try writer.writeAll("false"),
|
||||
.true => try writer.writeAll("true"),
|
||||
.false => try w.writeAll("false"),
|
||||
.true => try w.writeAll("true"),
|
||||
},
|
||||
.variable,
|
||||
.@"extern",
|
||||
@ -1038,45 +1040,45 @@ pub const DeclGen = struct {
|
||||
.empty_enum_value,
|
||||
=> unreachable, // non-runtime values
|
||||
.int => |int| switch (int.storage) {
|
||||
.u64, .i64, .big_int => try writer.print("{f}", .{try dg.fmtIntLiteral(val, location)}),
|
||||
.u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteral(val, location)}),
|
||||
.lazy_align, .lazy_size => {
|
||||
try writer.writeAll("((");
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.print("){fx})", .{try dg.fmtIntLiteral(
|
||||
try w.writeAll("((");
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.print("){fx})", .{try dg.fmtIntLiteral(
|
||||
try pt.intValue(.usize, val.toUnsignedInt(zcu)),
|
||||
.Other,
|
||||
)});
|
||||
},
|
||||
},
|
||||
.err => |err| try dg.renderErrorName(writer, err.name),
|
||||
.err => |err| try dg.renderErrorName(w, err.name),
|
||||
.error_union => |error_union| switch (ctype.info(ctype_pool)) {
|
||||
.basic => switch (error_union.val) {
|
||||
.err_name => |err_name| try dg.renderErrorName(writer, err_name),
|
||||
.payload => try writer.writeByte('0'),
|
||||
.err_name => |err_name| try dg.renderErrorName(w, err_name),
|
||||
.payload => try w.writeByte('0'),
|
||||
},
|
||||
.pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
|
||||
.aggregate => |aggregate| {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
for (0..aggregate.fields.len) |field_index| {
|
||||
if (field_index > 0) try writer.writeByte(',');
|
||||
if (field_index > 0) try w.writeByte(',');
|
||||
switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
|
||||
.@"error" => switch (error_union.val) {
|
||||
.err_name => |err_name| try dg.renderErrorName(writer, err_name),
|
||||
.payload => try writer.writeByte('0'),
|
||||
.err_name => |err_name| try dg.renderErrorName(w, err_name),
|
||||
.payload => try w.writeByte('0'),
|
||||
},
|
||||
.payload => switch (error_union.val) {
|
||||
.err_name => try dg.renderUndefValue(
|
||||
writer,
|
||||
w,
|
||||
ty.errorUnionPayload(zcu),
|
||||
initializer_type,
|
||||
),
|
||||
.payload => |payload| try dg.renderValue(
|
||||
writer,
|
||||
w,
|
||||
Value.fromInterned(payload),
|
||||
initializer_type,
|
||||
),
|
||||
@ -1084,10 +1086,10 @@ pub const DeclGen = struct {
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
},
|
||||
.enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location),
|
||||
.enum_tag => |enum_tag| try dg.renderValue(w, Value.fromInterned(enum_tag.int), location),
|
||||
.float => {
|
||||
const bits = ty.floatBits(target);
|
||||
const f128_val = val.toFloat(f128, zcu);
|
||||
@ -1114,18 +1116,18 @@ pub const DeclGen = struct {
|
||||
|
||||
var empty = true;
|
||||
if (std.math.isFinite(f128_val)) {
|
||||
try writer.writeAll("zig_make_");
|
||||
try dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeByte('(');
|
||||
try w.writeAll("zig_make_");
|
||||
try dg.renderTypeForBuiltinFnName(w, ty);
|
||||
try w.writeByte('(');
|
||||
switch (bits) {
|
||||
16 => try writer.print("{x}", .{val.toFloat(f16, zcu)}),
|
||||
32 => try writer.print("{x}", .{val.toFloat(f32, zcu)}),
|
||||
64 => try writer.print("{x}", .{val.toFloat(f64, zcu)}),
|
||||
80 => try writer.print("{x}", .{val.toFloat(f80, zcu)}),
|
||||
128 => try writer.print("{x}", .{f128_val}),
|
||||
16 => try w.print("{x}", .{val.toFloat(f16, zcu)}),
|
||||
32 => try w.print("{x}", .{val.toFloat(f32, zcu)}),
|
||||
64 => try w.print("{x}", .{val.toFloat(f64, zcu)}),
|
||||
80 => try w.print("{x}", .{val.toFloat(f80, zcu)}),
|
||||
128 => try w.print("{x}", .{f128_val}),
|
||||
else => unreachable,
|
||||
}
|
||||
try writer.writeAll(", ");
|
||||
try w.writeAll(", ");
|
||||
empty = false;
|
||||
} else {
|
||||
// isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan
|
||||
@ -1149,45 +1151,45 @@ pub const DeclGen = struct {
|
||||
// return dg.fail("Only quiet nans are supported in global variable initializers", .{});
|
||||
}
|
||||
|
||||
try writer.writeAll("zig_");
|
||||
try writer.writeAll(if (location == .StaticInitializer) "init" else "make");
|
||||
try writer.writeAll("_special_");
|
||||
try dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeByte('(');
|
||||
if (std.math.signbit(f128_val)) try writer.writeByte('-');
|
||||
try writer.writeAll(", ");
|
||||
try writer.writeAll(operation);
|
||||
try writer.writeAll(", ");
|
||||
try w.writeAll("zig_");
|
||||
try w.writeAll(if (location == .StaticInitializer) "init" else "make");
|
||||
try w.writeAll("_special_");
|
||||
try dg.renderTypeForBuiltinFnName(w, ty);
|
||||
try w.writeByte('(');
|
||||
if (std.math.signbit(f128_val)) try w.writeByte('-');
|
||||
try w.writeAll(", ");
|
||||
try w.writeAll(operation);
|
||||
try w.writeAll(", ");
|
||||
if (std.math.isNan(f128_val)) switch (bits) {
|
||||
// We only actually need to pass the significand, but it will get
|
||||
// properly masked anyway, so just pass the whole value.
|
||||
16 => try writer.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
|
||||
32 => try writer.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
|
||||
64 => try writer.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
|
||||
80 => try writer.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
|
||||
128 => try writer.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
|
||||
16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
|
||||
32 => try w.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
|
||||
64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
|
||||
80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
|
||||
128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
|
||||
else => unreachable,
|
||||
};
|
||||
try writer.writeAll(", ");
|
||||
try w.writeAll(", ");
|
||||
empty = false;
|
||||
}
|
||||
try writer.print("{fx}", .{try dg.fmtIntLiteral(
|
||||
try w.print("{fx}", .{try dg.fmtIntLiteral(
|
||||
try pt.intValue_big(repr_ty, repr_val_big.toConst()),
|
||||
location,
|
||||
)});
|
||||
if (!empty) try writer.writeByte(')');
|
||||
if (!empty) try w.writeByte(')');
|
||||
},
|
||||
.slice => |slice| {
|
||||
const aggregate = ctype.info(ctype_pool).aggregate;
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
for (0..aggregate.fields.len) |field_index| {
|
||||
if (field_index > 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, Value.fromInterned(
|
||||
if (field_index > 0) try w.writeByte(',');
|
||||
try dg.renderValue(w, Value.fromInterned(
|
||||
switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
|
||||
.ptr => slice.ptr,
|
||||
.len => slice.len,
|
||||
@ -1195,33 +1197,33 @@ pub const DeclGen = struct {
|
||||
},
|
||||
), initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
.ptr => {
|
||||
var arena = std.heap.ArenaAllocator.init(zcu.gpa);
|
||||
defer arena.deinit();
|
||||
const derivation = try val.pointerDerivation(arena.allocator(), pt);
|
||||
try dg.renderPointer(writer, derivation, location);
|
||||
try dg.renderPointer(w, derivation, location);
|
||||
},
|
||||
.opt => |opt| switch (ctype.info(ctype_pool)) {
|
||||
.basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
|
||||
.basic => if (ctype.isBool()) try w.writeAll(switch (opt.val) {
|
||||
.none => "true",
|
||||
else => "false",
|
||||
}) else switch (opt.val) {
|
||||
.none => try writer.writeByte('0'),
|
||||
.none => try w.writeByte('0'),
|
||||
else => |payload| switch (ip.indexToKey(payload)) {
|
||||
.undef => |err_ty| try dg.renderUndefValue(
|
||||
writer,
|
||||
w,
|
||||
.fromInterned(err_ty),
|
||||
location,
|
||||
),
|
||||
.err => |err| try dg.renderErrorName(writer, err.name),
|
||||
.err => |err| try dg.renderErrorName(w, err.name),
|
||||
else => unreachable,
|
||||
},
|
||||
},
|
||||
.pointer => switch (opt.val) {
|
||||
.none => try writer.writeAll("NULL"),
|
||||
else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),
|
||||
.none => try w.writeAll("NULL"),
|
||||
else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location),
|
||||
},
|
||||
.aligned, .array, .vector, .fwd_decl, .function => unreachable,
|
||||
.aggregate => |aggregate| {
|
||||
@ -1230,7 +1232,7 @@ pub const DeclGen = struct {
|
||||
else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
|
||||
.is_null, .payload => {},
|
||||
.ptr, .len => return dg.renderValue(
|
||||
writer,
|
||||
w,
|
||||
Value.fromInterned(payload),
|
||||
location,
|
||||
),
|
||||
@ -1238,48 +1240,48 @@ pub const DeclGen = struct {
|
||||
},
|
||||
}
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
for (0..aggregate.fields.len) |field_index| {
|
||||
if (field_index > 0) try writer.writeByte(',');
|
||||
if (field_index > 0) try w.writeByte(',');
|
||||
switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
|
||||
.is_null => try writer.writeAll(switch (opt.val) {
|
||||
.is_null => try w.writeAll(switch (opt.val) {
|
||||
.none => "true",
|
||||
else => "false",
|
||||
}),
|
||||
.payload => switch (opt.val) {
|
||||
.none => try dg.renderUndefValue(
|
||||
writer,
|
||||
w,
|
||||
ty.optionalChild(zcu),
|
||||
initializer_type,
|
||||
),
|
||||
else => |payload| try dg.renderValue(
|
||||
writer,
|
||||
w,
|
||||
Value.fromInterned(payload),
|
||||
initializer_type,
|
||||
),
|
||||
},
|
||||
.ptr => try writer.writeAll("NULL"),
|
||||
.len => try dg.renderUndefValue(writer, .usize, initializer_type),
|
||||
.ptr => try w.writeAll("NULL"),
|
||||
.len => try dg.renderUndefValue(w, .usize, initializer_type),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
},
|
||||
.aggregate => switch (ip.indexToKey(ty.toIntern())) {
|
||||
.array_type, .vector_type => {
|
||||
if (location == .FunctionArgument) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
const ai = ty.arrayInfo(zcu);
|
||||
if (ai.elem_type.eql(.u8, zcu)) {
|
||||
var literal: StringLiteral = .init(writer, ty.arrayLenIncludingSentinel(zcu));
|
||||
var literal: StringLiteral = .init(w, ty.arrayLenIncludingSentinel(zcu));
|
||||
try literal.start();
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
@ -1296,28 +1298,28 @@ pub const DeclGen = struct {
|
||||
}
|
||||
try literal.end();
|
||||
} else {
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
var index: usize = 0;
|
||||
while (index < ai.len) : (index += 1) {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
if (index != 0) try w.writeByte(',');
|
||||
const elem_val = try val.elemValue(pt, index);
|
||||
try dg.renderValue(writer, elem_val, initializer_type);
|
||||
try dg.renderValue(w, elem_val, initializer_type);
|
||||
}
|
||||
if (ai.sentinel) |s| {
|
||||
if (index != 0) try writer.writeByte(',');
|
||||
try dg.renderValue(writer, s, initializer_type);
|
||||
if (index != 0) try w.writeByte(',');
|
||||
try dg.renderValue(w, s, initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
}
|
||||
},
|
||||
.tuple_type => |tuple| {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
var empty = true;
|
||||
for (0..tuple.types.len) |field_index| {
|
||||
const comptime_val = tuple.values.get(ip)[field_index];
|
||||
@ -1325,7 +1327,7 @@ pub const DeclGen = struct {
|
||||
const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);
|
||||
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
|
||||
|
||||
if (!empty) try writer.writeByte(',');
|
||||
if (!empty) try w.writeByte(',');
|
||||
|
||||
const field_val = Value.fromInterned(
|
||||
switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
|
||||
@ -1337,30 +1339,30 @@ pub const DeclGen = struct {
|
||||
.repeated_elem => |elem| elem,
|
||||
},
|
||||
);
|
||||
try dg.renderValue(writer, field_val, initializer_type);
|
||||
try dg.renderValue(w, field_val, initializer_type);
|
||||
|
||||
empty = false;
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
.struct_type => {
|
||||
const loaded_struct = ip.loadStructType(ty.toIntern());
|
||||
switch (loaded_struct.layout) {
|
||||
.auto, .@"extern" => {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
var field_it = loaded_struct.iterateRuntimeOrder(ip);
|
||||
var need_comma = false;
|
||||
while (field_it.next()) |field_index| {
|
||||
const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
|
||||
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
|
||||
|
||||
if (need_comma) try writer.writeByte(',');
|
||||
if (need_comma) try w.writeByte(',');
|
||||
need_comma = true;
|
||||
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
|
||||
.bytes => |bytes| try pt.intern(.{ .int = .{
|
||||
@ -1370,9 +1372,9 @@ pub const DeclGen = struct {
|
||||
.elems => |elems| elems[field_index],
|
||||
.repeated_elem => |elem| elem,
|
||||
};
|
||||
try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
|
||||
try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
.@"packed" => {
|
||||
const int_info = ty.intInfo(zcu);
|
||||
@ -1390,16 +1392,16 @@ pub const DeclGen = struct {
|
||||
}
|
||||
|
||||
if (eff_num_fields == 0) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderUndefValue(writer, ty, location);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderUndefValue(w, ty, location);
|
||||
try w.writeByte(')');
|
||||
} else if (ty.bitSize(zcu) > 64) {
|
||||
// zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
|
||||
var num_or = eff_num_fields - 1;
|
||||
while (num_or > 0) : (num_or -= 1) {
|
||||
try writer.writeAll("zig_or_");
|
||||
try dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeByte('(');
|
||||
try w.writeAll("zig_or_");
|
||||
try dg.renderTypeForBuiltinFnName(w, ty);
|
||||
try w.writeByte('(');
|
||||
}
|
||||
|
||||
var eff_index: usize = 0;
|
||||
@ -1418,36 +1420,36 @@ pub const DeclGen = struct {
|
||||
};
|
||||
const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
|
||||
if (bit_offset != 0) {
|
||||
try writer.writeAll("zig_shl_");
|
||||
try dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeByte('(');
|
||||
try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
|
||||
try writer.writeAll(", ");
|
||||
try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
|
||||
try writer.writeByte(')');
|
||||
try w.writeAll("zig_shl_");
|
||||
try dg.renderTypeForBuiltinFnName(w, ty);
|
||||
try w.writeByte('(');
|
||||
try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
|
||||
try w.writeAll(", ");
|
||||
try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
|
||||
try w.writeByte(')');
|
||||
} else {
|
||||
try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
|
||||
try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
|
||||
}
|
||||
|
||||
if (needs_closing_paren) try writer.writeByte(')');
|
||||
if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
|
||||
if (needs_closing_paren) try w.writeByte(')');
|
||||
if (eff_index != eff_num_fields - 1) try w.writeAll(", ");
|
||||
|
||||
bit_offset += field_ty.bitSize(zcu);
|
||||
needs_closing_paren = true;
|
||||
eff_index += 1;
|
||||
}
|
||||
} else {
|
||||
try writer.writeByte('(');
|
||||
try w.writeByte('(');
|
||||
// a << a_off | b << b_off | c << c_off
|
||||
var empty = true;
|
||||
for (0..loaded_struct.field_types.len) |field_index| {
|
||||
const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
|
||||
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
|
||||
|
||||
if (!empty) try writer.writeAll(" | ");
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
if (!empty) try w.writeAll(" | ");
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
|
||||
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
|
||||
.bytes => |bytes| try pt.intern(.{ .int = .{
|
||||
@ -1464,24 +1466,24 @@ pub const DeclGen = struct {
|
||||
.{ .signedness = .unsigned, .bits = undefined };
|
||||
switch (field_int_info.signedness) {
|
||||
.signed => {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderValue(writer, Value.fromInterned(field_val), .Other);
|
||||
try writer.writeAll(" & ");
|
||||
try w.writeByte('(');
|
||||
try dg.renderValue(w, Value.fromInterned(field_val), .Other);
|
||||
try w.writeAll(" & ");
|
||||
const field_uint_ty = try pt.intType(.unsigned, field_int_info.bits);
|
||||
try dg.renderValue(writer, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
|
||||
try writer.writeByte(')');
|
||||
try dg.renderValue(w, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
|
||||
try w.writeByte(')');
|
||||
},
|
||||
.unsigned => try dg.renderValue(writer, Value.fromInterned(field_val), .Other),
|
||||
.unsigned => try dg.renderValue(w, Value.fromInterned(field_val), .Other),
|
||||
}
|
||||
if (bit_offset != 0) {
|
||||
try writer.writeAll(" << ");
|
||||
try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
|
||||
try w.writeAll(" << ");
|
||||
try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
|
||||
}
|
||||
|
||||
bit_offset += field_ty.bitSize(zcu);
|
||||
empty = false;
|
||||
}
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte(')');
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1495,11 +1497,11 @@ pub const DeclGen = struct {
|
||||
switch (loaded_union.flagsUnordered(ip).layout) {
|
||||
.@"packed" => {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderType(writer, backing_ty);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderType(w, backing_ty);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
try dg.renderValue(writer, Value.fromInterned(un.val), location);
|
||||
try dg.renderValue(w, Value.fromInterned(un.val), location);
|
||||
},
|
||||
.@"extern" => {
|
||||
if (location == .StaticInitializer) {
|
||||
@ -1507,21 +1509,21 @@ pub const DeclGen = struct {
|
||||
}
|
||||
|
||||
const ptr_ty = try pt.singleConstPtrType(ty);
|
||||
try writer.writeAll("*((");
|
||||
try dg.renderType(writer, ptr_ty);
|
||||
try writer.writeAll(")(");
|
||||
try dg.renderType(writer, backing_ty);
|
||||
try writer.writeAll("){");
|
||||
try dg.renderValue(writer, Value.fromInterned(un.val), location);
|
||||
try writer.writeAll("})");
|
||||
try w.writeAll("*((");
|
||||
try dg.renderType(w, ptr_ty);
|
||||
try w.writeAll(")(");
|
||||
try dg.renderType(w, backing_ty);
|
||||
try w.writeAll("){");
|
||||
try dg.renderValue(w, Value.fromInterned(un.val), location);
|
||||
try w.writeAll("})");
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
} else {
|
||||
if (!location.isInitializer()) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
|
||||
const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
|
||||
@ -1530,57 +1532,57 @@ pub const DeclGen = struct {
|
||||
if (loaded_union.flagsUnordered(ip).layout == .@"packed") {
|
||||
if (field_ty.hasRuntimeBits(zcu)) {
|
||||
if (field_ty.isPtrAtRuntime(zcu)) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
} else if (field_ty.zigTypeTag(zcu) == .float) {
|
||||
try writer.writeByte('(');
|
||||
try dg.renderCType(writer, ctype);
|
||||
try writer.writeByte(')');
|
||||
try w.writeByte('(');
|
||||
try dg.renderCType(w, ctype);
|
||||
try w.writeByte(')');
|
||||
}
|
||||
try dg.renderValue(writer, Value.fromInterned(un.val), location);
|
||||
} else try writer.writeByte('0');
|
||||
try dg.renderValue(w, Value.fromInterned(un.val), location);
|
||||
} else try w.writeByte('0');
|
||||
return;
|
||||
}
|
||||
|
||||
const has_tag = loaded_union.hasTag(ip);
|
||||
if (has_tag) try writer.writeByte('{');
|
||||
if (has_tag) try w.writeByte('{');
|
||||
const aggregate = ctype.info(ctype_pool).aggregate;
|
||||
for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
|
||||
if (outer_field_index > 0) try writer.writeByte(',');
|
||||
if (outer_field_index > 0) try w.writeByte(',');
|
||||
switch (if (has_tag)
|
||||
aggregate.fields.at(outer_field_index, ctype_pool).name.index
|
||||
else
|
||||
.payload) {
|
||||
.tag => try dg.renderValue(
|
||||
writer,
|
||||
w,
|
||||
Value.fromInterned(un.tag),
|
||||
initializer_type,
|
||||
),
|
||||
.payload => {
|
||||
try writer.writeByte('{');
|
||||
try w.writeByte('{');
|
||||
if (field_ty.hasRuntimeBits(zcu)) {
|
||||
try writer.print(" .{f } = ", .{fmtIdent(field_name.toSlice(ip))});
|
||||
try w.print(" .{f } = ", .{fmtIdent(field_name.toSlice(ip))});
|
||||
try dg.renderValue(
|
||||
writer,
|
||||
w,
|
||||
Value.fromInterned(un.val),
|
||||
initializer_type,
|
||||
);
|
||||
try writer.writeByte(' ');
|
||||
try w.writeByte(' ');
|
||||
} else for (0..loaded_union.field_types.len) |inner_field_index| {
|
||||
const inner_field_ty: Type = .fromInterned(
|
||||
loaded_union.field_types.get(ip)[inner_field_index],
|
||||
);
|
||||
if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
|
||||
try dg.renderUndefValue(writer, inner_field_ty, initializer_type);
|
||||
try dg.renderUndefValue(w, inner_field_ty, initializer_type);
|
||||
break;
|
||||
}
|
||||
try writer.writeByte('}');
|
||||
try w.writeByte('}');
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
if (has_tag) try writer.writeByte('}');
|
||||
if (has_tag) try w.writeByte('}');
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -2999,18 +3001,20 @@ pub fn generate(
|
||||
.pass = .{ .nav = func.owner_nav },
|
||||
.is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
|
||||
.expected_block = null,
|
||||
.fwd_decl = .init(gpa),
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = .empty,
|
||||
.scratch = .empty,
|
||||
.uavs = .empty,
|
||||
},
|
||||
.code = .init(gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.code_header = undefined,
|
||||
.code = undefined,
|
||||
.indent_counter = 0,
|
||||
},
|
||||
.lazy_fns = .empty,
|
||||
};
|
||||
defer {
|
||||
function.object.code.deinit();
|
||||
function.object.code_header.init(gpa);
|
||||
function.object.code.init(gpa);
|
||||
function.object.dg.fwd_decl.deinit();
|
||||
function.object.dg.ctype_pool.deinit(gpa);
|
||||
function.object.dg.scratch.deinit(gpa);
|
||||
@ -3018,7 +3022,9 @@ pub fn generate(
|
||||
function.deinit();
|
||||
}
|
||||
try function.object.dg.ctype_pool.init(gpa);
|
||||
function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
|
||||
function.object.dg.fwd_decl.init(gpa);
|
||||
function.object.code_header.init(gpa);
|
||||
function.object.code.init(gpa);
|
||||
|
||||
genFunc(&function) catch |err| switch (err) {
|
||||
error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),
|
||||
@ -3034,6 +3040,7 @@ pub fn generate(
|
||||
};
|
||||
errdefer mir.deinit(gpa);
|
||||
mir.uavs = function.object.dg.uavs.move();
|
||||
mir.code_header = try function.object.code_header.toOwnedSlice();
|
||||
mir.code = try function.object.code.toOwnedSlice();
|
||||
mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();
|
||||
mir.ctype_pool = function.object.dg.ctype_pool.move();
|
||||
@ -3041,7 +3048,7 @@ pub fn generate(
|
||||
return mir;
|
||||
}
|
||||
|
||||
fn genFunc(f: *Function) !void {
|
||||
pub fn genFunc(f: *Function) Error!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -4033,7 +4040,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
|
||||
try f.writeCValueDeref(w, ret_val)
|
||||
else
|
||||
try f.writeCValue(w, ret_val, .Other);
|
||||
try w.writeAll(";\n");
|
||||
try w.write(";\n");
|
||||
if (is_array) {
|
||||
try freeLocal(f, inst, ret_val.new_local, null);
|
||||
}
|
||||
@ -4347,7 +4354,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
|
||||
try f.writeCValue(w, rhs, .FunctionArgument);
|
||||
if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
|
||||
try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
|
||||
try w.writeAll(");\n");
|
||||
try w.writeAll(");");
|
||||
try f.object.newline();
|
||||
try v.end(f, inst, w);
|
||||
|
||||
return local;
|
||||
@ -4884,8 +4892,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
|
||||
const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
|
||||
const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
|
||||
const writer = f.object.writer();
|
||||
try writer.print("/* inline:{f} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
|
||||
const w = &f.object.code.buffered_writer;
|
||||
try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
|
||||
try f.object.newline();
|
||||
return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));
|
||||
}
|
||||
|
||||
@ -7415,30 +7424,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const inst_ty = unwrapped.result_ty;
|
||||
const elem_ty = inst_ty.childType(zcu);
|
||||
|
||||
const writer = &f.object.code.buffered_writer;
|
||||
const w = &f.object.code.buffered_writer;
|
||||
const local = try f.allocLocal(inst, inst_ty);
|
||||
try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands
|
||||
for (mask, 0..) |mask_elem, out_idx| {
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeByte('[');
|
||||
try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other);
|
||||
try writer.writeAll("] = ");
|
||||
try f.writeCValue(w, local, .Other);
|
||||
try w.writeByte('[');
|
||||
try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
|
||||
try w.writeAll("] = ");
|
||||
switch (mask_elem.unwrap()) {
|
||||
.a_elem => |src_idx| {
|
||||
try f.writeCValue(writer, operand_a, .Other);
|
||||
try writer.writeByte('[');
|
||||
try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
|
||||
try writer.writeByte(']');
|
||||
try f.writeCValue(w, operand_a, .Other);
|
||||
try w.writeByte('[');
|
||||
try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
|
||||
try w.writeByte(']');
|
||||
},
|
||||
.b_elem => |src_idx| {
|
||||
try f.writeCValue(writer, operand_b, .Other);
|
||||
try writer.writeByte('[');
|
||||
try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
|
||||
try writer.writeByte(']');
|
||||
try f.writeCValue(w, operand_b, .Other);
|
||||
try w.writeByte('[');
|
||||
try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
|
||||
try w.writeByte(']');
|
||||
},
|
||||
.undef => try f.object.dg.renderUndefValue(writer, elem_ty, .Other),
|
||||
.undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other),
|
||||
}
|
||||
try writer.writeAll(";\n");
|
||||
try w.writeByte(';');
|
||||
try f.object.newline();
|
||||
}
|
||||
|
||||
return local;
|
||||
@ -7889,12 +7899,13 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
|
||||
fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
||||
const writer = f.object.writer();
|
||||
const w = &f.object.code.buffered_writer;
|
||||
const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeAll(" = ");
|
||||
try f.object.dg.renderNav(writer, ty_nav.nav, .Other);
|
||||
try writer.writeAll(";\n");
|
||||
try f.writeCValue(w, local, .Other);
|
||||
try w.writeAll(" = ");
|
||||
try f.object.dg.renderNav(w, ty_nav.nav, .Other);
|
||||
try w.writeByte(';');
|
||||
try f.object.newline();
|
||||
return local;
|
||||
}
|
||||
|
||||
@ -8480,19 +8491,19 @@ const Assignment = struct {
|
||||
const Vectorize = struct {
|
||||
index: CValue = .none,
|
||||
|
||||
pub fn start(f: *Function, inst: Air.Inst.Index, writer: *Writer, ty: Type) !Vectorize {
|
||||
pub fn start(f: *Function, inst: Air.Inst.Index, w: *Writer, ty: Type) !Vectorize {
|
||||
const pt = f.object.dg.pt;
|
||||
const zcu = pt.zcu;
|
||||
return if (ty.zigTypeTag(zcu) == .vector) index: {
|
||||
const local = try f.allocLocal(inst, .usize);
|
||||
|
||||
try writer.writeAll("for (");
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
|
||||
try w.writeAll("for (");
|
||||
try f.writeCValue(w, local, .Other);
|
||||
try w.print(" = {fd}; ", .{try f.fmtIntLiteral(.zero_usize)});
|
||||
try f.writeCValue(w, local, .Other);
|
||||
try w.print(" < {fd}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
|
||||
try f.writeCValue(w, local, .Other);
|
||||
try w.print(" += {fd}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
|
||||
f.object.indent();
|
||||
try f.object.newline();
|
||||
|
||||
|
||||
335
src/link/C.zig
335
src/link/C.zig
@ -25,34 +25,34 @@ base: link.File,
|
||||
/// This linker backend does not try to incrementally link output C source code.
|
||||
/// Instead, it tracks all declarations in this table, and iterates over it
|
||||
/// in the flush function, stitching pre-rendered pieces of C code together.
|
||||
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock) = .empty,
|
||||
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock),
|
||||
/// All the string bytes of rendered C code, all squished into one array.
|
||||
/// While in progress, a separate buffer is used, and then when finished, the
|
||||
/// buffer is copied into this one.
|
||||
string_bytes: std.ArrayListUnmanaged(u8) = .empty,
|
||||
string_bytes: std.ArrayListUnmanaged(u8),
|
||||
/// Tracks all the anonymous decls that are used by all the decls so they can
|
||||
/// be rendered during flush().
|
||||
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock) = .empty,
|
||||
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock),
|
||||
/// Sparse set of uavs that are overaligned. Underaligned anon decls are
|
||||
/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
|
||||
/// the keys of `uavs`.
|
||||
aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty,
|
||||
aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
|
||||
|
||||
exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock) = .empty,
|
||||
exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .empty,
|
||||
exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock),
|
||||
exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock),
|
||||
|
||||
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
|
||||
/// one with every call.
|
||||
fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
fwd_decl_buf: []u8,
|
||||
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
|
||||
/// one with every call.
|
||||
code_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
code_header_buf: []u8,
|
||||
/// Optimization, `updateDecl` reuses this buffer rather than creating a new
|
||||
/// one with every call.
|
||||
code_buf: []u8,
|
||||
/// Optimization, `flush` reuses this buffer rather than creating a new
|
||||
/// one with every call.
|
||||
lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
/// Optimization, `flush` reuses this buffer rather than creating a new
|
||||
/// one with every call.
|
||||
lazy_code_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
scratch_buf: []u32,
|
||||
|
||||
/// A reference into `string_bytes`.
|
||||
const String = extern struct {
|
||||
@ -67,11 +67,11 @@ const String = extern struct {
|
||||
|
||||
/// Per-declaration data.
|
||||
pub const AvBlock = struct {
|
||||
code: String = String.empty,
|
||||
fwd_decl: String = String.empty,
|
||||
fwd_decl: String = .empty,
|
||||
code: String = .empty,
|
||||
/// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
|
||||
/// over each `Decl` and generate the definition for each used `CType` once.
|
||||
ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
|
||||
ctype_pool: codegen.CType.Pool = .empty,
|
||||
/// May contain string references to ctype_pool
|
||||
lazy_fns: codegen.LazyFnMap = .{},
|
||||
|
||||
@ -84,20 +84,21 @@ pub const AvBlock = struct {
|
||||
|
||||
/// Per-exported-symbol data.
|
||||
pub const ExportedBlock = struct {
|
||||
fwd_decl: String = String.empty,
|
||||
fwd_decl: String = .empty,
|
||||
};
|
||||
|
||||
pub fn getString(this: C, s: String) []const u8 {
|
||||
return this.string_bytes.items[s.start..][0..s.len];
|
||||
}
|
||||
|
||||
pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
|
||||
pub fn addString(this: *C, writers: []const *std.io.AllocatingWriter) Allocator.Error!String {
|
||||
const comp = this.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
try this.string_bytes.appendSlice(gpa, s);
|
||||
const start = this.string_bytes.items.len;
|
||||
for (writers) |writer| try this.string_bytes.appendSlice(gpa, writer.getWritten());
|
||||
return .{
|
||||
.start = @intCast(this.string_bytes.items.len - s.len),
|
||||
.len = @intCast(s.len),
|
||||
.start = @intCast(start),
|
||||
.len = @intCast(this.string_bytes.items.len - start),
|
||||
};
|
||||
}
|
||||
|
||||
@ -147,6 +148,16 @@ pub fn createEmpty(
|
||||
.file = file,
|
||||
.build_id = options.build_id,
|
||||
},
|
||||
.navs = .empty,
|
||||
.string_bytes = .empty,
|
||||
.uavs = .empty,
|
||||
.aligned_uavs = .empty,
|
||||
.exported_navs = .empty,
|
||||
.exported_uavs = .empty,
|
||||
.fwd_decl_buf = &.{},
|
||||
.code_header_buf = &.{},
|
||||
.code_buf = &.{},
|
||||
.scratch_buf = &.{},
|
||||
};
|
||||
|
||||
return c_file;
|
||||
@ -170,10 +181,10 @@ pub fn deinit(self: *C) void {
|
||||
self.exported_uavs.deinit(gpa);
|
||||
|
||||
self.string_bytes.deinit(gpa);
|
||||
self.fwd_decl_buf.deinit(gpa);
|
||||
self.code_buf.deinit(gpa);
|
||||
self.lazy_fwd_decl_buf.deinit(gpa);
|
||||
self.lazy_code_buf.deinit(gpa);
|
||||
gpa.free(self.fwd_decl_buf);
|
||||
gpa.free(self.code_header_buf);
|
||||
gpa.free(self.code_buf);
|
||||
gpa.free(self.scratch_buf);
|
||||
}
|
||||
|
||||
pub fn updateFunc(
|
||||
@ -194,20 +205,15 @@ pub fn updateFunc(
|
||||
.ctype_pool = mir.c.ctype_pool.move(),
|
||||
.lazy_fns = mir.c.lazy_fns.move(),
|
||||
};
|
||||
gop.value_ptr.code = try self.addString(mir.c.code);
|
||||
gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl);
|
||||
gop.value_ptr.fwd_decl = try self.addString(&.{&function.object.dg.fwd_decl});
|
||||
gop.value_ptr.code = try self.addString(&.{ &function.object.code_header, &function.object.code });
|
||||
try self.addUavsFromCodegen(&mir.c.uavs);
|
||||
}
|
||||
|
||||
fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
|
||||
fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) link.File.FlushError!void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
const uav = self.uavs.keys()[i];
|
||||
|
||||
const fwd_decl = &self.fwd_decl_buf;
|
||||
const code = &self.code_buf;
|
||||
fwd_decl.clearRetainingCapacity();
|
||||
code.clearRetainingCapacity();
|
||||
|
||||
var object: codegen.Object = .{
|
||||
.dg = .{
|
||||
.gpa = gpa,
|
||||
@ -217,21 +223,24 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
|
||||
.pass = .{ .uav = uav },
|
||||
.is_naked_fn = false,
|
||||
.expected_block = null,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.ctype_pool = codegen.CType.Pool.empty,
|
||||
.scratch = .{},
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = .empty,
|
||||
.scratch = .initBuffer(self.scratch_buf),
|
||||
.uavs = .empty,
|
||||
},
|
||||
.code = code.toManaged(gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.code_header = undefined,
|
||||
.code = undefined,
|
||||
.indent_counter = 0,
|
||||
};
|
||||
object.indent_writer = .{ .underlying_writer = object.code.writer() };
|
||||
object.dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
|
||||
object.code.initOwnedSlice(gpa, self.code_buf);
|
||||
defer {
|
||||
object.dg.uavs.deinit(gpa);
|
||||
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
|
||||
object.dg.ctype_pool.deinit(object.dg.gpa);
|
||||
object.dg.scratch.deinit(gpa);
|
||||
code.* = object.code.moveToUnmanaged();
|
||||
|
||||
self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
|
||||
self.code_buf = object.code.toArrayList().allocatedSlice();
|
||||
self.scratch_buf = object.dg.scratch.allocatedSlice();
|
||||
}
|
||||
try object.dg.ctype_pool.init(gpa);
|
||||
|
||||
@ -243,15 +252,15 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
|
||||
//try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
|
||||
//return;
|
||||
},
|
||||
else => |e| return e,
|
||||
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
try self.addUavsFromCodegen(&object.dg.uavs);
|
||||
|
||||
object.dg.ctype_pool.freeUnusedCapacity(gpa);
|
||||
self.uavs.values()[i] = .{
|
||||
.code = try self.addString(object.code.items),
|
||||
.fwd_decl = try self.addString(object.dg.fwd_decl.items),
|
||||
.fwd_decl = try self.addString(&.{&object.dg.fwd_decl}),
|
||||
.code = try self.addString(&.{&object.code}),
|
||||
.ctype_pool = object.dg.ctype_pool.move(),
|
||||
};
|
||||
}
|
||||
@ -277,12 +286,8 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
|
||||
errdefer _ = self.navs.pop();
|
||||
if (!gop.found_existing) gop.value_ptr.* = .{};
|
||||
const ctype_pool = &gop.value_ptr.ctype_pool;
|
||||
const fwd_decl = &self.fwd_decl_buf;
|
||||
const code = &self.code_buf;
|
||||
try ctype_pool.init(gpa);
|
||||
ctype_pool.clearRetainingCapacity();
|
||||
fwd_decl.clearRetainingCapacity();
|
||||
code.clearRetainingCapacity();
|
||||
|
||||
var object: codegen.Object = .{
|
||||
.dg = .{
|
||||
@ -293,22 +298,25 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
|
||||
.pass = .{ .nav = nav_index },
|
||||
.is_naked_fn = false,
|
||||
.expected_block = null,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = ctype_pool.*,
|
||||
.scratch = .{},
|
||||
.scratch = .initBuffer(self.scratch_buf),
|
||||
.uavs = .empty,
|
||||
},
|
||||
.code = code.toManaged(gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.code_header = undefined,
|
||||
.code = undefined,
|
||||
.indent_counter = 0,
|
||||
};
|
||||
object.indent_writer = .{ .underlying_writer = object.code.writer() };
|
||||
object.dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
|
||||
object.code.initOwnedSlice(gpa, self.code_buf);
|
||||
defer {
|
||||
object.dg.uavs.deinit(gpa);
|
||||
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
|
||||
ctype_pool.* = object.dg.ctype_pool.move();
|
||||
ctype_pool.freeUnusedCapacity(gpa);
|
||||
object.dg.scratch.deinit(gpa);
|
||||
code.* = object.code.moveToUnmanaged();
|
||||
|
||||
self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
|
||||
self.code_buf = object.code.toArrayList().allocatedSlice();
|
||||
self.scratch_buf = object.dg.scratch.allocatedSlice();
|
||||
}
|
||||
|
||||
codegen.genDecl(&object) catch |err| switch (err) {
|
||||
@ -316,10 +324,10 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
|
||||
error.CodegenFail => return,
|
||||
error.OutOfMemory => |e| return e,
|
||||
},
|
||||
else => |e| return e,
|
||||
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
gop.value_ptr.code = try self.addString(object.code.items);
|
||||
gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
|
||||
gop.value_ptr.fwd_decl = try self.addString(&.{&object.dg.fwd_decl});
|
||||
gop.value_ptr.code = try self.addString(&.{&object.code});
|
||||
try self.addUavsFromCodegen(&object.dg.uavs);
|
||||
}
|
||||
|
||||
@ -331,19 +339,14 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn
|
||||
_ = ti_id;
|
||||
}
|
||||
|
||||
fn abiDefines(self: *C, target: *const std.Target) !std.ArrayList(u8) {
|
||||
const gpa = self.base.comp.gpa;
|
||||
var defines = std.ArrayList(u8).init(gpa);
|
||||
errdefer defines.deinit();
|
||||
const writer = defines.writer();
|
||||
fn abiDefines(bw: *std.io.BufferedWriter, target: std.Target) !void {
|
||||
switch (target.abi) {
|
||||
.msvc, .itanium => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
|
||||
.msvc, .itanium => try bw.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
|
||||
else => {},
|
||||
}
|
||||
try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
|
||||
try bw.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
|
||||
target.cMaxIntAlignment(),
|
||||
});
|
||||
return defines;
|
||||
}
|
||||
|
||||
pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
|
||||
@ -374,37 +377,49 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
|
||||
// emit-h is in `flushEmitH` below.
|
||||
|
||||
var f: Flush = .{
|
||||
.ctype_pool = codegen.CType.Pool.empty,
|
||||
.lazy_ctype_pool = codegen.CType.Pool.empty,
|
||||
.ctype_pool = .empty,
|
||||
.ctype_global_from_decl_map = .empty,
|
||||
.ctypes = .empty,
|
||||
|
||||
.lazy_ctype_pool = .empty,
|
||||
.lazy_fns = .empty,
|
||||
.lazy_fwd_decl = .empty,
|
||||
.lazy_code = .empty,
|
||||
|
||||
.all_buffers = .empty,
|
||||
.file_size = 0,
|
||||
};
|
||||
defer f.deinit(gpa);
|
||||
|
||||
const abi_defines = try self.abiDefines(zcu.getTarget());
|
||||
defer abi_defines.deinit();
|
||||
var abi_defines_aw: std.io.AllocatingWriter = undefined;
|
||||
abi_defines_aw.init(gpa);
|
||||
defer abi_defines_aw.deinit();
|
||||
abiDefines(&abi_defines_aw.buffered_writer, zcu.getTarget()) catch |err| switch (err) {
|
||||
error.WriteFailed => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
// Covers defines, zig.h, ctypes, asm, lazy fwd.
|
||||
try f.all_buffers.ensureUnusedCapacity(gpa, 5);
|
||||
|
||||
f.appendBufAssumeCapacity(abi_defines.items);
|
||||
f.appendBufAssumeCapacity(abi_defines_aw.getWritten());
|
||||
f.appendBufAssumeCapacity(zig_h);
|
||||
|
||||
const ctypes_index = f.all_buffers.items.len;
|
||||
f.all_buffers.items.len += 1;
|
||||
|
||||
{
|
||||
var asm_buf = f.asm_buf.toManaged(gpa);
|
||||
defer f.asm_buf = asm_buf.moveToUnmanaged();
|
||||
try codegen.genGlobalAsm(zcu, asm_buf.writer());
|
||||
f.appendBufAssumeCapacity(asm_buf.items);
|
||||
}
|
||||
var asm_aw: std.io.AllocatingWriter = undefined;
|
||||
asm_aw.init(gpa);
|
||||
defer asm_aw.deinit();
|
||||
codegen.genGlobalAsm(zcu, &asm_aw.buffered_writer) catch |err| switch (err) {
|
||||
error.WriteFailed => return error.OutOfMemory,
|
||||
};
|
||||
f.appendBufAssumeCapacity(asm_aw.getWritten());
|
||||
|
||||
const lazy_index = f.all_buffers.items.len;
|
||||
f.all_buffers.items.len += 1;
|
||||
|
||||
self.lazy_fwd_decl_buf.clearRetainingCapacity();
|
||||
self.lazy_code_buf.clearRetainingCapacity();
|
||||
try f.lazy_ctype_pool.init(gpa);
|
||||
try self.flushErrDecls(pt, &f.lazy_ctype_pool);
|
||||
try self.flushErrDecls(pt, &f);
|
||||
|
||||
// Unlike other backends, the .c code we are emitting has order-dependent decls.
|
||||
// `CType`s, forward decls, and non-functions first.
|
||||
@ -462,22 +477,15 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
|
||||
}
|
||||
}
|
||||
|
||||
f.all_buffers.items[ctypes_index] = .{
|
||||
.base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
|
||||
.len = f.ctypes_buf.items.len,
|
||||
};
|
||||
f.file_size += f.ctypes_buf.items.len;
|
||||
f.all_buffers.items[ctypes_index] = f.ctypes.items;
|
||||
f.file_size += f.ctypes.items.len;
|
||||
|
||||
const lazy_fwd_decl_len = self.lazy_fwd_decl_buf.items.len;
|
||||
f.all_buffers.items[lazy_index] = .{
|
||||
.base = if (lazy_fwd_decl_len > 0) self.lazy_fwd_decl_buf.items.ptr else "",
|
||||
.len = lazy_fwd_decl_len,
|
||||
};
|
||||
f.file_size += lazy_fwd_decl_len;
|
||||
f.all_buffers.items[lazy_index] = f.lazy_fwd_decl.items;
|
||||
f.file_size += f.lazy_fwd_decl.items.len;
|
||||
|
||||
// Now the code.
|
||||
try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);
|
||||
f.appendBufAssumeCapacity(self.lazy_code_buf.items);
|
||||
f.appendBufAssumeCapacity(f.lazy_code.items);
|
||||
for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
|
||||
if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
|
||||
.@"extern" => .zig_extern,
|
||||
@ -493,31 +501,35 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
|
||||
|
||||
const file = self.base.file.?;
|
||||
file.setEndPos(f.file_size) catch |err| return diags.fail("failed to allocate file: {s}", .{@errorName(err)});
|
||||
file.pwritevAll(f.all_buffers.items, 0) catch |err| return diags.fail("failed to write to '{'}': {s}", .{
|
||||
self.base.emit, @errorName(err),
|
||||
});
|
||||
var fw = file.writer();
|
||||
var bw = fw.interface().unbuffered();
|
||||
bw.writeVecAll(f.all_buffers.items) catch |err| switch (err) {
|
||||
error.WriteFailed => return diags.fail("failed to write to '{f'}': {s}", .{
|
||||
self.base.emit, @errorName(fw.err.?),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const Flush = struct {
|
||||
ctype_pool: codegen.CType.Pool,
|
||||
ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .empty,
|
||||
ctypes_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType),
|
||||
ctypes: std.ArrayListUnmanaged(u8),
|
||||
|
||||
lazy_ctype_pool: codegen.CType.Pool,
|
||||
lazy_fns: LazyFns = .{},
|
||||
|
||||
asm_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||
lazy_fns: LazyFns,
|
||||
lazy_fwd_decl: std.ArrayListUnmanaged(u8),
|
||||
lazy_code: std.ArrayListUnmanaged(u8),
|
||||
|
||||
/// We collect a list of buffers to write, and write them all at once with pwritev 😎
|
||||
all_buffers: std.ArrayListUnmanaged(std.posix.iovec_const) = .empty,
|
||||
all_buffers: std.ArrayListUnmanaged([]const u8),
|
||||
/// Keeps track of the total bytes of `all_buffers`.
|
||||
file_size: u64 = 0,
|
||||
file_size: u64,
|
||||
|
||||
const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
|
||||
|
||||
fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
|
||||
if (buf.len == 0) return;
|
||||
f.all_buffers.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });
|
||||
f.all_buffers.appendAssumeCapacity(buf);
|
||||
f.file_size += buf.len;
|
||||
}
|
||||
|
||||
@ -532,14 +544,15 @@ const Flush = struct {
|
||||
}
|
||||
|
||||
fn deinit(f: *Flush, gpa: Allocator) void {
|
||||
f.all_buffers.deinit(gpa);
|
||||
f.asm_buf.deinit(gpa);
|
||||
f.lazy_fns.deinit(gpa);
|
||||
f.lazy_ctype_pool.deinit(gpa);
|
||||
f.ctypes_buf.deinit(gpa);
|
||||
f.ctype_pool.deinit(gpa);
|
||||
assert(f.ctype_global_from_decl_map.items.len == 0);
|
||||
f.ctype_global_from_decl_map.deinit(gpa);
|
||||
f.ctype_pool.deinit(gpa);
|
||||
f.ctypes.deinit(gpa);
|
||||
f.lazy_ctype_pool.deinit(gpa);
|
||||
f.lazy_fns.deinit(gpa);
|
||||
f.lazy_fwd_decl.deinit(gpa);
|
||||
f.lazy_code.deinit(gpa);
|
||||
f.all_buffers.deinit(gpa);
|
||||
}
|
||||
};
|
||||
|
||||
@ -562,9 +575,9 @@ fn flushCTypes(
|
||||
try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
|
||||
defer global_from_decl_map.clearRetainingCapacity();
|
||||
|
||||
var ctypes_buf = f.ctypes_buf.toManaged(gpa);
|
||||
defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
|
||||
const writer = ctypes_buf.writer();
|
||||
var ctypes_aw: std.io.AllocatingWriter = undefined;
|
||||
const ctypes_bw = ctypes_aw.fromArrayList(gpa, &f.ctypes);
|
||||
defer f.ctypes = ctypes_aw.toArrayList();
|
||||
|
||||
for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
|
||||
const PoolAdapter = struct {
|
||||
@ -591,26 +604,25 @@ fn flushCTypes(
|
||||
PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
|
||||
);
|
||||
global_from_decl_map.appendAssumeCapacity(global_ctype);
|
||||
try codegen.genTypeDecl(
|
||||
codegen.genTypeDecl(
|
||||
zcu,
|
||||
writer,
|
||||
ctypes_bw,
|
||||
global_ctype_pool,
|
||||
global_ctype,
|
||||
pass,
|
||||
decl_ctype_pool,
|
||||
decl_ctype,
|
||||
found_existing,
|
||||
);
|
||||
) catch |err| switch (err) {
|
||||
error.WriteFailed => return error.OutOfMemory,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) FlushDeclError!void {
|
||||
fn flushErrDecls(self: *C, pt: Zcu.PerThread, f: *Flush) FlushDeclError!void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
const fwd_decl = &self.lazy_fwd_decl_buf;
|
||||
const code = &self.lazy_code_buf;
|
||||
|
||||
var object = codegen.Object{
|
||||
var object: codegen.Object = .{
|
||||
.dg = .{
|
||||
.gpa = gpa,
|
||||
.pt = pt,
|
||||
@ -619,27 +631,30 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F
|
||||
.pass = .flush,
|
||||
.is_naked_fn = false,
|
||||
.expected_block = null,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.ctype_pool = ctype_pool.*,
|
||||
.scratch = .{},
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = f.lazy_ctype_pool,
|
||||
.scratch = .initBuffer(self.scratch_buf),
|
||||
.uavs = .empty,
|
||||
},
|
||||
.code = code.toManaged(gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.code_header = undefined,
|
||||
.code = undefined,
|
||||
.indent_counter = 0,
|
||||
};
|
||||
object.indent_writer = .{ .underlying_writer = object.code.writer() };
|
||||
_ = object.dg.fwd_decl.fromArrayList(gpa, &f.lazy_fwd_decl);
|
||||
_ = object.code.fromArrayList(gpa, &f.lazy_code);
|
||||
defer {
|
||||
object.dg.uavs.deinit(gpa);
|
||||
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
|
||||
ctype_pool.* = object.dg.ctype_pool.move();
|
||||
ctype_pool.freeUnusedCapacity(gpa);
|
||||
object.dg.scratch.deinit(gpa);
|
||||
code.* = object.code.moveToUnmanaged();
|
||||
f.lazy_ctype_pool = object.dg.ctype_pool.move();
|
||||
f.lazy_ctype_pool.freeUnusedCapacity(gpa);
|
||||
|
||||
f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
|
||||
f.lazy_code = object.code.toArrayList();
|
||||
self.scratch_buf = object.dg.scratch.allocatedSlice();
|
||||
}
|
||||
|
||||
codegen.genErrDecls(&object) catch |err| switch (err) {
|
||||
error.AnalysisFail => unreachable,
|
||||
else => |e| return e,
|
||||
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
try self.addUavsFromCodegen(&object.dg.uavs);
|
||||
@ -649,16 +664,13 @@ fn flushLazyFn(
|
||||
self: *C,
|
||||
pt: Zcu.PerThread,
|
||||
mod: *Module,
|
||||
ctype_pool: *codegen.CType.Pool,
|
||||
f: *Flush,
|
||||
lazy_ctype_pool: *const codegen.CType.Pool,
|
||||
lazy_fn: codegen.LazyFnMap.Entry,
|
||||
) FlushDeclError!void {
|
||||
const gpa = self.base.comp.gpa;
|
||||
|
||||
const fwd_decl = &self.lazy_fwd_decl_buf;
|
||||
const code = &self.lazy_code_buf;
|
||||
|
||||
var object = codegen.Object{
|
||||
var object: codegen.Object = .{
|
||||
.dg = .{
|
||||
.gpa = gpa,
|
||||
.pt = pt,
|
||||
@ -667,29 +679,32 @@ fn flushLazyFn(
|
||||
.pass = .flush,
|
||||
.is_naked_fn = false,
|
||||
.expected_block = null,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.ctype_pool = ctype_pool.*,
|
||||
.scratch = .{},
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = f.lazy_ctype_pool,
|
||||
.scratch = .initBuffer(self.scratch_buf),
|
||||
.uavs = .empty,
|
||||
},
|
||||
.code = code.toManaged(gpa),
|
||||
.indent_writer = undefined, // set later so we can get a pointer to object.code
|
||||
.code_header = undefined,
|
||||
.code = undefined,
|
||||
.indent_counter = 0,
|
||||
};
|
||||
object.indent_writer = .{ .underlying_writer = object.code.writer() };
|
||||
_ = object.dg.fwd_decl.fromArrayList(gpa, &f.lazy_fwd_decl);
|
||||
_ = object.code.fromArrayList(gpa, &f.lazy_code);
|
||||
defer {
|
||||
// If this assert trips just handle the anon_decl_deps the same as
|
||||
// `updateFunc()` does.
|
||||
assert(object.dg.uavs.count() == 0);
|
||||
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
|
||||
ctype_pool.* = object.dg.ctype_pool.move();
|
||||
ctype_pool.freeUnusedCapacity(gpa);
|
||||
object.dg.scratch.deinit(gpa);
|
||||
code.* = object.code.moveToUnmanaged();
|
||||
f.lazy_ctype_pool = object.dg.ctype_pool.move();
|
||||
f.lazy_ctype_pool.freeUnusedCapacity(gpa);
|
||||
|
||||
f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
|
||||
f.lazy_code = object.code.toArrayList();
|
||||
self.scratch_buf = object.dg.scratch.allocatedSlice();
|
||||
}
|
||||
|
||||
codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
|
||||
error.AnalysisFail => unreachable,
|
||||
else => |e| return e,
|
||||
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
}
|
||||
|
||||
@ -709,7 +724,7 @@ fn flushLazyFns(
|
||||
const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
|
||||
if (gop.found_existing) continue;
|
||||
gop.value_ptr.* = {};
|
||||
try self.flushLazyFn(pt, mod, &f.lazy_ctype_pool, lazy_ctype_pool, entry);
|
||||
try self.flushLazyFn(pt, mod, f, lazy_ctype_pool, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,8 +817,6 @@ pub fn updateExports(
|
||||
},
|
||||
};
|
||||
const ctype_pool = &decl_block.ctype_pool;
|
||||
const fwd_decl = &self.fwd_decl_buf;
|
||||
fwd_decl.clearRetainingCapacity();
|
||||
var dg: codegen.DeclGen = .{
|
||||
.gpa = gpa,
|
||||
.pt = pt,
|
||||
@ -812,20 +825,24 @@ pub fn updateExports(
|
||||
.pass = pass,
|
||||
.is_naked_fn = false,
|
||||
.expected_block = null,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.fwd_decl = undefined,
|
||||
.ctype_pool = decl_block.ctype_pool,
|
||||
.scratch = .{},
|
||||
.scratch = .initBuffer(self.scratch_buf),
|
||||
.uavs = .empty,
|
||||
};
|
||||
dg.fwd_decl.initOwnedSlice(gpa, self.fwd_decl_buf);
|
||||
defer {
|
||||
assert(dg.uavs.count() == 0);
|
||||
fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
|
||||
ctype_pool.* = dg.ctype_pool.move();
|
||||
ctype_pool.freeUnusedCapacity(gpa);
|
||||
dg.scratch.deinit(gpa);
|
||||
|
||||
self.fwd_decl_buf = dg.fwd_decl.toArrayList().allocatedSlice();
|
||||
self.scratch_buf = dg.scratch.allocatedSlice();
|
||||
}
|
||||
try codegen.genExports(&dg, exported, export_indices);
|
||||
exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };
|
||||
codegen.genExports(&dg, exported, export_indices) catch |err| switch (err) {
|
||||
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
exported_block.* = .{ .fwd_decl = try self.addString(&.{&dg.fwd_decl}) };
|
||||
}
|
||||
|
||||
pub fn deleteExport(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user