|
|
|
|
@ -32,6 +32,8 @@ pub const CValue = union(enum) {
|
|
|
|
|
constant: Air.Inst.Ref,
|
|
|
|
|
/// Index into the parameters
|
|
|
|
|
arg: usize,
|
|
|
|
|
/// Index into a tuple's fields
|
|
|
|
|
field: usize,
|
|
|
|
|
/// By-value
|
|
|
|
|
decl: Decl.Index,
|
|
|
|
|
decl_ref: Decl.Index,
|
|
|
|
|
@ -79,7 +81,6 @@ const BuiltinInfo = enum {
|
|
|
|
|
Bits,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// TODO make this not cut off at 128 bytes
|
|
|
|
|
fn formatTypeAsCIdentifier(
|
|
|
|
|
data: FormatTypeAsCIdentContext,
|
|
|
|
|
comptime fmt: []const u8,
|
|
|
|
|
@ -1297,7 +1298,8 @@ pub const DeclGen = struct {
|
|
|
|
|
var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
|
|
|
|
|
defer fqn_buf.deinit();
|
|
|
|
|
|
|
|
|
|
const owner_decl = dg.module.declPtr(child_ty.getOwnerDecl());
|
|
|
|
|
const owner_decl_index = child_ty.getOwnerDecl();
|
|
|
|
|
const owner_decl = dg.module.declPtr(owner_decl_index);
|
|
|
|
|
try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
|
|
|
|
|
|
|
|
|
|
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
|
|
|
|
|
@ -1309,7 +1311,11 @@ pub const DeclGen = struct {
|
|
|
|
|
else => unreachable,
|
|
|
|
|
};
|
|
|
|
|
const name_begin = buffer.items.len + "typedef ".len + tag.len;
|
|
|
|
|
try buffer.writer().print("typedef {s}zig_S_{} ", .{ tag, fmtIdent(fqn_buf.items) });
|
|
|
|
|
try buffer.writer().print("typedef {s}zig_S_{}__{d} ", .{
|
|
|
|
|
tag,
|
|
|
|
|
fmtIdent(fqn_buf.items),
|
|
|
|
|
@enumToInt(owner_decl_index),
|
|
|
|
|
});
|
|
|
|
|
const name_end = buffer.items.len - " ".len;
|
|
|
|
|
try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len);
|
|
|
|
|
buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
|
|
|
|
|
@ -1378,26 +1384,17 @@ pub const DeclGen = struct {
|
|
|
|
|
try buffer.appendSlice("typedef struct {\n");
|
|
|
|
|
{
|
|
|
|
|
const fields = t.tupleFields();
|
|
|
|
|
var empty = true;
|
|
|
|
|
var field_id: usize = 0;
|
|
|
|
|
for (fields.types) |field_ty, i| {
|
|
|
|
|
if (!field_ty.hasRuntimeBits()) continue;
|
|
|
|
|
const val = fields.values[i];
|
|
|
|
|
if (val.tag() != .unreachable_value) continue;
|
|
|
|
|
|
|
|
|
|
var field_name_buf: []const u8 = &.{};
|
|
|
|
|
defer dg.typedefs.allocator.free(field_name_buf);
|
|
|
|
|
const field_name = if (t.isTuple()) field_name: {
|
|
|
|
|
field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i});
|
|
|
|
|
break :field_name field_name_buf;
|
|
|
|
|
} else t.structFieldName(i);
|
|
|
|
|
if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
|
|
|
|
|
|
|
|
|
|
try buffer.append(' ');
|
|
|
|
|
try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete);
|
|
|
|
|
try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete);
|
|
|
|
|
try buffer.appendSlice(";\n");
|
|
|
|
|
|
|
|
|
|
empty = false;
|
|
|
|
|
field_id += 1;
|
|
|
|
|
}
|
|
|
|
|
if (empty) try buffer.appendSlice(" char empty_tuple;\n");
|
|
|
|
|
if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n");
|
|
|
|
|
}
|
|
|
|
|
const name_begin = buffer.items.len + "} ".len;
|
|
|
|
|
try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)});
|
|
|
|
|
@ -1751,12 +1748,38 @@ pub const DeclGen = struct {
|
|
|
|
|
},
|
|
|
|
|
.Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed)
|
|
|
|
|
try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind)
|
|
|
|
|
else if (kind == .Complete or t.isTupleOrAnonStruct()) {
|
|
|
|
|
else if (t.isTupleOrAnonStruct()) {
|
|
|
|
|
const ExpectedContents = struct { types: [8]Type, values: [8]Value };
|
|
|
|
|
var stack align(@alignOf(ExpectedContents)) =
|
|
|
|
|
std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
|
|
|
|
|
const allocator = stack.get();
|
|
|
|
|
|
|
|
|
|
var tuple_storage = std.MultiArrayList(struct { type: Type, value: Value }){};
|
|
|
|
|
defer tuple_storage.deinit(allocator);
|
|
|
|
|
try tuple_storage.ensureTotalCapacity(allocator, t.structFieldCount());
|
|
|
|
|
|
|
|
|
|
const fields = t.tupleFields();
|
|
|
|
|
for (fields.values) |value, index|
|
|
|
|
|
if (value.tag() == .unreachable_value)
|
|
|
|
|
tuple_storage.appendAssumeCapacity(.{
|
|
|
|
|
.type = fields.types[index],
|
|
|
|
|
.value = value,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const tuple_slice = tuple_storage.slice();
|
|
|
|
|
var tuple_pl = Type.Payload.Tuple{ .data = .{
|
|
|
|
|
.types = tuple_slice.items(.type),
|
|
|
|
|
.values = tuple_slice.items(.value),
|
|
|
|
|
} };
|
|
|
|
|
const tuple_ty = Type.initPayload(&tuple_pl.base);
|
|
|
|
|
|
|
|
|
|
const name = dg.getTypedefName(tuple_ty) orelse
|
|
|
|
|
try dg.renderTupleTypedef(tuple_ty);
|
|
|
|
|
|
|
|
|
|
try w.writeAll(name);
|
|
|
|
|
} else if (kind == .Complete) {
|
|
|
|
|
const name = dg.getTypedefName(t) orelse switch (tag) {
|
|
|
|
|
.Struct => if (t.isTupleOrAnonStruct())
|
|
|
|
|
try dg.renderTupleTypedef(t)
|
|
|
|
|
else
|
|
|
|
|
try dg.renderStructTypedef(t),
|
|
|
|
|
.Struct => try dg.renderStructTypedef(t),
|
|
|
|
|
.Union => try dg.renderUnionTypedef(t),
|
|
|
|
|
else => unreachable,
|
|
|
|
|
};
|
|
|
|
|
@ -1976,6 +1999,7 @@ pub const DeclGen = struct {
|
|
|
|
|
.local_ref => |i| return w.print("&t{d}", .{i}),
|
|
|
|
|
.constant => unreachable,
|
|
|
|
|
.arg => |i| return w.print("a{d}", .{i}),
|
|
|
|
|
.field => |i| return w.print("f{d}", .{i}),
|
|
|
|
|
.decl => |decl| return dg.renderDeclName(w, decl),
|
|
|
|
|
.decl_ref => |decl| {
|
|
|
|
|
try w.writeByte('&');
|
|
|
|
|
@ -1994,6 +2018,7 @@ pub const DeclGen = struct {
|
|
|
|
|
.local_ref => |i| return w.print("t{d}", .{i}),
|
|
|
|
|
.constant => unreachable,
|
|
|
|
|
.arg => |i| return w.print("(*a{d})", .{i}),
|
|
|
|
|
.field => |i| return w.print("f{d}", .{i}),
|
|
|
|
|
.decl => |decl| {
|
|
|
|
|
try w.writeAll("(*");
|
|
|
|
|
try dg.renderDeclName(w, decl);
|
|
|
|
|
@ -2018,7 +2043,7 @@ pub const DeclGen = struct {
|
|
|
|
|
|
|
|
|
|
fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
|
|
|
|
|
switch (c_value) {
|
|
|
|
|
.none, .constant, .undef => unreachable,
|
|
|
|
|
.none, .constant, .field, .undef => unreachable,
|
|
|
|
|
.local, .arg, .decl, .identifier, .bytes => {
|
|
|
|
|
try dg.writeCValue(writer, c_value);
|
|
|
|
|
try writer.writeAll("->");
|
|
|
|
|
@ -2236,12 +2261,6 @@ pub fn genDecl(o: *Object) !void {
|
|
|
|
|
const variable: *Module.Var = var_payload.data;
|
|
|
|
|
const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
|
|
|
|
|
const fwd_decl_writer = o.dg.fwd_decl.writer();
|
|
|
|
|
if (is_global) {
|
|
|
|
|
try fwd_decl_writer.writeAll("zig_extern_c ");
|
|
|
|
|
}
|
|
|
|
|
if (variable.is_threadlocal) {
|
|
|
|
|
try fwd_decl_writer.writeAll("zig_threadlocal ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const decl_c_value: CValue = if (is_global) .{
|
|
|
|
|
.bytes = mem.span(o.dg.decl.name),
|
|
|
|
|
@ -2249,6 +2268,8 @@ pub fn genDecl(o: *Object) !void {
|
|
|
|
|
.decl = o.dg.decl_index,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (is_global) try fwd_decl_writer.writeAll("zig_extern_c ");
|
|
|
|
|
if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
|
|
|
|
|
try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
|
|
|
|
|
try fwd_decl_writer.writeAll(";\n");
|
|
|
|
|
|
|
|
|
|
@ -2257,6 +2278,7 @@ pub fn genDecl(o: *Object) !void {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const w = o.writer();
|
|
|
|
|
if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
|
|
|
|
|
try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
|
|
|
|
|
try w.writeAll(" = ");
|
|
|
|
|
if (variable.init.tag() != .unreachable_value) {
|
|
|
|
|
@ -2595,19 +2617,36 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
|
|
|
|
|
const ptr_ty = f.air.typeOf(bin_op.lhs);
|
|
|
|
|
if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
|
|
|
|
|
!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ptr = try f.resolveInst(bin_op.lhs);
|
|
|
|
|
const index = try f.resolveInst(bin_op.rhs);
|
|
|
|
|
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(inst_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
} else try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, ptr, .Other);
|
|
|
|
|
try writer.writeByte('[');
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll("];\n");
|
|
|
|
|
try writer.writeByte(']');
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, inst_ty);
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2637,19 +2676,36 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
|
|
|
|
|
const slice_ty = f.air.typeOf(bin_op.lhs);
|
|
|
|
|
if (!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
|
|
|
|
|
!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const slice = try f.resolveInst(bin_op.lhs);
|
|
|
|
|
const index = try f.resolveInst(bin_op.rhs);
|
|
|
|
|
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(inst_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
} else try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, slice, .Other);
|
|
|
|
|
try writer.writeAll(".ptr[");
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll("];\n");
|
|
|
|
|
try writer.writeByte(']');
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, inst_ty);
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2672,18 +2728,34 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
|
|
|
|
|
const array = try f.resolveInst(bin_op.lhs);
|
|
|
|
|
const index = try f.resolveInst(bin_op.rhs);
|
|
|
|
|
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(inst_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
} else try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, array, .Other);
|
|
|
|
|
try writer.writeByte('[');
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll("];\n");
|
|
|
|
|
try writer.writeByte(']');
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, inst_ty);
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2817,7 +2889,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
|
|
|
|
|
const array_local = try f.allocLocal(lowered_ret_ty, .Mut);
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
|
|
|
|
|
try f.writeCValueMember(writer, array_local, .{ .field = 0 });
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
if (deref)
|
|
|
|
|
try f.writeCValueDeref(writer, operand)
|
|
|
|
|
@ -3063,13 +3135,13 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
|
|
|
|
|
const local = try f.allocLocal(inst_ty, .Mut);
|
|
|
|
|
try w.writeAll(";\n");
|
|
|
|
|
|
|
|
|
|
try f.writeCValue(w, local, .Other);
|
|
|
|
|
try w.writeAll(".field_1 = zig_");
|
|
|
|
|
try f.writeCValueMember(w, local, .{ .field = 1 });
|
|
|
|
|
try w.writeAll(" = zig_");
|
|
|
|
|
try w.writeAll(operation);
|
|
|
|
|
try w.writeAll("o_");
|
|
|
|
|
try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
|
|
|
|
|
try w.writeAll("(&");
|
|
|
|
|
try f.writeCValueMember(w, local, .{ .identifier = "field_0" });
|
|
|
|
|
try f.writeCValueMember(w, local, .{ .field = 0 });
|
|
|
|
|
try w.writeAll(", ");
|
|
|
|
|
try f.writeCValue(w, lhs, .FunctionArgument);
|
|
|
|
|
try w.writeAll(", ");
|
|
|
|
|
@ -3191,7 +3263,7 @@ fn airEquality(
|
|
|
|
|
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
|
|
|
|
|
if (operand_ty.tag() == .optional) {
|
|
|
|
|
if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
|
|
|
|
|
// (A && B) || (C && (A == B))
|
|
|
|
|
// A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
|
|
|
|
|
|
|
|
|
|
@ -3429,7 +3501,7 @@ fn airCall(
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, array_local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
|
|
|
|
|
try f.writeCValueMember(writer, result_local, .{ .field = 0 });
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, ret_ty);
|
|
|
|
|
try writer.writeAll("));\n");
|
|
|
|
|
@ -3590,25 +3662,39 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
// If result is .none then the value of the block is unused.
|
|
|
|
|
if (result != .none) {
|
|
|
|
|
const operand = try f.resolveInst(branch.operand);
|
|
|
|
|
try f.writeCValue(writer, result, .Other);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, operand, .Other);
|
|
|
|
|
|
|
|
|
|
const operand_ty = f.air.typeOf(branch.operand);
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
if (lowersToArray(operand_ty, target)) {
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, result, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValue(writer, operand, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, operand_ty);
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
} else {
|
|
|
|
|
try f.writeCValue(writer, result, .Other);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, operand, .Other);
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try f.object.writer().print("goto zig_block_{d};\n", .{block.block_id});
|
|
|
|
|
try writer.print("goto zig_block_{d};\n", .{block.block_id});
|
|
|
|
|
return CValue.none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst))
|
|
|
|
|
return CValue.none;
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
// No IgnoreComptime until Sema stops giving us garbage Air.
|
|
|
|
|
// https://github.com/ziglang/zig/issues/13410
|
|
|
|
|
if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const operand = try f.resolveInst(ty_op.operand);
|
|
|
|
|
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
if (inst_ty.isPtrAtRuntime() and
|
|
|
|
|
f.air.typeOf(ty_op.operand).isPtrAtRuntime())
|
|
|
|
|
{
|
|
|
|
|
@ -3982,9 +4068,9 @@ fn airIsNull(
|
|
|
|
|
|
|
|
|
|
const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime())
|
|
|
|
|
TypedValue{ .ty = Type.bool, .val = Value.@"true" }
|
|
|
|
|
else if (operand_ty.isPtrLikeOptional())
|
|
|
|
|
else if (optional_ty.isPtrLikeOptional())
|
|
|
|
|
// operand is a regular pointer, test `operand !=/== NULL`
|
|
|
|
|
TypedValue{ .ty = operand_ty, .val = Value.@"null" }
|
|
|
|
|
TypedValue{ .ty = optional_ty, .val = Value.@"null" }
|
|
|
|
|
else if (payload_ty.zigTypeTag() == .ErrorSet)
|
|
|
|
|
TypedValue{ .ty = payload_ty, .val = Value.zero }
|
|
|
|
|
else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: {
|
|
|
|
|
@ -4007,26 +4093,34 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const operand = try f.resolveInst(ty_op.operand);
|
|
|
|
|
const opt_ty = f.air.typeOf(ty_op.operand);
|
|
|
|
|
|
|
|
|
|
var buf: Type.Payload.ElemType = undefined;
|
|
|
|
|
const payload_ty = opt_ty.optionalChild(&buf);
|
|
|
|
|
|
|
|
|
|
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
|
|
|
|
return CValue.none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opt_ty.optionalReprIsPayload()) {
|
|
|
|
|
return operand;
|
|
|
|
|
}
|
|
|
|
|
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
|
|
|
|
|
if (opt_ty.optionalReprIsPayload()) return operand;
|
|
|
|
|
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
const local = try f.allocLocal(inst_ty, .Const);
|
|
|
|
|
try writer.writeAll(" = (");
|
|
|
|
|
try f.writeCValue(writer, operand, .Other);
|
|
|
|
|
try writer.writeAll(").payload;\n");
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(inst_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
} else try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, inst_ty);
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4159,16 +4253,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
|
|
|
|
|
try f.renderTypecast(writer, field_ptr_ty);
|
|
|
|
|
try writer.writeByte(')');
|
|
|
|
|
|
|
|
|
|
const extra_name: ?[]const u8 = switch (struct_ty.tag()) {
|
|
|
|
|
.union_tagged, .union_safety_tagged => "payload",
|
|
|
|
|
else => null,
|
|
|
|
|
const extra_name: CValue = switch (struct_ty.tag()) {
|
|
|
|
|
.union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
|
|
|
|
|
else => .none,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var field_name_buf: []const u8 = &.{};
|
|
|
|
|
defer f.object.dg.gpa.free(field_name_buf);
|
|
|
|
|
const field_name: ?[]const u8 = switch (struct_ty.tag()) {
|
|
|
|
|
const field_name: CValue = switch (struct_ty.tag()) {
|
|
|
|
|
.@"struct" => switch (struct_ty.containerLayout()) {
|
|
|
|
|
.Auto, .Extern => struct_ty.structFieldName(index),
|
|
|
|
|
.Auto, .Extern => CValue{ .identifier = struct_ty.structFieldName(index) },
|
|
|
|
|
.Packed => if (field_ptr_info.data.host_size == 0) {
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
|
|
|
|
|
@ -4189,29 +4281,35 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
|
|
|
|
|
try f.writeCValue(writer, struct_ptr, .Other);
|
|
|
|
|
try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
|
|
|
|
|
return local;
|
|
|
|
|
} else null,
|
|
|
|
|
} else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
|
|
|
|
|
},
|
|
|
|
|
.@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index],
|
|
|
|
|
.tuple, .anon_struct => |tag| field_name: {
|
|
|
|
|
.@"union", .union_safety_tagged, .union_tagged => .{
|
|
|
|
|
.identifier = struct_ty.unionFields().keys()[index],
|
|
|
|
|
},
|
|
|
|
|
.tuple, .anon_struct => field_name: {
|
|
|
|
|
const tuple = struct_ty.tupleFields();
|
|
|
|
|
if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
|
|
|
|
|
|
|
|
|
|
if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index);
|
|
|
|
|
|
|
|
|
|
field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
|
|
|
|
|
break :field_name field_name_buf;
|
|
|
|
|
var id: usize = 0;
|
|
|
|
|
for (tuple.values[0..index]) |value|
|
|
|
|
|
id += @boolToInt(value.tag() == .unreachable_value);
|
|
|
|
|
break :field_name .{ .field = id };
|
|
|
|
|
},
|
|
|
|
|
else => unreachable,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (field_ty.hasRuntimeBitsIgnoreComptime()) {
|
|
|
|
|
try writer.writeByte('&');
|
|
|
|
|
if (extra_name orelse field_name) |name|
|
|
|
|
|
try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name })
|
|
|
|
|
if (extra_name != .none) {
|
|
|
|
|
try f.writeCValueDerefMember(writer, struct_ptr, extra_name);
|
|
|
|
|
if (field_name != .none) {
|
|
|
|
|
try writer.writeByte('.');
|
|
|
|
|
try f.writeCValue(writer, field_name, .Other);
|
|
|
|
|
}
|
|
|
|
|
} else if (field_name != .none)
|
|
|
|
|
try f.writeCValueDerefMember(writer, struct_ptr, field_name)
|
|
|
|
|
else
|
|
|
|
|
try f.writeCValueDeref(writer, struct_ptr);
|
|
|
|
|
if (extra_name) |_| if (field_name) |name|
|
|
|
|
|
try writer.print(".{ }", .{fmtIdent(name)});
|
|
|
|
|
} else try f.writeCValue(writer, struct_ptr, .Other);
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
@ -4221,9 +4319,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst))
|
|
|
|
|
return CValue.none;
|
|
|
|
|
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
if (!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
|
|
|
|
|
const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const struct_byval = try f.resolveInst(extra.struct_operand);
|
|
|
|
|
const struct_ty = f.air.typeOf(extra.struct_operand);
|
|
|
|
|
@ -4232,11 +4332,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
// Ensure complete type definition is visible before accessing fields.
|
|
|
|
|
try f.renderType(std.io.null_writer, struct_ty);
|
|
|
|
|
|
|
|
|
|
var field_name_buf: []const u8 = "";
|
|
|
|
|
defer f.object.dg.gpa.free(field_name_buf);
|
|
|
|
|
const field_name = switch (struct_ty.tag()) {
|
|
|
|
|
const extra_name: CValue = switch (struct_ty.tag()) {
|
|
|
|
|
.union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
|
|
|
|
|
else => .none,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const field_name: CValue = switch (struct_ty.tag()) {
|
|
|
|
|
.@"struct" => switch (struct_ty.containerLayout()) {
|
|
|
|
|
.Auto, .Extern => struct_ty.structFieldName(extra.field_index),
|
|
|
|
|
.Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) },
|
|
|
|
|
.Packed => {
|
|
|
|
|
const struct_obj = struct_ty.castTag(.@"struct").?.data;
|
|
|
|
|
const int_info = struct_ty.intInfo(target);
|
|
|
|
|
@ -4294,19 +4397,20 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
return local;
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
|
|
|
|
|
.tuple, .anon_struct => |tag| blk: {
|
|
|
|
|
.@"union", .union_safety_tagged, .union_tagged => .{
|
|
|
|
|
.identifier = struct_ty.unionFields().keys()[extra.field_index],
|
|
|
|
|
},
|
|
|
|
|
.tuple, .anon_struct => blk: {
|
|
|
|
|
const tuple = struct_ty.tupleFields();
|
|
|
|
|
if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
|
|
|
|
|
|
|
|
|
|
if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index);
|
|
|
|
|
|
|
|
|
|
field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index});
|
|
|
|
|
break :blk field_name_buf;
|
|
|
|
|
var id: usize = 0;
|
|
|
|
|
for (tuple.values[0..extra.field_index]) |value|
|
|
|
|
|
id += @boolToInt(value.tag() == .unreachable_value);
|
|
|
|
|
break :blk .{ .field = id };
|
|
|
|
|
},
|
|
|
|
|
else => unreachable,
|
|
|
|
|
};
|
|
|
|
|
const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
|
|
|
|
|
|
|
|
|
|
const is_array = lowersToArray(inst_ty, target);
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
@ -4315,15 +4419,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValue(writer, struct_byval, .Other);
|
|
|
|
|
try writer.print(".{s}{ }, sizeof(", .{ payload, fmtIdent(field_name) });
|
|
|
|
|
} else try writer.writeAll(" = ");
|
|
|
|
|
if (extra_name != .none) {
|
|
|
|
|
try f.writeCValueMember(writer, struct_byval, extra_name);
|
|
|
|
|
try writer.writeByte('.');
|
|
|
|
|
try f.writeCValue(writer, field_name, .Other);
|
|
|
|
|
} else try f.writeCValueMember(writer, struct_byval, field_name);
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, inst_ty);
|
|
|
|
|
try writer.writeAll("));\n");
|
|
|
|
|
} else {
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
try f.writeCValue(writer, struct_byval, .Other);
|
|
|
|
|
try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) });
|
|
|
|
|
try writer.writeAll("))");
|
|
|
|
|
}
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4383,25 +4490,33 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst))
|
|
|
|
|
return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const operand = try f.resolveInst(ty_op.operand);
|
|
|
|
|
if (f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
if (inst_ty.optionalReprIsPayload()) {
|
|
|
|
|
return operand;
|
|
|
|
|
}
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const payload = try f.resolveInst(ty_op.operand);
|
|
|
|
|
if (inst_ty.optionalReprIsPayload()) return payload;
|
|
|
|
|
|
|
|
|
|
// .wrap_optional is used to convert non-optionals into optionals so it can never be null.
|
|
|
|
|
const local = try f.allocLocal(inst_ty, .Const);
|
|
|
|
|
const payload_ty = f.air.typeOf(ty_op.operand);
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(payload_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
try writer.writeAll(" = { .payload = ");
|
|
|
|
|
try f.writeCValue(writer, operand, .Initializer);
|
|
|
|
|
try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
|
|
|
|
|
try writer.writeAll(", .is_null = ");
|
|
|
|
|
try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer);
|
|
|
|
|
try writer.writeAll(" };\n");
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValue(writer, payload, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, payload_ty);
|
|
|
|
|
try writer.writeAll("));\n");
|
|
|
|
|
}
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4473,35 +4588,33 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (f.liveness.isUnused(inst))
|
|
|
|
|
return CValue.none;
|
|
|
|
|
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
const operand = try f.resolveInst(ty_op.operand);
|
|
|
|
|
if (f.liveness.isUnused(inst)) return CValue.none;
|
|
|
|
|
|
|
|
|
|
const inst_ty = f.air.typeOfIndex(inst);
|
|
|
|
|
const payload_ty = inst_ty.errorUnionPayload();
|
|
|
|
|
const error_ty = inst_ty.errorUnionSet();
|
|
|
|
|
const ty_op = f.air.instructions.items(.data)[inst].ty_op;
|
|
|
|
|
const payload_ty = inst_ty.errorUnionPayload();
|
|
|
|
|
const payload = try f.resolveInst(ty_op.operand);
|
|
|
|
|
|
|
|
|
|
const target = f.object.dg.module.getTarget();
|
|
|
|
|
const is_array = lowersToArray(payload_ty, target);
|
|
|
|
|
|
|
|
|
|
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
try writer.writeAll(" = { .payload = ");
|
|
|
|
|
try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer);
|
|
|
|
|
try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
|
|
|
|
|
try writer.writeAll(", .error = ");
|
|
|
|
|
try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer);
|
|
|
|
|
try writer.writeAll(" };\n");
|
|
|
|
|
|
|
|
|
|
if (is_array) {
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .Other);
|
|
|
|
|
try writer.writeAll(".payload, ");
|
|
|
|
|
try f.writeCValue(writer, operand, .FunctionArgument);
|
|
|
|
|
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValue(writer, payload, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, payload_ty);
|
|
|
|
|
try writer.writeAll("));\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -4845,10 +4958,41 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
|
|
|
|
|
fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
|
|
|
|
|
const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
|
|
|
|
|
const dest_ty = f.air.typeOf(pl_op.operand);
|
|
|
|
|
const dest_ptr = try f.resolveInst(pl_op.operand);
|
|
|
|
|
const value = try f.resolveInst(extra.lhs);
|
|
|
|
|
const len = try f.resolveInst(extra.rhs);
|
|
|
|
|
|
|
|
|
|
const writer = f.object.writer();
|
|
|
|
|
if (dest_ty.isVolatilePtr()) {
|
|
|
|
|
var u8_ptr_pl = dest_ty.ptrInfo();
|
|
|
|
|
u8_ptr_pl.data.pointee_type = Type.u8;
|
|
|
|
|
const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
|
|
|
|
|
|
|
|
|
|
try writer.writeAll("for (");
|
|
|
|
|
const index = try f.allocLocal(Type.usize, .Mut);
|
|
|
|
|
try writer.writeAll(" = ");
|
|
|
|
|
try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer);
|
|
|
|
|
try writer.writeAll("; ");
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll(" != ");
|
|
|
|
|
try f.writeCValue(writer, len, .Other);
|
|
|
|
|
try writer.writeAll("; ");
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll(" += ");
|
|
|
|
|
try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
|
|
|
|
|
try writer.writeAll(") ((");
|
|
|
|
|
try f.renderTypecast(writer, u8_ptr_ty);
|
|
|
|
|
try writer.writeByte(')');
|
|
|
|
|
try f.writeCValue(writer, dest_ptr, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(")[");
|
|
|
|
|
try f.writeCValue(writer, index, .Other);
|
|
|
|
|
try writer.writeAll("] = ");
|
|
|
|
|
try f.writeCValue(writer, value, .FunctionArgument);
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
|
|
|
|
|
return CValue.none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try writer.writeAll("memset(");
|
|
|
|
|
try f.writeCValue(writer, dest_ptr, .FunctionArgument);
|
|
|
|
|
@ -5068,27 +5212,28 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
|
|
|
|
if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
|
|
|
|
|
try writer.writeAll("};\n");
|
|
|
|
|
|
|
|
|
|
var field_id: usize = 0;
|
|
|
|
|
for (elements) |element, index| {
|
|
|
|
|
if (inst_ty.structFieldValueComptime(index)) |_| continue;
|
|
|
|
|
|
|
|
|
|
const element_ty = f.air.typeOf(element);
|
|
|
|
|
if (element_ty.zigTypeTag() != .Array) continue;
|
|
|
|
|
|
|
|
|
|
var field_name_buf: []u8 = &.{};
|
|
|
|
|
defer f.object.dg.gpa.free(field_name_buf);
|
|
|
|
|
const field_name = if (inst_ty.isTuple()) field_name: {
|
|
|
|
|
field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index});
|
|
|
|
|
break :field_name field_name_buf;
|
|
|
|
|
} else inst_ty.structFieldName(index);
|
|
|
|
|
const field_name = if (inst_ty.isTupleOrAnonStruct())
|
|
|
|
|
CValue{ .field = field_id }
|
|
|
|
|
else
|
|
|
|
|
CValue{ .identifier = inst_ty.structFieldName(index) };
|
|
|
|
|
|
|
|
|
|
try writer.writeAll(";\n");
|
|
|
|
|
try writer.writeAll("memcpy(");
|
|
|
|
|
try f.writeCValue(writer, local, .Other);
|
|
|
|
|
try writer.print(".{ }, ", .{fmtIdent(field_name)});
|
|
|
|
|
try f.writeCValueMember(writer, local, field_name);
|
|
|
|
|
try writer.writeAll(", ");
|
|
|
|
|
try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);
|
|
|
|
|
try writer.writeAll(", sizeof(");
|
|
|
|
|
try f.renderTypecast(writer, element_ty);
|
|
|
|
|
try writer.writeAll("));\n");
|
|
|
|
|
|
|
|
|
|
field_id += 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.Packed => {
|
|
|
|
|
@ -5634,10 +5779,9 @@ fn isByRef(ty: Type) bool {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LowerFnRetTyBuffer = struct {
|
|
|
|
|
const names = [1][]const u8{"array"};
|
|
|
|
|
types: [1]Type,
|
|
|
|
|
values: [1]Value,
|
|
|
|
|
payload: Type.Payload.AnonStruct,
|
|
|
|
|
payload: Type.Payload.Tuple,
|
|
|
|
|
};
|
|
|
|
|
fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {
|
|
|
|
|
if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);
|
|
|
|
|
@ -5646,7 +5790,6 @@ fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) T
|
|
|
|
|
buffer.types = [1]Type{ret_ty};
|
|
|
|
|
buffer.values = [1]Value{Value.initTag(.unreachable_value)};
|
|
|
|
|
buffer.payload = .{ .data = .{
|
|
|
|
|
.names = &LowerFnRetTyBuffer.names,
|
|
|
|
|
.types = &buffer.types,
|
|
|
|
|
.values = &buffer.values,
|
|
|
|
|
} };
|
|
|
|
|
|