mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
stage2: implement @unionInit
The ZIR instruction `union_init_ptr` is renamed to `union_init`. I made it always use by-value semantics for now, not taking the time to invest in result location semantics, in case we decide to change the rules for unions. This way is much simpler. There is a new AIR instruction: union_init. This is for a comptime known tag, runtime-known field value. vector_init is renamed to aggregate_init, which solves a TODO comment.
This commit is contained in:
parent
32e89a98d8
commit
2687b8f7f4
18
src/Air.zig
18
src/Air.zig
@ -561,13 +561,15 @@ pub const Inst = struct {
|
||||
/// Uses the `un_op` field.
|
||||
error_name,
|
||||
|
||||
/// Constructs a vector, tuple, or array value out of runtime-known elements.
|
||||
/// Constructs a vector, tuple, struct, or array value out of runtime-known elements.
|
||||
/// Some of the elements may be comptime-known.
|
||||
/// Uses the `ty_pl` field, payload is index of an array of elements, each of which
|
||||
/// is a `Ref`. Length of the array is given by the vector type.
|
||||
/// TODO rename this to `aggregate_init` and make it support array values and
|
||||
/// struct values too.
|
||||
vector_init,
|
||||
aggregate_init,
|
||||
|
||||
/// Constructs a union from a field index and a runtime-known init value.
|
||||
/// Uses the `ty_pl` field with payload `UnionInit`.
|
||||
union_init,
|
||||
|
||||
/// Communicates an intent to load memory.
|
||||
/// Result is always unused.
|
||||
@ -768,6 +770,11 @@ pub const AtomicRmw = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const UnionInit = struct {
|
||||
field_index: u32,
|
||||
init: Inst.Ref,
|
||||
};
|
||||
|
||||
pub fn getMainBody(air: Air) []const Air.Inst.Index {
|
||||
const body_index = air.extra[@enumToInt(ExtraIndex.main_block)];
|
||||
const extra = air.extraData(Block, body_index);
|
||||
@ -864,7 +871,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
.cmpxchg_weak,
|
||||
.cmpxchg_strong,
|
||||
.slice,
|
||||
.vector_init,
|
||||
.aggregate_init,
|
||||
.union_init,
|
||||
.field_parent_ptr,
|
||||
=> return air.getRefType(datas[inst].ty_pl.ty),
|
||||
|
||||
|
||||
@ -2052,8 +2052,8 @@ fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Sc
|
||||
_ = try unusedResultExpr(gz, expr_scope, expr_node);
|
||||
}
|
||||
|
||||
/// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`.
|
||||
/// Otherwise returns 0.
|
||||
/// Returns AST source node of the thing that is noreturn if the statement is
|
||||
/// definitely `noreturn`. Otherwise returns 0.
|
||||
fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index {
|
||||
try emitDbgNode(gz, statement);
|
||||
// We need to emit an error if the result is not `noreturn` or `void`, but
|
||||
@ -2201,7 +2201,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init_ptr,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
.error_set_decl,
|
||||
@ -6802,40 +6802,17 @@ fn unionInit(
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const union_type = try typeExpr(gz, scope, params[0]);
|
||||
const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
|
||||
switch (rl) {
|
||||
.none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
|
||||
_ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
|
||||
.container_type = union_type,
|
||||
.field_name = field_name,
|
||||
});
|
||||
const result = try expr(gz, scope, .{ .ty = union_type }, params[2]);
|
||||
return rvalue(gz, rl, result, node);
|
||||
},
|
||||
.ptr => |result_ptr| {
|
||||
return unionInitRlPtr(gz, scope, node, result_ptr, params[2], union_type, field_name);
|
||||
},
|
||||
.block_ptr => |block_scope| {
|
||||
return unionInitRlPtr(gz, scope, node, block_scope.rl_ptr, params[2], union_type, field_name);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unionInitRlPtr(
|
||||
parent_gz: *GenZir,
|
||||
scope: *Scope,
|
||||
node: Ast.Node.Index,
|
||||
result_ptr: Zir.Inst.Ref,
|
||||
expr_node: Ast.Node.Index,
|
||||
union_type: Zir.Inst.Ref,
|
||||
field_name: Zir.Inst.Ref,
|
||||
) InnerError!Zir.Inst.Ref {
|
||||
const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
|
||||
.result_ptr = result_ptr,
|
||||
.union_type = union_type,
|
||||
const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
|
||||
.container_type = union_type,
|
||||
.field_name = field_name,
|
||||
});
|
||||
// TODO check if we need to do the elision like below in asRlPtr
|
||||
return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node);
|
||||
const init = try reachableExpr(gz, scope, .{ .ty = field_type }, params[2], node);
|
||||
const result = try gz.addPlNode(.union_init, node, Zir.Inst.UnionInit{
|
||||
.union_type = union_type,
|
||||
.init = init,
|
||||
.field_name = field_name,
|
||||
});
|
||||
return rvalue(gz, rl, result, node);
|
||||
}
|
||||
|
||||
fn asRlPtr(
|
||||
|
||||
@ -25,7 +25,7 @@ tomb_bits: []usize,
|
||||
/// array. The meaning of the data depends on the AIR tag.
|
||||
/// * `cond_br` - points to a `CondBr` in `extra` at this index.
|
||||
/// * `switch_br` - points to a `SwitchBr` in `extra` at this index.
|
||||
/// * `asm`, `call`, `vector_init` - the value is a set of bits which are the extra tomb
|
||||
/// * `asm`, `call`, `aggregate_init` - the value is a set of bits which are the extra tomb
|
||||
/// bits of operands.
|
||||
/// The main tomb bits are still used and the extra ones are starting with the lsb of the
|
||||
/// value here.
|
||||
@ -420,10 +420,10 @@ fn analyzeInst(
|
||||
}
|
||||
return extra_tombs.finish();
|
||||
},
|
||||
.vector_init => {
|
||||
.aggregate_init => {
|
||||
const ty_pl = inst_datas[inst].ty_pl;
|
||||
const vector_ty = a.air.getRefType(ty_pl.ty);
|
||||
const len = @intCast(usize, vector_ty.arrayLen());
|
||||
const aggregate_ty = a.air.getRefType(ty_pl.ty);
|
||||
const len = @intCast(usize, aggregate_ty.arrayLen());
|
||||
const elements = @bitCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]);
|
||||
|
||||
if (elements.len <= bpi - 1) {
|
||||
@ -442,6 +442,10 @@ fn analyzeInst(
|
||||
}
|
||||
return extra_tombs.finish();
|
||||
},
|
||||
.union_init => {
|
||||
const extra = a.air.extraData(Air.UnionInit, inst_datas[inst].ty_pl.payload).data;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ extra.init, .none, .none });
|
||||
},
|
||||
.struct_field_ptr, .struct_field_val => {
|
||||
const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
|
||||
|
||||
@ -1123,6 +1123,15 @@ pub const Union = struct {
|
||||
/// undefined until `status` is `have_field_types` or `have_layout`.
|
||||
ty: Type,
|
||||
abi_align: Value,
|
||||
|
||||
/// Returns the field alignment, assuming the union is not packed.
|
||||
pub fn normalAlignment(field: Field, target: Target) u32 {
|
||||
if (field.abi_align.tag() == .abi_align_default) {
|
||||
return field.ty.abiAlignment(target);
|
||||
} else {
|
||||
return @intCast(u32, field.abi_align.toUnsignedInt());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
|
||||
|
||||
113
src/Sema.zig
113
src/Sema.zig
@ -204,7 +204,7 @@ pub const Block = struct {
|
||||
return block.namespace.file_scope;
|
||||
}
|
||||
|
||||
pub fn addTy(
|
||||
fn addTy(
|
||||
block: *Block,
|
||||
tag: Air.Inst.Tag,
|
||||
ty: Type,
|
||||
@ -215,7 +215,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addTyOp(
|
||||
fn addTyOp(
|
||||
block: *Block,
|
||||
tag: Air.Inst.Tag,
|
||||
ty: Type,
|
||||
@ -230,7 +230,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {
|
||||
fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = .bitcast,
|
||||
.data = .{ .ty_op = .{
|
||||
@ -240,14 +240,14 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {
|
||||
fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = tag,
|
||||
.data = .{ .no_op = {} },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addUnOp(
|
||||
fn addUnOp(
|
||||
block: *Block,
|
||||
tag: Air.Inst.Tag,
|
||||
operand: Air.Inst.Ref,
|
||||
@ -258,7 +258,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addBr(
|
||||
fn addBr(
|
||||
block: *Block,
|
||||
target_block: Air.Inst.Index,
|
||||
operand: Air.Inst.Ref,
|
||||
@ -328,7 +328,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addStructFieldVal(
|
||||
fn addStructFieldVal(
|
||||
block: *Block,
|
||||
struct_val: Air.Inst.Ref,
|
||||
field_index: u32,
|
||||
@ -346,7 +346,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addSliceElemPtr(
|
||||
fn addSliceElemPtr(
|
||||
block: *Block,
|
||||
slice: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
@ -364,7 +364,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addPtrElemPtr(
|
||||
fn addPtrElemPtr(
|
||||
block: *Block,
|
||||
array_ptr: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
@ -374,7 +374,7 @@ pub const Block = struct {
|
||||
return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref);
|
||||
}
|
||||
|
||||
pub fn addPtrElemPtrTypeRef(
|
||||
fn addPtrElemPtrTypeRef(
|
||||
block: *Block,
|
||||
array_ptr: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
@ -392,7 +392,7 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addVectorInit(
|
||||
fn addAggregateInit(
|
||||
block: *Block,
|
||||
vector_ty: Type,
|
||||
elements: []const Air.Inst.Ref,
|
||||
@ -404,7 +404,7 @@ pub const Block = struct {
|
||||
sema.appendRefsAssumeCapacity(elements);
|
||||
|
||||
return block.addInst(.{
|
||||
.tag = .vector_init,
|
||||
.tag = .aggregate_init,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = ty_ref,
|
||||
.payload = extra_index,
|
||||
@ -412,6 +412,24 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
fn addUnionInit(
|
||||
block: *Block,
|
||||
union_ty: Type,
|
||||
field_index: u32,
|
||||
init: Air.Inst.Ref,
|
||||
) !Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = .union_init,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = try block.sema.addType(union_ty),
|
||||
.payload = try block.sema.addExtra(Air.UnionInit{
|
||||
.field_index = field_index,
|
||||
.init = init,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
|
||||
return Air.indexToRef(try block.addInstAsIndex(inst));
|
||||
}
|
||||
@ -697,7 +715,7 @@ fn analyzeBodyInner(
|
||||
.array_init_ref => try sema.zirArrayInit(block, inst, true),
|
||||
.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
|
||||
.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
|
||||
.union_init_ptr => try sema.zirUnionInitPtr(block, inst),
|
||||
.union_init => try sema.zirUnionInit(block, inst),
|
||||
.field_type => try sema.zirFieldType(block, inst),
|
||||
.field_type_ref => try sema.zirFieldTypeRef(block, inst),
|
||||
.ptr_to_int => try sema.zirPtrToInt(block, inst),
|
||||
@ -11273,10 +11291,31 @@ fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
|
||||
}
|
||||
}
|
||||
|
||||
fn zirUnionInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
return sema.fail(block, src, "TODO: Sema.zirUnionInitPtr", .{});
|
||||
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||
const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
|
||||
const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
|
||||
const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
|
||||
const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
|
||||
const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
|
||||
const init = sema.resolveInst(extra.init);
|
||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
||||
const field_index_usize = union_obj.fields.getIndex(field_name) orelse
|
||||
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
||||
const field_index = @intCast(u32, field_index_usize);
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
|
||||
const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
|
||||
return sema.addConstant(
|
||||
union_ty,
|
||||
try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = init_val }),
|
||||
);
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, init_src);
|
||||
try sema.resolveTypeLayout(block, ty_src, union_ty);
|
||||
return block.addUnionInit(union_ty, field_index, init);
|
||||
}
|
||||
|
||||
fn zirStructInit(
|
||||
@ -11447,7 +11486,7 @@ fn finishStructInit(
|
||||
}
|
||||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addVectorInit(struct_ty, field_inits);
|
||||
return block.addAggregateInit(struct_ty, field_inits);
|
||||
}
|
||||
|
||||
fn zirStructInitAnon(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
|
||||
@ -11527,7 +11566,7 @@ fn zirArrayInit(
|
||||
return alloc;
|
||||
}
|
||||
|
||||
return block.addVectorInit(array_ty, resolved_args);
|
||||
return block.addAggregateInit(array_ty, resolved_args);
|
||||
}
|
||||
|
||||
fn zirArrayInitAnon(
|
||||
@ -11593,7 +11632,7 @@ fn zirArrayInitAnon(
|
||||
element_refs[i] = sema.resolveInst(operand);
|
||||
}
|
||||
|
||||
return block.addVectorInit(tuple_ty, element_refs);
|
||||
return block.addAggregateInit(tuple_ty, element_refs);
|
||||
}
|
||||
|
||||
fn addConstantMaybeRef(
|
||||
@ -11617,31 +11656,47 @@ fn addConstantMaybeRef(
|
||||
|
||||
fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const src = inst_data.src();
|
||||
return sema.fail(block, src, "TODO: Sema.zirFieldTypeRef", .{});
|
||||
const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
|
||||
const ty_src = inst_data.src();
|
||||
const field_src = inst_data.src();
|
||||
const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
|
||||
const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
|
||||
return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
|
||||
}
|
||||
|
||||
fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
|
||||
const src = inst_data.src();
|
||||
const ty_src = inst_data.src();
|
||||
const field_src = inst_data.src();
|
||||
const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
|
||||
const field_name = sema.code.nullTerminatedString(extra.name_start);
|
||||
const unresolved_ty = try sema.resolveType(block, src, extra.container_type);
|
||||
const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_ty);
|
||||
return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
|
||||
}
|
||||
|
||||
fn fieldType(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
aggregate_ty: Type,
|
||||
field_name: []const u8,
|
||||
field_src: LazySrcLoc,
|
||||
ty_src: LazySrcLoc,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const resolved_ty = try sema.resolveTypeFields(block, ty_src, aggregate_ty);
|
||||
switch (resolved_ty.zigTypeTag()) {
|
||||
.Struct => {
|
||||
const struct_obj = resolved_ty.castTag(.@"struct").?.data;
|
||||
const field = struct_obj.fields.get(field_name) orelse
|
||||
return sema.failWithBadStructFieldAccess(block, struct_obj, src, field_name);
|
||||
return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
|
||||
return sema.addType(field.ty);
|
||||
},
|
||||
.Union => {
|
||||
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
|
||||
const field = union_obj.fields.get(field_name) orelse
|
||||
return sema.failWithBadUnionFieldAccess(block, union_obj, src, field_name);
|
||||
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
|
||||
return sema.addType(field.ty);
|
||||
},
|
||||
else => return sema.fail(block, src, "expected struct or union; found '{}'", .{
|
||||
else => return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{
|
||||
resolved_ty,
|
||||
}),
|
||||
}
|
||||
@ -16396,7 +16451,7 @@ fn coerceArrayLike(
|
||||
|
||||
if (runtime_src) |rs| {
|
||||
try sema.requireRuntimeBlock(block, rs);
|
||||
return block.addVectorInit(dest_ty, element_refs);
|
||||
return block.addAggregateInit(dest_ty, element_refs);
|
||||
}
|
||||
|
||||
return sema.addConstant(
|
||||
@ -16453,7 +16508,7 @@ fn coerceTupleToArray(
|
||||
|
||||
if (runtime_src) |rs| {
|
||||
try sema.requireRuntimeBlock(block, rs);
|
||||
return block.addVectorInit(dest_ty, element_refs);
|
||||
return block.addAggregateInit(dest_ty, element_refs);
|
||||
}
|
||||
|
||||
return sema.addConstant(
|
||||
|
||||
15
src/Zir.zig
15
src/Zir.zig
@ -721,10 +721,9 @@ pub const Inst = struct {
|
||||
/// Anonymous array initialization syntax, make the result a pointer.
|
||||
/// Uses the `pl_node` field. Payload is `MultiOp`.
|
||||
array_init_anon_ref,
|
||||
/// Given a pointer to a union and a comptime known field name, activates that field
|
||||
/// and returns a pointer to it.
|
||||
/// Uses the `pl_node` field. Payload is `UnionInitPtr`.
|
||||
union_init_ptr,
|
||||
/// Implements the `@unionInit` builtin.
|
||||
/// Uses the `pl_node` field. Payload is `UnionInit`.
|
||||
union_init,
|
||||
/// Implements the `@typeInfo` builtin. Uses `un_node`.
|
||||
type_info,
|
||||
/// Implements the `@sizeOf` builtin. Uses `un_node`.
|
||||
@ -1125,7 +1124,7 @@ pub const Inst = struct {
|
||||
.array_init_anon,
|
||||
.array_init_ref,
|
||||
.array_init_anon_ref,
|
||||
.union_init_ptr,
|
||||
.union_init,
|
||||
.field_type,
|
||||
.field_type_ref,
|
||||
.int_to_enum,
|
||||
@ -1383,7 +1382,7 @@ pub const Inst = struct {
|
||||
.array_init_anon = .pl_node,
|
||||
.array_init_ref = .pl_node,
|
||||
.array_init_anon_ref = .pl_node,
|
||||
.union_init_ptr = .pl_node,
|
||||
.union_init = .pl_node,
|
||||
.type_info = .un_node,
|
||||
.size_of = .un_node,
|
||||
.bit_size_of = .un_node,
|
||||
@ -2896,10 +2895,10 @@ pub const Inst = struct {
|
||||
ordering: Ref,
|
||||
};
|
||||
|
||||
pub const UnionInitPtr = struct {
|
||||
result_ptr: Ref,
|
||||
pub const UnionInit = struct {
|
||||
union_type: Ref,
|
||||
field_name: Ref,
|
||||
init: Ref,
|
||||
};
|
||||
|
||||
pub const AtomicStore = struct {
|
||||
|
||||
@ -625,7 +625,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.tag_name => try self.airTagName(inst),
|
||||
.error_name => try self.airErrorName(inst),
|
||||
.splat => try self.airSplat(inst),
|
||||
.vector_init => try self.airVectorInit(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
.prefetch => try self.airPrefetch(inst),
|
||||
|
||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||
@ -3472,14 +3473,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const vector_ty = self.air.typeOfIndex(inst);
|
||||
const len = vector_ty.vectorLen();
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
const result: MCValue = res: {
|
||||
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
|
||||
return self.fail("TODO implement airVectorInit for {}", .{self.target.cpu.arch});
|
||||
return self.fail("TODO implement airAggregateInit for {}", .{self.target.cpu.arch});
|
||||
};
|
||||
|
||||
if (elements.len <= Liveness.bpi - 1) {
|
||||
@ -3494,6 +3495,13 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return bt.finishAir(result);
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
_ = extra;
|
||||
return self.fail("TODO implement airUnionInit for aarch64", .{});
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
|
||||
|
||||
@ -609,7 +609,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.tag_name => try self.airTagName(inst),
|
||||
.error_name => try self.airErrorName(inst),
|
||||
.splat => try self.airSplat(inst),
|
||||
.vector_init => try self.airVectorInit(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
.prefetch => try self.airPrefetch(inst),
|
||||
|
||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||
@ -3937,14 +3938,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const vector_ty = self.air.typeOfIndex(inst);
|
||||
const len = vector_ty.vectorLen();
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
const result: MCValue = res: {
|
||||
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
|
||||
return self.fail("TODO implement airVectorInit for arm", .{});
|
||||
return self.fail("TODO implement airAggregateInit for arm", .{});
|
||||
};
|
||||
|
||||
if (elements.len <= Liveness.bpi - 1) {
|
||||
@ -3959,6 +3960,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return bt.finishAir(result);
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
_ = extra;
|
||||
|
||||
return self.fail("TODO implement airUnionInit for arm", .{});
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
|
||||
|
||||
@ -596,7 +596,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.tag_name => try self.airTagName(inst),
|
||||
.error_name => try self.airErrorName(inst),
|
||||
.splat => try self.airSplat(inst),
|
||||
.vector_init => try self.airVectorInit(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
.prefetch => try self.airPrefetch(inst),
|
||||
|
||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||
@ -2157,14 +2158,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const vector_ty = self.air.typeOfIndex(inst);
|
||||
const len = vector_ty.vectorLen();
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
const result: MCValue = res: {
|
||||
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
|
||||
return self.fail("TODO implement airVectorInit for riscv64", .{});
|
||||
return self.fail("TODO implement airAggregateInit for riscv64", .{});
|
||||
};
|
||||
|
||||
if (elements.len <= Liveness.bpi - 1) {
|
||||
@ -2179,6 +2180,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return bt.finishAir(result);
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
_ = extra;
|
||||
return self.fail("TODO implement airUnionInit for riscv64", .{});
|
||||
// return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
|
||||
|
||||
@ -1642,7 +1642,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
.ret_ptr => self.airRetPtr(inst),
|
||||
.ret_load => self.airRetLoad(inst),
|
||||
.splat => self.airSplat(inst),
|
||||
.vector_init => self.airVectorInit(inst),
|
||||
.aggregate_init => self.airAggregateInit(inst),
|
||||
.union_init => self.airUnionInit(inst),
|
||||
.prefetch => self.airPrefetch(inst),
|
||||
|
||||
.slice => self.airSlice(inst),
|
||||
@ -3350,7 +3351,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
return self.fail("TODO: Implement wasm airSplat", .{});
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
|
||||
|
||||
const vector_ty = self.air.typeOfIndex(inst);
|
||||
@ -3359,7 +3360,7 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
|
||||
switch (vector_ty.zigTypeTag()) {
|
||||
.Vector => return self.fail("TODO: Wasm backend: implement airVectorInit for vectors", .{}),
|
||||
.Vector => return self.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
|
||||
.Array => {
|
||||
const result = try self.allocStack(vector_ty);
|
||||
const elem_ty = vector_ty.childType();
|
||||
@ -3413,6 +3414,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
}
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
|
||||
return self.fail("TODO: Wasm backend: implement airUnionInit", .{});
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
_ = prefetch;
|
||||
|
||||
@ -708,7 +708,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
.tag_name => try self.airTagName(inst),
|
||||
.error_name => try self.airErrorName(inst),
|
||||
.splat => try self.airSplat(inst),
|
||||
.vector_init => try self.airVectorInit(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
.prefetch => try self.airPrefetch(inst),
|
||||
|
||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||
@ -5232,14 +5233,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const vector_ty = self.air.typeOfIndex(inst);
|
||||
const len = vector_ty.vectorLen();
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
|
||||
const result: MCValue = res: {
|
||||
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
|
||||
return self.fail("TODO implement airVectorInit for x86_64", .{});
|
||||
return self.fail("TODO implement airAggregateInit for x86_64", .{});
|
||||
};
|
||||
|
||||
if (elements.len <= Liveness.bpi - 1) {
|
||||
@ -5254,6 +5255,16 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return bt.finishAir(result);
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
const result: MCValue = res: {
|
||||
if (self.liveness.isUnused(inst)) break :res MCValue.dead;
|
||||
return self.fail("TODO implement airAggregateInit for x86_64", .{});
|
||||
};
|
||||
return self.finishAir(inst, result, .{ extra.init, .none, .none });
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
|
||||
|
||||
@ -1713,7 +1713,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
||||
.tag_name => try airTagName(f, inst),
|
||||
.error_name => try airErrorName(f, inst),
|
||||
.splat => try airSplat(f, inst),
|
||||
.vector_init => try airVectorInit(f, inst),
|
||||
.aggregate_init => try airAggregateInit(f, inst),
|
||||
.union_init => try airUnionInit(f, inst),
|
||||
.prefetch => try airPrefetch(f, inst),
|
||||
|
||||
.int_to_float,
|
||||
@ -3526,7 +3527,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
return f.fail("TODO: C backend: implement airSplat", .{});
|
||||
}
|
||||
|
||||
fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
if (f.liveness.isUnused(inst)) return CValue.none;
|
||||
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
@ -3541,7 +3542,22 @@ fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
|
||||
_ = elements;
|
||||
_ = local;
|
||||
return f.fail("TODO: C backend: implement airVectorInit", .{});
|
||||
return f.fail("TODO: C backend: implement airAggregateInit", .{});
|
||||
}
|
||||
|
||||
fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
if (f.liveness.isUnused(inst)) return CValue.none;
|
||||
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
|
||||
|
||||
const writer = f.object.writer();
|
||||
const local = try f.allocLocal(inst_ty, .Const);
|
||||
try writer.writeAll(" = ");
|
||||
|
||||
_ = local;
|
||||
_ = ty_pl;
|
||||
return f.fail("TODO: C backend: implement airUnionInit", .{});
|
||||
}
|
||||
|
||||
fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
|
||||
@ -2175,7 +2175,8 @@ pub const FuncGen = struct {
|
||||
.tag_name => try self.airTagName(inst),
|
||||
.error_name => try self.airErrorName(inst),
|
||||
.splat => try self.airSplat(inst),
|
||||
.vector_init => try self.airVectorInit(inst),
|
||||
.aggregate_init => try self.airAggregateInit(inst),
|
||||
.union_init => try self.airUnionInit(inst),
|
||||
.prefetch => try self.airPrefetch(inst),
|
||||
|
||||
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
|
||||
@ -4608,7 +4609,7 @@ pub const FuncGen = struct {
|
||||
return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");
|
||||
}
|
||||
|
||||
fn airVectorInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
@ -4693,6 +4694,109 @@ pub const FuncGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
const union_ty = self.air.typeOfIndex(inst);
|
||||
const union_llvm_ty = try self.dg.llvmType(union_ty);
|
||||
const target = self.dg.module.getTarget();
|
||||
const layout = union_ty.unionGetLayout(target);
|
||||
if (layout.payload_size == 0) {
|
||||
if (layout.tag_size == 0) {
|
||||
return null;
|
||||
}
|
||||
assert(!isByRef(union_ty));
|
||||
return union_llvm_ty.constInt(extra.field_index, .False);
|
||||
}
|
||||
assert(isByRef(union_ty));
|
||||
// The llvm type of the alloca will the the named LLVM union type, which will not
|
||||
// necessarily match the format that we need, depending on which tag is active. We
|
||||
// must construct the correct unnamed struct type here and bitcast, in order to
|
||||
// then set the fields appropriately.
|
||||
const result_ptr = self.buildAlloca(union_llvm_ty);
|
||||
const llvm_payload = try self.resolveInst(extra.init);
|
||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
||||
assert(union_obj.haveFieldTypes());
|
||||
const field = union_obj.fields.values()[extra.field_index];
|
||||
const field_llvm_ty = try self.dg.llvmType(field.ty);
|
||||
const tag_llvm_ty = try self.dg.llvmType(union_obj.tag_ty);
|
||||
const field_size = field.ty.abiSize(target);
|
||||
const field_align = field.normalAlignment(target);
|
||||
|
||||
const llvm_union_ty = t: {
|
||||
const payload = p: {
|
||||
if (!field.ty.hasRuntimeBits()) {
|
||||
const padding_len = @intCast(c_uint, layout.payload_size);
|
||||
break :p self.context.intType(8).arrayType(padding_len);
|
||||
}
|
||||
if (field_size == layout.payload_size) {
|
||||
break :p field_llvm_ty;
|
||||
}
|
||||
const padding_len = @intCast(c_uint, layout.payload_size - field_size);
|
||||
const fields: [2]*const llvm.Type = .{
|
||||
field_llvm_ty, self.context.intType(8).arrayType(padding_len),
|
||||
};
|
||||
break :p self.context.structType(&fields, fields.len, .False);
|
||||
};
|
||||
if (layout.tag_size == 0) {
|
||||
const fields: [1]*const llvm.Type = .{payload};
|
||||
break :t self.context.structType(&fields, fields.len, .False);
|
||||
}
|
||||
var fields: [2]*const llvm.Type = undefined;
|
||||
if (layout.tag_align >= layout.payload_align) {
|
||||
fields = .{ tag_llvm_ty, payload };
|
||||
} else {
|
||||
fields = .{ payload, tag_llvm_ty };
|
||||
}
|
||||
break :t self.context.structType(&fields, fields.len, .False);
|
||||
};
|
||||
|
||||
const casted_ptr = self.builder.buildBitCast(result_ptr, llvm_union_ty.pointerType(0), "");
|
||||
|
||||
// Now we follow the layout as expressed above with GEP instructions to set the
|
||||
// tag and the payload.
|
||||
const index_type = self.context.intType(32);
|
||||
|
||||
if (layout.tag_size == 0) {
|
||||
const indices: [3]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constNull(),
|
||||
index_type.constNull(),
|
||||
};
|
||||
const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
|
||||
const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, len, "");
|
||||
const store_inst = self.builder.buildStore(llvm_payload, field_ptr);
|
||||
store_inst.setAlignment(field_align);
|
||||
return result_ptr;
|
||||
}
|
||||
|
||||
{
|
||||
const indices: [3]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constInt(@boolToInt(layout.tag_align >= layout.payload_align), .False),
|
||||
index_type.constNull(),
|
||||
};
|
||||
const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
|
||||
const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, len, "");
|
||||
const store_inst = self.builder.buildStore(llvm_payload, field_ptr);
|
||||
store_inst.setAlignment(field_align);
|
||||
}
|
||||
{
|
||||
const indices: [2]*const llvm.Value = .{
|
||||
index_type.constNull(),
|
||||
index_type.constInt(@boolToInt(layout.tag_align < layout.payload_align), .False),
|
||||
};
|
||||
const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, "");
|
||||
const llvm_tag = union_llvm_ty.constInt(extra.field_index, .False);
|
||||
const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
|
||||
store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));
|
||||
}
|
||||
|
||||
return result_ptr;
|
||||
}
|
||||
|
||||
fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
const prefetch = self.air.instructions.items(.data)[inst].prefetch;
|
||||
|
||||
|
||||
@ -232,7 +232,8 @@ const Writer = struct {
|
||||
.assembly => try w.writeAssembly(s, inst),
|
||||
.dbg_stmt => try w.writeDbgStmt(s, inst),
|
||||
.call => try w.writeCall(s, inst),
|
||||
.vector_init => try w.writeVectorInit(s, inst),
|
||||
.aggregate_init => try w.writeAggregateInit(s, inst),
|
||||
.union_init => try w.writeUnionInit(s, inst),
|
||||
.br => try w.writeBr(s, inst),
|
||||
.cond_br => try w.writeCondBr(s, inst),
|
||||
.switch_br => try w.writeSwitchBr(s, inst),
|
||||
@ -301,7 +302,7 @@ const Writer = struct {
|
||||
try s.writeAll("}");
|
||||
}
|
||||
|
||||
fn writeVectorInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const vector_ty = w.air.getRefType(ty_pl.ty);
|
||||
const len = @intCast(usize, vector_ty.arrayLen());
|
||||
@ -315,6 +316,14 @@ const Writer = struct {
|
||||
try s.writeAll("]");
|
||||
}
|
||||
|
||||
fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
|
||||
|
||||
try s.print("{d}, ", .{extra.field_index});
|
||||
try w.writeOperand(s, inst, 0, extra.init);
|
||||
}
|
||||
|
||||
fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
|
||||
|
||||
@ -273,7 +273,7 @@ const Writer = struct {
|
||||
.slice_end => try self.writeSliceEnd(stream, inst),
|
||||
.slice_sentinel => try self.writeSliceSentinel(stream, inst),
|
||||
|
||||
.union_init_ptr => try self.writeUnionInitPtr(stream, inst),
|
||||
.union_init => try self.writeUnionInit(stream, inst),
|
||||
|
||||
.struct_init,
|
||||
.struct_init_ref,
|
||||
@ -692,14 +692,14 @@ const Writer = struct {
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeUnionInitPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
fn writeUnionInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = self.code.extraData(Zir.Inst.UnionInitPtr, inst_data.payload_index).data;
|
||||
try self.writeInstRef(stream, extra.result_ptr);
|
||||
try stream.writeAll(", ");
|
||||
const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
|
||||
try self.writeInstRef(stream, extra.union_type);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.field_name);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.init);
|
||||
try stream.writeAll(") ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
@ -785,8 +785,40 @@ test "return union init with void payload" {
|
||||
comptime try S.entry();
|
||||
}
|
||||
|
||||
test "@unionInit stored to a const" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
const U = union(enum) {
|
||||
boolean: bool,
|
||||
byte: u8,
|
||||
};
|
||||
fn doTheTest() !void {
|
||||
{
|
||||
var t = true;
|
||||
const u = @unionInit(U, "boolean", t);
|
||||
try expect(u.boolean);
|
||||
}
|
||||
{
|
||||
var byte: u8 = 69;
|
||||
const u = @unionInit(U, "byte", byte);
|
||||
try expect(u.byte == 69);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
comptime try S.doTheTest();
|
||||
try S.doTheTest();
|
||||
}
|
||||
|
||||
test "@unionInit can modify a union type" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const UnionInitEnum = union(enum) {
|
||||
Boolean: bool,
|
||||
@ -807,7 +839,9 @@ test "@unionInit can modify a union type" {
|
||||
}
|
||||
|
||||
test "@unionInit can modify a pointer value" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const UnionInitEnum = union(enum) {
|
||||
Boolean: bool,
|
||||
@ -825,7 +859,9 @@ test "@unionInit can modify a pointer value" {
|
||||
}
|
||||
|
||||
test "union no tag with struct member" {
|
||||
if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const Struct = struct {};
|
||||
const Union = union {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user