authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-26 20:59:36-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-26 20:59:36-07:00
log2687b8f7f4825c9018af6998e1de140e6185f9cd
tree4bbd5f609153618e883ad4cce09c7a8c920a22b0
parent32e89a98d82c0f4505a3f3d4cd72e7db2eadfbb9

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.

16 files changed, 370 insertions(+), 110 deletions(-)

src/Air.zig+13-5
...@@ -561,13 +561,15 @@ pub const Inst = struct {...@@ -561,13 +561,15 @@ pub const Inst = struct {
561 /// Uses the `un_op` field.561 /// Uses the `un_op` field.
562 error_name,562 error_name,
563563
564 /// Constructs a vector, tuple, or array value out of runtime-known elements.564 /// Constructs a vector, tuple, struct, or array value out of runtime-known elements.
565 /// Some of the elements may be comptime-known.565 /// Some of the elements may be comptime-known.
566 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which566 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which
567 /// is a `Ref`. Length of the array is given by the vector type.567 /// is a `Ref`. Length of the array is given by the vector type.
568 /// TODO rename this to `aggregate_init` and make it support array values and568 aggregate_init,
569 /// struct values too.569
570 vector_init,570 /// Constructs a union from a field index and a runtime-known init value.
571 /// Uses the `ty_pl` field with payload `UnionInit`.
572 union_init,
571573
572 /// Communicates an intent to load memory.574 /// Communicates an intent to load memory.
573 /// Result is always unused.575 /// Result is always unused.
...@@ -768,6 +770,11 @@ pub const AtomicRmw = struct {...@@ -768,6 +770,11 @@ pub const AtomicRmw = struct {
768 }770 }
769};771};
770772
773pub const UnionInit = struct {
774 field_index: u32,
775 init: Inst.Ref,
776};
777
771pub fn getMainBody(air: Air) []const Air.Inst.Index {778pub fn getMainBody(air: Air) []const Air.Inst.Index {
772 const body_index = air.extra[@enumToInt(ExtraIndex.main_block)];779 const body_index = air.extra[@enumToInt(ExtraIndex.main_block)];
773 const extra = air.extraData(Block, body_index);780 const extra = air.extraData(Block, body_index);
...@@ -864,7 +871,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -864,7 +871,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
864 .cmpxchg_weak,871 .cmpxchg_weak,
865 .cmpxchg_strong,872 .cmpxchg_strong,
866 .slice,873 .slice,
867 .vector_init,874 .aggregate_init,
875 .union_init,
868 .field_parent_ptr,876 .field_parent_ptr,
869 => return air.getRefType(datas[inst].ty_pl.ty),877 => return air.getRefType(datas[inst].ty_pl.ty),
870878
src/AstGen.zig+11-34
...@@ -2052,8 +2052,8 @@ fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Sc...@@ -2052,8 +2052,8 @@ fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Sc
2052 _ = try unusedResultExpr(gz, expr_scope, expr_node);2052 _ = try unusedResultExpr(gz, expr_scope, expr_node);
2053}2053}
20542054
2055/// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`.2055/// Returns AST source node of the thing that is noreturn if the statement is
2056/// Otherwise returns 0.2056/// definitely `noreturn`. Otherwise returns 0.
2057fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index {2057fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index {
2058 try emitDbgNode(gz, statement);2058 try emitDbgNode(gz, statement);
2059 // We need to emit an error if the result is not `noreturn` or `void`, but2059 // 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...@@ -2201,7 +2201,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2201 .array_init_anon,2201 .array_init_anon,
2202 .array_init_ref,2202 .array_init_ref,
2203 .array_init_anon_ref,2203 .array_init_anon_ref,
2204 .union_init_ptr,2204 .union_init,
2205 .field_type,2205 .field_type,
2206 .field_type_ref,2206 .field_type_ref,
2207 .error_set_decl,2207 .error_set_decl,
...@@ -6802,40 +6802,17 @@ fn unionInit(...@@ -6802,40 +6802,17 @@ fn unionInit(
6802) InnerError!Zir.Inst.Ref {6802) InnerError!Zir.Inst.Ref {
6803 const union_type = try typeExpr(gz, scope, params[0]);6803 const union_type = try typeExpr(gz, scope, params[0]);
6804 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);6804 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
6805 switch (rl) {6805 const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
6806 .none, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {6806 .container_type = union_type,
6807 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{6807 .field_name = field_name,
6808 .container_type = union_type,6808 });
6809 .field_name = field_name,6809 const init = try reachableExpr(gz, scope, .{ .ty = field_type }, params[2], node);
6810 });6810 const result = try gz.addPlNode(.union_init, node, Zir.Inst.UnionInit{
6811 const result = try expr(gz, scope, .{ .ty = union_type }, params[2]);
6812 return rvalue(gz, rl, result, node);
6813 },
6814 .ptr => |result_ptr| {
6815 return unionInitRlPtr(gz, scope, node, result_ptr, params[2], union_type, field_name);
6816 },
6817 .block_ptr => |block_scope| {
6818 return unionInitRlPtr(gz, scope, node, block_scope.rl_ptr, params[2], union_type, field_name);
6819 },
6820 }
6821}
6822
6823fn unionInitRlPtr(
6824 parent_gz: *GenZir,
6825 scope: *Scope,
6826 node: Ast.Node.Index,
6827 result_ptr: Zir.Inst.Ref,
6828 expr_node: Ast.Node.Index,
6829 union_type: Zir.Inst.Ref,
6830 field_name: Zir.Inst.Ref,
6831) InnerError!Zir.Inst.Ref {
6832 const union_init_ptr = try parent_gz.addPlNode(.union_init_ptr, node, Zir.Inst.UnionInitPtr{
6833 .result_ptr = result_ptr,
6834 .union_type = union_type,6811 .union_type = union_type,
6812 .init = init,
6835 .field_name = field_name,6813 .field_name = field_name,
6836 });6814 });
6837 // TODO check if we need to do the elision like below in asRlPtr6815 return rvalue(gz, rl, result, node);
6838 return expr(parent_gz, scope, .{ .ptr = union_init_ptr }, expr_node);
6839}6816}
68406817
6841fn asRlPtr(6818fn asRlPtr(
src/Liveness.zig+8-4
...@@ -25,7 +25,7 @@ tomb_bits: []usize,...@@ -25,7 +25,7 @@ tomb_bits: []usize,
25/// array. The meaning of the data depends on the AIR tag.25/// array. The meaning of the data depends on the AIR tag.
26/// * `cond_br` - points to a `CondBr` in `extra` at this index.26/// * `cond_br` - points to a `CondBr` in `extra` at this index.
27/// * `switch_br` - points to a `SwitchBr` in `extra` at this index.27/// * `switch_br` - points to a `SwitchBr` in `extra` at this index.
28/// * `asm`, `call`, `vector_init` - the value is a set of bits which are the extra tomb28/// * `asm`, `call`, `aggregate_init` - the value is a set of bits which are the extra tomb
29/// bits of operands.29/// bits of operands.
30/// The main tomb bits are still used and the extra ones are starting with the lsb of the30/// The main tomb bits are still used and the extra ones are starting with the lsb of the
31/// value here.31/// value here.
...@@ -420,10 +420,10 @@ fn analyzeInst(...@@ -420,10 +420,10 @@ fn analyzeInst(
420 }420 }
421 return extra_tombs.finish();421 return extra_tombs.finish();
422 },422 },
423 .vector_init => {423 .aggregate_init => {
424 const ty_pl = inst_datas[inst].ty_pl;424 const ty_pl = inst_datas[inst].ty_pl;
425 const vector_ty = a.air.getRefType(ty_pl.ty);425 const aggregate_ty = a.air.getRefType(ty_pl.ty);
426 const len = @intCast(usize, vector_ty.arrayLen());426 const len = @intCast(usize, aggregate_ty.arrayLen());
427 const elements = @bitCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]);427 const elements = @bitCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]);
428428
429 if (elements.len <= bpi - 1) {429 if (elements.len <= bpi - 1) {
...@@ -442,6 +442,10 @@ fn analyzeInst(...@@ -442,6 +442,10 @@ fn analyzeInst(
442 }442 }
443 return extra_tombs.finish();443 return extra_tombs.finish();
444 },444 },
445 .union_init => {
446 const extra = a.air.extraData(Air.UnionInit, inst_datas[inst].ty_pl.payload).data;
447 return trackOperands(a, new_set, inst, main_tomb, .{ extra.init, .none, .none });
448 },
445 .struct_field_ptr, .struct_field_val => {449 .struct_field_ptr, .struct_field_val => {
446 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;450 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
447 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });451 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
src/Module.zig+9
...@@ -1123,6 +1123,15 @@ pub const Union = struct {...@@ -1123,6 +1123,15 @@ pub const Union = struct {
1123 /// undefined until `status` is `have_field_types` or `have_layout`.1123 /// undefined until `status` is `have_field_types` or `have_layout`.
1124 ty: Type,1124 ty: Type,
1125 abi_align: Value,1125 abi_align: Value,
1126
1127 /// Returns the field alignment, assuming the union is not packed.
1128 pub fn normalAlignment(field: Field, target: Target) u32 {
1129 if (field.abi_align.tag() == .abi_align_default) {
1130 return field.ty.abiAlignment(target);
1131 } else {
1132 return @intCast(u32, field.abi_align.toUnsignedInt());
1133 }
1134 }
1126 };1135 };
11271136
1128 pub const Fields = std.StringArrayHashMapUnmanaged(Field);1137 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
src/Sema.zig+84-29
...@@ -204,7 +204,7 @@ pub const Block = struct {...@@ -204,7 +204,7 @@ pub const Block = struct {
204 return block.namespace.file_scope;204 return block.namespace.file_scope;
205 }205 }
206206
207 pub fn addTy(207 fn addTy(
208 block: *Block,208 block: *Block,
209 tag: Air.Inst.Tag,209 tag: Air.Inst.Tag,
210 ty: Type,210 ty: Type,
...@@ -215,7 +215,7 @@ pub const Block = struct {...@@ -215,7 +215,7 @@ pub const Block = struct {
215 });215 });
216 }216 }
217217
218 pub fn addTyOp(218 fn addTyOp(
219 block: *Block,219 block: *Block,
220 tag: Air.Inst.Tag,220 tag: Air.Inst.Tag,
221 ty: Type,221 ty: Type,
...@@ -230,7 +230,7 @@ pub const Block = struct {...@@ -230,7 +230,7 @@ pub const Block = struct {
230 });230 });
231 }231 }
232232
233 pub fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {233 fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref {
234 return block.addInst(.{234 return block.addInst(.{
235 .tag = .bitcast,235 .tag = .bitcast,
236 .data = .{ .ty_op = .{236 .data = .{ .ty_op = .{
...@@ -240,14 +240,14 @@ pub const Block = struct {...@@ -240,14 +240,14 @@ pub const Block = struct {
240 });240 });
241 }241 }
242242
243 pub fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {243 fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref {
244 return block.addInst(.{244 return block.addInst(.{
245 .tag = tag,245 .tag = tag,
246 .data = .{ .no_op = {} },246 .data = .{ .no_op = {} },
247 });247 });
248 }248 }
249249
250 pub fn addUnOp(250 fn addUnOp(
251 block: *Block,251 block: *Block,
252 tag: Air.Inst.Tag,252 tag: Air.Inst.Tag,
253 operand: Air.Inst.Ref,253 operand: Air.Inst.Ref,
...@@ -258,7 +258,7 @@ pub const Block = struct {...@@ -258,7 +258,7 @@ pub const Block = struct {
258 });258 });
259 }259 }
260260
261 pub fn addBr(261 fn addBr(
262 block: *Block,262 block: *Block,
263 target_block: Air.Inst.Index,263 target_block: Air.Inst.Index,
264 operand: Air.Inst.Ref,264 operand: Air.Inst.Ref,
...@@ -328,7 +328,7 @@ pub const Block = struct {...@@ -328,7 +328,7 @@ pub const Block = struct {
328 });328 });
329 }329 }
330330
331 pub fn addStructFieldVal(331 fn addStructFieldVal(
332 block: *Block,332 block: *Block,
333 struct_val: Air.Inst.Ref,333 struct_val: Air.Inst.Ref,
334 field_index: u32,334 field_index: u32,
...@@ -346,7 +346,7 @@ pub const Block = struct {...@@ -346,7 +346,7 @@ pub const Block = struct {
346 });346 });
347 }347 }
348348
349 pub fn addSliceElemPtr(349 fn addSliceElemPtr(
350 block: *Block,350 block: *Block,
351 slice: Air.Inst.Ref,351 slice: Air.Inst.Ref,
352 elem_index: Air.Inst.Ref,352 elem_index: Air.Inst.Ref,
...@@ -364,7 +364,7 @@ pub const Block = struct {...@@ -364,7 +364,7 @@ pub const Block = struct {
364 });364 });
365 }365 }
366366
367 pub fn addPtrElemPtr(367 fn addPtrElemPtr(
368 block: *Block,368 block: *Block,
369 array_ptr: Air.Inst.Ref,369 array_ptr: Air.Inst.Ref,
370 elem_index: Air.Inst.Ref,370 elem_index: Air.Inst.Ref,
...@@ -374,7 +374,7 @@ pub const Block = struct {...@@ -374,7 +374,7 @@ pub const Block = struct {
374 return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref);374 return block.addPtrElemPtrTypeRef(array_ptr, elem_index, ty_ref);
375 }375 }
376376
377 pub fn addPtrElemPtrTypeRef(377 fn addPtrElemPtrTypeRef(
378 block: *Block,378 block: *Block,
379 array_ptr: Air.Inst.Ref,379 array_ptr: Air.Inst.Ref,
380 elem_index: Air.Inst.Ref,380 elem_index: Air.Inst.Ref,
...@@ -392,7 +392,7 @@ pub const Block = struct {...@@ -392,7 +392,7 @@ pub const Block = struct {
392 });392 });
393 }393 }
394394
395 pub fn addVectorInit(395 fn addAggregateInit(
396 block: *Block,396 block: *Block,
397 vector_ty: Type,397 vector_ty: Type,
398 elements: []const Air.Inst.Ref,398 elements: []const Air.Inst.Ref,
...@@ -404,7 +404,7 @@ pub const Block = struct {...@@ -404,7 +404,7 @@ pub const Block = struct {
404 sema.appendRefsAssumeCapacity(elements);404 sema.appendRefsAssumeCapacity(elements);
405405
406 return block.addInst(.{406 return block.addInst(.{
407 .tag = .vector_init,407 .tag = .aggregate_init,
408 .data = .{ .ty_pl = .{408 .data = .{ .ty_pl = .{
409 .ty = ty_ref,409 .ty = ty_ref,
410 .payload = extra_index,410 .payload = extra_index,
...@@ -412,6 +412,24 @@ pub const Block = struct {...@@ -412,6 +412,24 @@ pub const Block = struct {
412 });412 });
413 }413 }
414414
415 fn addUnionInit(
416 block: *Block,
417 union_ty: Type,
418 field_index: u32,
419 init: Air.Inst.Ref,
420 ) !Air.Inst.Ref {
421 return block.addInst(.{
422 .tag = .union_init,
423 .data = .{ .ty_pl = .{
424 .ty = try block.sema.addType(union_ty),
425 .payload = try block.sema.addExtra(Air.UnionInit{
426 .field_index = field_index,
427 .init = init,
428 }),
429 } },
430 });
431 }
432
415 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {433 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
416 return Air.indexToRef(try block.addInstAsIndex(inst));434 return Air.indexToRef(try block.addInstAsIndex(inst));
417 }435 }
...@@ -697,7 +715,7 @@ fn analyzeBodyInner(...@@ -697,7 +715,7 @@ fn analyzeBodyInner(
697 .array_init_ref => try sema.zirArrayInit(block, inst, true),715 .array_init_ref => try sema.zirArrayInit(block, inst, true),
698 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),716 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
699 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),717 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
700 .union_init_ptr => try sema.zirUnionInitPtr(block, inst),718 .union_init => try sema.zirUnionInit(block, inst),
701 .field_type => try sema.zirFieldType(block, inst),719 .field_type => try sema.zirFieldType(block, inst),
702 .field_type_ref => try sema.zirFieldTypeRef(block, inst),720 .field_type_ref => try sema.zirFieldTypeRef(block, inst),
703 .ptr_to_int => try sema.zirPtrToInt(block, inst),721 .ptr_to_int => try sema.zirPtrToInt(block, inst),
...@@ -11273,10 +11291,31 @@ fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {...@@ -11273,10 +11291,31 @@ fn arrayInitEmpty(sema: *Sema, obj_ty: Type) CompileError!Air.Inst.Ref {
11273 }11291 }
11274}11292}
1127511293
11276fn zirUnionInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11294fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11277 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;11295 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11278 const src = inst_data.src();11296 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11279 return sema.fail(block, src, "TODO: Sema.zirUnionInitPtr", .{});11297 const field_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
11298 const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
11299 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
11300 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
11301 const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
11302 const init = sema.resolveInst(extra.init);
11303 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
11304 const field_index_usize = union_obj.fields.getIndex(field_name) orelse
11305 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
11306 const field_index = @intCast(u32, field_index_usize);
11307
11308 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
11309 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
11310 return sema.addConstant(
11311 union_ty,
11312 try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = init_val }),
11313 );
11314 }
11315
11316 try sema.requireRuntimeBlock(block, init_src);
11317 try sema.resolveTypeLayout(block, ty_src, union_ty);
11318 return block.addUnionInit(union_ty, field_index, init);
11280}11319}
1128111320
11282fn zirStructInit(11321fn zirStructInit(
...@@ -11447,7 +11486,7 @@ fn finishStructInit(...@@ -11447,7 +11486,7 @@ fn finishStructInit(
11447 }11486 }
1144811487
11449 try sema.requireRuntimeBlock(block, src);11488 try sema.requireRuntimeBlock(block, src);
11450 return block.addVectorInit(struct_ty, field_inits);11489 return block.addAggregateInit(struct_ty, field_inits);
11451}11490}
1145211491
11453fn zirStructInitAnon(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {11492fn zirStructInitAnon(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
...@@ -11527,7 +11566,7 @@ fn zirArrayInit(...@@ -11527,7 +11566,7 @@ fn zirArrayInit(
11527 return alloc;11566 return alloc;
11528 }11567 }
1152911568
11530 return block.addVectorInit(array_ty, resolved_args);11569 return block.addAggregateInit(array_ty, resolved_args);
11531}11570}
1153211571
11533fn zirArrayInitAnon(11572fn zirArrayInitAnon(
...@@ -11593,7 +11632,7 @@ fn zirArrayInitAnon(...@@ -11593,7 +11632,7 @@ fn zirArrayInitAnon(
11593 element_refs[i] = sema.resolveInst(operand);11632 element_refs[i] = sema.resolveInst(operand);
11594 }11633 }
1159511634
11596 return block.addVectorInit(tuple_ty, element_refs);11635 return block.addAggregateInit(tuple_ty, element_refs);
11597}11636}
1159811637
11599fn addConstantMaybeRef(11638fn addConstantMaybeRef(
...@@ -11617,31 +11656,47 @@ fn addConstantMaybeRef(...@@ -11617,31 +11656,47 @@ fn addConstantMaybeRef(
1161711656
11618fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11657fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11619 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;11658 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11620 const src = inst_data.src();11659 const extra = sema.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
11621 return sema.fail(block, src, "TODO: Sema.zirFieldTypeRef", .{});11660 const ty_src = inst_data.src();
11661 const field_src = inst_data.src();
11662 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
11663 const field_name = try sema.resolveConstString(block, field_src, extra.field_name);
11664 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
11622}11665}
1162311666
11624fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11667fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11625 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;11668 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11626 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;11669 const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
11627 const src = inst_data.src();11670 const ty_src = inst_data.src();
11671 const field_src = inst_data.src();
11672 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
11628 const field_name = sema.code.nullTerminatedString(extra.name_start);11673 const field_name = sema.code.nullTerminatedString(extra.name_start);
11629 const unresolved_ty = try sema.resolveType(block, src, extra.container_type);11674 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
11630 const resolved_ty = try sema.resolveTypeFields(block, src, unresolved_ty);11675}
11676
11677fn fieldType(
11678 sema: *Sema,
11679 block: *Block,
11680 aggregate_ty: Type,
11681 field_name: []const u8,
11682 field_src: LazySrcLoc,
11683 ty_src: LazySrcLoc,
11684) CompileError!Air.Inst.Ref {
11685 const resolved_ty = try sema.resolveTypeFields(block, ty_src, aggregate_ty);
11631 switch (resolved_ty.zigTypeTag()) {11686 switch (resolved_ty.zigTypeTag()) {
11632 .Struct => {11687 .Struct => {
11633 const struct_obj = resolved_ty.castTag(.@"struct").?.data;11688 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
11634 const field = struct_obj.fields.get(field_name) orelse11689 const field = struct_obj.fields.get(field_name) orelse
11635 return sema.failWithBadStructFieldAccess(block, struct_obj, src, field_name);11690 return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
11636 return sema.addType(field.ty);11691 return sema.addType(field.ty);
11637 },11692 },
11638 .Union => {11693 .Union => {
11639 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;11694 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
11640 const field = union_obj.fields.get(field_name) orelse11695 const field = union_obj.fields.get(field_name) orelse
11641 return sema.failWithBadUnionFieldAccess(block, union_obj, src, field_name);11696 return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
11642 return sema.addType(field.ty);11697 return sema.addType(field.ty);
11643 },11698 },
11644 else => return sema.fail(block, src, "expected struct or union; found '{}'", .{11699 else => return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{
11645 resolved_ty,11700 resolved_ty,
11646 }),11701 }),
11647 }11702 }
...@@ -16396,7 +16451,7 @@ fn coerceArrayLike(...@@ -16396,7 +16451,7 @@ fn coerceArrayLike(
1639616451
16397 if (runtime_src) |rs| {16452 if (runtime_src) |rs| {
16398 try sema.requireRuntimeBlock(block, rs);16453 try sema.requireRuntimeBlock(block, rs);
16399 return block.addVectorInit(dest_ty, element_refs);16454 return block.addAggregateInit(dest_ty, element_refs);
16400 }16455 }
1640116456
16402 return sema.addConstant(16457 return sema.addConstant(
...@@ -16453,7 +16508,7 @@ fn coerceTupleToArray(...@@ -16453,7 +16508,7 @@ fn coerceTupleToArray(
1645316508
16454 if (runtime_src) |rs| {16509 if (runtime_src) |rs| {
16455 try sema.requireRuntimeBlock(block, rs);16510 try sema.requireRuntimeBlock(block, rs);
16456 return block.addVectorInit(dest_ty, element_refs);16511 return block.addAggregateInit(dest_ty, element_refs);
16457 }16512 }
1645816513
16459 return sema.addConstant(16514 return sema.addConstant(
src/Zir.zig+7-8
...@@ -721,10 +721,9 @@ pub const Inst = struct {...@@ -721,10 +721,9 @@ pub const Inst = struct {
721 /// Anonymous array initialization syntax, make the result a pointer.721 /// Anonymous array initialization syntax, make the result a pointer.
722 /// Uses the `pl_node` field. Payload is `MultiOp`.722 /// Uses the `pl_node` field. Payload is `MultiOp`.
723 array_init_anon_ref,723 array_init_anon_ref,
724 /// Given a pointer to a union and a comptime known field name, activates that field724 /// Implements the `@unionInit` builtin.
725 /// and returns a pointer to it.725 /// Uses the `pl_node` field. Payload is `UnionInit`.
726 /// Uses the `pl_node` field. Payload is `UnionInitPtr`.726 union_init,
727 union_init_ptr,
728 /// Implements the `@typeInfo` builtin. Uses `un_node`.727 /// Implements the `@typeInfo` builtin. Uses `un_node`.
729 type_info,728 type_info,
730 /// Implements the `@sizeOf` builtin. Uses `un_node`.729 /// Implements the `@sizeOf` builtin. Uses `un_node`.
...@@ -1125,7 +1124,7 @@ pub const Inst = struct {...@@ -1125,7 +1124,7 @@ pub const Inst = struct {
1125 .array_init_anon,1124 .array_init_anon,
1126 .array_init_ref,1125 .array_init_ref,
1127 .array_init_anon_ref,1126 .array_init_anon_ref,
1128 .union_init_ptr,1127 .union_init,
1129 .field_type,1128 .field_type,
1130 .field_type_ref,1129 .field_type_ref,
1131 .int_to_enum,1130 .int_to_enum,
...@@ -1383,7 +1382,7 @@ pub const Inst = struct {...@@ -1383,7 +1382,7 @@ pub const Inst = struct {
1383 .array_init_anon = .pl_node,1382 .array_init_anon = .pl_node,
1384 .array_init_ref = .pl_node,1383 .array_init_ref = .pl_node,
1385 .array_init_anon_ref = .pl_node,1384 .array_init_anon_ref = .pl_node,
1386 .union_init_ptr = .pl_node,1385 .union_init = .pl_node,
1387 .type_info = .un_node,1386 .type_info = .un_node,
1388 .size_of = .un_node,1387 .size_of = .un_node,
1389 .bit_size_of = .un_node,1388 .bit_size_of = .un_node,
...@@ -2896,10 +2895,10 @@ pub const Inst = struct {...@@ -2896,10 +2895,10 @@ pub const Inst = struct {
2896 ordering: Ref,2895 ordering: Ref,
2897 };2896 };
28982897
2899 pub const UnionInitPtr = struct {2898 pub const UnionInit = struct {
2900 result_ptr: Ref,
2901 union_type: Ref,2899 union_type: Ref,
2902 field_name: Ref,2900 field_name: Ref,
2901 init: Ref,
2903 };2902 };
29042903
2905 pub const AtomicStore = struct {2904 pub const AtomicStore = struct {
src/arch/aarch64/CodeGen.zig+11-3
...@@ -625,7 +625,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -625,7 +625,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
625 .tag_name => try self.airTagName(inst),625 .tag_name => try self.airTagName(inst),
626 .error_name => try self.airErrorName(inst),626 .error_name => try self.airErrorName(inst),
627 .splat => try self.airSplat(inst),627 .splat => try self.airSplat(inst),
628 .vector_init => try self.airVectorInit(inst),628 .aggregate_init => try self.airAggregateInit(inst),
629 .union_init => try self.airUnionInit(inst),
629 .prefetch => try self.airPrefetch(inst),630 .prefetch => try self.airPrefetch(inst),
630631
631 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),632 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
...@@ -3472,14 +3473,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3472,14 +3473,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
3472 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3473 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3473}3474}
34743475
3475fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {3476fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
3476 const vector_ty = self.air.typeOfIndex(inst);3477 const vector_ty = self.air.typeOfIndex(inst);
3477 const len = vector_ty.vectorLen();3478 const len = vector_ty.vectorLen();
3478 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3479 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3479 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);3480 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
3480 const result: MCValue = res: {3481 const result: MCValue = res: {
3481 if (self.liveness.isUnused(inst)) break :res MCValue.dead;3482 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
3482 return self.fail("TODO implement airVectorInit for {}", .{self.target.cpu.arch});3483 return self.fail("TODO implement airAggregateInit for {}", .{self.target.cpu.arch});
3483 };3484 };
34843485
3485 if (elements.len <= Liveness.bpi - 1) {3486 if (elements.len <= Liveness.bpi - 1) {
...@@ -3494,6 +3495,13 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -3494,6 +3495,13 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
3494 return bt.finishAir(result);3495 return bt.finishAir(result);
3495}3496}
34963497
3498fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
3499 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3500 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
3501 _ = extra;
3502 return self.fail("TODO implement airUnionInit for aarch64", .{});
3503}
3504
3497fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {3505fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
3498 const prefetch = self.air.instructions.items(.data)[inst].prefetch;3506 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
3499 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });3507 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
src/arch/arm/CodeGen.zig+12-3
...@@ -609,7 +609,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -609,7 +609,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
609 .tag_name => try self.airTagName(inst),609 .tag_name => try self.airTagName(inst),
610 .error_name => try self.airErrorName(inst),610 .error_name => try self.airErrorName(inst),
611 .splat => try self.airSplat(inst),611 .splat => try self.airSplat(inst),
612 .vector_init => try self.airVectorInit(inst),612 .aggregate_init => try self.airAggregateInit(inst),
613 .union_init => try self.airUnionInit(inst),
613 .prefetch => try self.airPrefetch(inst),614 .prefetch => try self.airPrefetch(inst),
614615
615 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),616 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
...@@ -3937,14 +3938,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3937,14 +3938,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
3937 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3938 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3938}3939}
39393940
3940fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {3941fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
3941 const vector_ty = self.air.typeOfIndex(inst);3942 const vector_ty = self.air.typeOfIndex(inst);
3942 const len = vector_ty.vectorLen();3943 const len = vector_ty.vectorLen();
3943 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3944 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3944 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);3945 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
3945 const result: MCValue = res: {3946 const result: MCValue = res: {
3946 if (self.liveness.isUnused(inst)) break :res MCValue.dead;3947 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
3947 return self.fail("TODO implement airVectorInit for arm", .{});3948 return self.fail("TODO implement airAggregateInit for arm", .{});
3948 };3949 };
39493950
3950 if (elements.len <= Liveness.bpi - 1) {3951 if (elements.len <= Liveness.bpi - 1) {
...@@ -3959,6 +3960,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -3959,6 +3960,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
3959 return bt.finishAir(result);3960 return bt.finishAir(result);
3960}3961}
39613962
3963fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
3964 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3965 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
3966 _ = extra;
3967
3968 return self.fail("TODO implement airUnionInit for arm", .{});
3969}
3970
3962fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {3971fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
3963 const prefetch = self.air.instructions.items(.data)[inst].prefetch;3972 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
3964 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });3973 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
src/arch/riscv64/CodeGen.zig+12-3
...@@ -596,7 +596,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -596,7 +596,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
596 .tag_name => try self.airTagName(inst),596 .tag_name => try self.airTagName(inst),
597 .error_name => try self.airErrorName(inst),597 .error_name => try self.airErrorName(inst),
598 .splat => try self.airSplat(inst),598 .splat => try self.airSplat(inst),
599 .vector_init => try self.airVectorInit(inst),599 .aggregate_init => try self.airAggregateInit(inst),
600 .union_init => try self.airUnionInit(inst),
600 .prefetch => try self.airPrefetch(inst),601 .prefetch => try self.airPrefetch(inst),
601602
602 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),603 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
...@@ -2157,14 +2158,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2157,14 +2158,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
2157 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2158 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2158}2159}
21592160
2160fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {2161fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
2161 const vector_ty = self.air.typeOfIndex(inst);2162 const vector_ty = self.air.typeOfIndex(inst);
2162 const len = vector_ty.vectorLen();2163 const len = vector_ty.vectorLen();
2163 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2164 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2164 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);2165 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
2165 const result: MCValue = res: {2166 const result: MCValue = res: {
2166 if (self.liveness.isUnused(inst)) break :res MCValue.dead;2167 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
2167 return self.fail("TODO implement airVectorInit for riscv64", .{});2168 return self.fail("TODO implement airAggregateInit for riscv64", .{});
2168 };2169 };
21692170
2170 if (elements.len <= Liveness.bpi - 1) {2171 if (elements.len <= Liveness.bpi - 1) {
...@@ -2179,6 +2180,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -2179,6 +2180,14 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
2179 return bt.finishAir(result);2180 return bt.finishAir(result);
2180}2181}
21812182
2183fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
2184 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2185 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
2186 _ = extra;
2187 return self.fail("TODO implement airUnionInit for riscv64", .{});
2188 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
2189}
2190
2182fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {2191fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
2183 const prefetch = self.air.instructions.items(.data)[inst].prefetch;2192 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
2184 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });2193 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
src/arch/wasm/CodeGen.zig+9-3
...@@ -1642,7 +1642,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1642,7 +1642,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1642 .ret_ptr => self.airRetPtr(inst),1642 .ret_ptr => self.airRetPtr(inst),
1643 .ret_load => self.airRetLoad(inst),1643 .ret_load => self.airRetLoad(inst),
1644 .splat => self.airSplat(inst),1644 .splat => self.airSplat(inst),
1645 .vector_init => self.airVectorInit(inst),1645 .aggregate_init => self.airAggregateInit(inst),
1646 .union_init => self.airUnionInit(inst),
1646 .prefetch => self.airPrefetch(inst),1647 .prefetch => self.airPrefetch(inst),
16471648
1648 .slice => self.airSlice(inst),1649 .slice => self.airSlice(inst),
...@@ -3350,7 +3351,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3350,7 +3351,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3350 return self.fail("TODO: Implement wasm airSplat", .{});3351 return self.fail("TODO: Implement wasm airSplat", .{});
3351}3352}
33523353
3353fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3354fn airAggregateInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3354 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3355 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
33553356
3356 const vector_ty = self.air.typeOfIndex(inst);3357 const vector_ty = self.air.typeOfIndex(inst);
...@@ -3359,7 +3360,7 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3359,7 +3360,7 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3359 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);3360 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
33603361
3361 switch (vector_ty.zigTypeTag()) {3362 switch (vector_ty.zigTypeTag()) {
3362 .Vector => return self.fail("TODO: Wasm backend: implement airVectorInit for vectors", .{}),3363 .Vector => return self.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}),
3363 .Array => {3364 .Array => {
3364 const result = try self.allocStack(vector_ty);3365 const result = try self.allocStack(vector_ty);
3365 const elem_ty = vector_ty.childType();3366 const elem_ty = vector_ty.childType();
...@@ -3413,6 +3414,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3413,6 +3414,11 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3413 }3414 }
3414}3415}
34153416
3417fn airUnionInit(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3418 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3419 return self.fail("TODO: Wasm backend: implement airUnionInit", .{});
3420}
3421
3416fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3422fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3417 const prefetch = self.air.instructions.items(.data)[inst].prefetch;3423 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
3418 _ = prefetch;3424 _ = prefetch;
src/arch/x86_64/CodeGen.zig+14-3
...@@ -708,7 +708,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -708,7 +708,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
708 .tag_name => try self.airTagName(inst),708 .tag_name => try self.airTagName(inst),
709 .error_name => try self.airErrorName(inst),709 .error_name => try self.airErrorName(inst),
710 .splat => try self.airSplat(inst),710 .splat => try self.airSplat(inst),
711 .vector_init => try self.airVectorInit(inst),711 .aggregate_init => try self.airAggregateInit(inst),
712 .union_init => try self.airUnionInit(inst),
712 .prefetch => try self.airPrefetch(inst),713 .prefetch => try self.airPrefetch(inst),
713714
714 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),715 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
...@@ -5232,14 +5233,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {...@@ -5232,14 +5233,14 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void {
5232 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5233 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5233}5234}
52345235
5235fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {5236fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
5236 const vector_ty = self.air.typeOfIndex(inst);5237 const vector_ty = self.air.typeOfIndex(inst);
5237 const len = vector_ty.vectorLen();5238 const len = vector_ty.vectorLen();
5238 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5239 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5239 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);5240 const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
5240 const result: MCValue = res: {5241 const result: MCValue = res: {
5241 if (self.liveness.isUnused(inst)) break :res MCValue.dead;5242 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
5242 return self.fail("TODO implement airVectorInit for x86_64", .{});5243 return self.fail("TODO implement airAggregateInit for x86_64", .{});
5243 };5244 };
52445245
5245 if (elements.len <= Liveness.bpi - 1) {5246 if (elements.len <= Liveness.bpi - 1) {
...@@ -5254,6 +5255,16 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {...@@ -5254,6 +5255,16 @@ fn airVectorInit(self: *Self, inst: Air.Inst.Index) !void {
5254 return bt.finishAir(result);5255 return bt.finishAir(result);
5255}5256}
52565257
5258fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
5259 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
5260 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
5261 const result: MCValue = res: {
5262 if (self.liveness.isUnused(inst)) break :res MCValue.dead;
5263 return self.fail("TODO implement airAggregateInit for x86_64", .{});
5264 };
5265 return self.finishAir(inst, result, .{ extra.init, .none, .none });
5266}
5267
5257fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {5268fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
5258 const prefetch = self.air.instructions.items(.data)[inst].prefetch;5269 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
5259 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });5270 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
src/codegen/c.zig+19-3
...@@ -1713,7 +1713,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1713,7 +1713,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1713 .tag_name => try airTagName(f, inst),1713 .tag_name => try airTagName(f, inst),
1714 .error_name => try airErrorName(f, inst),1714 .error_name => try airErrorName(f, inst),
1715 .splat => try airSplat(f, inst),1715 .splat => try airSplat(f, inst),
1716 .vector_init => try airVectorInit(f, inst),1716 .aggregate_init => try airAggregateInit(f, inst),
1717 .union_init => try airUnionInit(f, inst),
1717 .prefetch => try airPrefetch(f, inst),1718 .prefetch => try airPrefetch(f, inst),
17181719
1719 .int_to_float,1720 .int_to_float,
...@@ -3526,7 +3527,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3526,7 +3527,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
3526 return f.fail("TODO: C backend: implement airSplat", .{});3527 return f.fail("TODO: C backend: implement airSplat", .{});
3527}3528}
35283529
3529fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue {3530fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
3530 if (f.liveness.isUnused(inst)) return CValue.none;3531 if (f.liveness.isUnused(inst)) return CValue.none;
35313532
3532 const inst_ty = f.air.typeOfIndex(inst);3533 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3541,7 +3542,22 @@ fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3541,7 +3542,22 @@ fn airVectorInit(f: *Function, inst: Air.Inst.Index) !CValue {
35413542
3542 _ = elements;3543 _ = elements;
3543 _ = local;3544 _ = local;
3544 return f.fail("TODO: C backend: implement airVectorInit", .{});3545 return f.fail("TODO: C backend: implement airAggregateInit", .{});
3546}
3547
3548fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
3549 if (f.liveness.isUnused(inst)) return CValue.none;
3550
3551 const inst_ty = f.air.typeOfIndex(inst);
3552 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3553
3554 const writer = f.object.writer();
3555 const local = try f.allocLocal(inst_ty, .Const);
3556 try writer.writeAll(" = ");
3557
3558 _ = local;
3559 _ = ty_pl;
3560 return f.fail("TODO: C backend: implement airUnionInit", .{});
3545}3561}
35463562
3547fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {3563fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
src/codegen/llvm.zig+106-2
...@@ -2175,7 +2175,8 @@ pub const FuncGen = struct {...@@ -2175,7 +2175,8 @@ pub const FuncGen = struct {
2175 .tag_name => try self.airTagName(inst),2175 .tag_name => try self.airTagName(inst),
2176 .error_name => try self.airErrorName(inst),2176 .error_name => try self.airErrorName(inst),
2177 .splat => try self.airSplat(inst),2177 .splat => try self.airSplat(inst),
2178 .vector_init => try self.airVectorInit(inst),2178 .aggregate_init => try self.airAggregateInit(inst),
2179 .union_init => try self.airUnionInit(inst),
2179 .prefetch => try self.airPrefetch(inst),2180 .prefetch => try self.airPrefetch(inst),
21802181
2181 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),2182 .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
...@@ -4608,7 +4609,7 @@ pub const FuncGen = struct {...@@ -4608,7 +4609,7 @@ pub const FuncGen = struct {
4608 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");4609 return self.builder.buildShuffleVector(op_vector, undef_vector, mask_llvm_ty.constNull(), "");
4609 }4610 }
46104611
4611 fn airVectorInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {4612 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4612 if (self.liveness.isUnused(inst)) return null;4613 if (self.liveness.isUnused(inst)) return null;
46134614
4614 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;4615 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -4693,6 +4694,109 @@ pub const FuncGen = struct {...@@ -4693,6 +4694,109 @@ pub const FuncGen = struct {
4693 }4694 }
4694 }4695 }
46954696
4697 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4698 if (self.liveness.isUnused(inst)) return null;
4699
4700 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4701 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
4702 const union_ty = self.air.typeOfIndex(inst);
4703 const union_llvm_ty = try self.dg.llvmType(union_ty);
4704 const target = self.dg.module.getTarget();
4705 const layout = union_ty.unionGetLayout(target);
4706 if (layout.payload_size == 0) {
4707 if (layout.tag_size == 0) {
4708 return null;
4709 }
4710 assert(!isByRef(union_ty));
4711 return union_llvm_ty.constInt(extra.field_index, .False);
4712 }
4713 assert(isByRef(union_ty));
4714 // The llvm type of the alloca will the the named LLVM union type, which will not
4715 // necessarily match the format that we need, depending on which tag is active. We
4716 // must construct the correct unnamed struct type here and bitcast, in order to
4717 // then set the fields appropriately.
4718 const result_ptr = self.buildAlloca(union_llvm_ty);
4719 const llvm_payload = try self.resolveInst(extra.init);
4720 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
4721 assert(union_obj.haveFieldTypes());
4722 const field = union_obj.fields.values()[extra.field_index];
4723 const field_llvm_ty = try self.dg.llvmType(field.ty);
4724 const tag_llvm_ty = try self.dg.llvmType(union_obj.tag_ty);
4725 const field_size = field.ty.abiSize(target);
4726 const field_align = field.normalAlignment(target);
4727
4728 const llvm_union_ty = t: {
4729 const payload = p: {
4730 if (!field.ty.hasRuntimeBits()) {
4731 const padding_len = @intCast(c_uint, layout.payload_size);
4732 break :p self.context.intType(8).arrayType(padding_len);
4733 }
4734 if (field_size == layout.payload_size) {
4735 break :p field_llvm_ty;
4736 }
4737 const padding_len = @intCast(c_uint, layout.payload_size - field_size);
4738 const fields: [2]*const llvm.Type = .{
4739 field_llvm_ty, self.context.intType(8).arrayType(padding_len),
4740 };
4741 break :p self.context.structType(&fields, fields.len, .False);
4742 };
4743 if (layout.tag_size == 0) {
4744 const fields: [1]*const llvm.Type = .{payload};
4745 break :t self.context.structType(&fields, fields.len, .False);
4746 }
4747 var fields: [2]*const llvm.Type = undefined;
4748 if (layout.tag_align >= layout.payload_align) {
4749 fields = .{ tag_llvm_ty, payload };
4750 } else {
4751 fields = .{ payload, tag_llvm_ty };
4752 }
4753 break :t self.context.structType(&fields, fields.len, .False);
4754 };
4755
4756 const casted_ptr = self.builder.buildBitCast(result_ptr, llvm_union_ty.pointerType(0), "");
4757
4758 // Now we follow the layout as expressed above with GEP instructions to set the
4759 // tag and the payload.
4760 const index_type = self.context.intType(32);
4761
4762 if (layout.tag_size == 0) {
4763 const indices: [3]*const llvm.Value = .{
4764 index_type.constNull(),
4765 index_type.constNull(),
4766 index_type.constNull(),
4767 };
4768 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
4769 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, len, "");
4770 const store_inst = self.builder.buildStore(llvm_payload, field_ptr);
4771 store_inst.setAlignment(field_align);
4772 return result_ptr;
4773 }
4774
4775 {
4776 const indices: [3]*const llvm.Value = .{
4777 index_type.constNull(),
4778 index_type.constInt(@boolToInt(layout.tag_align >= layout.payload_align), .False),
4779 index_type.constNull(),
4780 };
4781 const len: c_uint = if (field_size == layout.payload_size) 2 else 3;
4782 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, len, "");
4783 const store_inst = self.builder.buildStore(llvm_payload, field_ptr);
4784 store_inst.setAlignment(field_align);
4785 }
4786 {
4787 const indices: [2]*const llvm.Value = .{
4788 index_type.constNull(),
4789 index_type.constInt(@boolToInt(layout.tag_align < layout.payload_align), .False),
4790 };
4791 const field_ptr = self.builder.buildInBoundsGEP(casted_ptr, &indices, indices.len, "");
4792 const llvm_tag = union_llvm_ty.constInt(extra.field_index, .False);
4793 const store_inst = self.builder.buildStore(llvm_tag, field_ptr);
4794 store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target));
4795 }
4796
4797 return result_ptr;
4798 }
4799
4696 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {4800 fn airPrefetch(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
4697 const prefetch = self.air.instructions.items(.data)[inst].prefetch;4801 const prefetch = self.air.instructions.items(.data)[inst].prefetch;
46984802
src/print_air.zig+11-2
...@@ -232,7 +232,8 @@ const Writer = struct {...@@ -232,7 +232,8 @@ const Writer = struct {
232 .assembly => try w.writeAssembly(s, inst),232 .assembly => try w.writeAssembly(s, inst),
233 .dbg_stmt => try w.writeDbgStmt(s, inst),233 .dbg_stmt => try w.writeDbgStmt(s, inst),
234 .call => try w.writeCall(s, inst),234 .call => try w.writeCall(s, inst),
235 .vector_init => try w.writeVectorInit(s, inst),235 .aggregate_init => try w.writeAggregateInit(s, inst),
236 .union_init => try w.writeUnionInit(s, inst),
236 .br => try w.writeBr(s, inst),237 .br => try w.writeBr(s, inst),
237 .cond_br => try w.writeCondBr(s, inst),238 .cond_br => try w.writeCondBr(s, inst),
238 .switch_br => try w.writeSwitchBr(s, inst),239 .switch_br => try w.writeSwitchBr(s, inst),
...@@ -301,7 +302,7 @@ const Writer = struct {...@@ -301,7 +302,7 @@ const Writer = struct {
301 try s.writeAll("}");302 try s.writeAll("}");
302 }303 }
303304
304 fn writeVectorInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {305 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
305 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;306 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
306 const vector_ty = w.air.getRefType(ty_pl.ty);307 const vector_ty = w.air.getRefType(ty_pl.ty);
307 const len = @intCast(usize, vector_ty.arrayLen());308 const len = @intCast(usize, vector_ty.arrayLen());
...@@ -315,6 +316,14 @@ const Writer = struct {...@@ -315,6 +316,14 @@ const Writer = struct {
315 try s.writeAll("]");316 try s.writeAll("]");
316 }317 }
317318
319 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
320 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
321 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
322
323 try s.print("{d}, ", .{extra.field_index});
324 try w.writeOperand(s, inst, 0, extra.init);
325 }
326
318 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {327 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
319 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;328 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
320 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;329 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
src/print_zir.zig+5-5
...@@ -273,7 +273,7 @@ const Writer = struct {...@@ -273,7 +273,7 @@ const Writer = struct {
273 .slice_end => try self.writeSliceEnd(stream, inst),273 .slice_end => try self.writeSliceEnd(stream, inst),
274 .slice_sentinel => try self.writeSliceSentinel(stream, inst),274 .slice_sentinel => try self.writeSliceSentinel(stream, inst),
275275
276 .union_init_ptr => try self.writeUnionInitPtr(stream, inst),276 .union_init => try self.writeUnionInit(stream, inst),
277277
278 .struct_init,278 .struct_init,
279 .struct_init_ref,279 .struct_init_ref,
...@@ -692,14 +692,14 @@ const Writer = struct {...@@ -692,14 +692,14 @@ const Writer = struct {
692 try self.writeSrc(stream, inst_data.src());692 try self.writeSrc(stream, inst_data.src());
693 }693 }
694694
695 fn writeUnionInitPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {695 fn writeUnionInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
696 const inst_data = self.code.instructions.items(.data)[inst].pl_node;696 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
697 const extra = self.code.extraData(Zir.Inst.UnionInitPtr, inst_data.payload_index).data;697 const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
698 try self.writeInstRef(stream, extra.result_ptr);
699 try stream.writeAll(", ");
700 try self.writeInstRef(stream, extra.union_type);698 try self.writeInstRef(stream, extra.union_type);
701 try stream.writeAll(", ");699 try stream.writeAll(", ");
702 try self.writeInstRef(stream, extra.field_name);700 try self.writeInstRef(stream, extra.field_name);
701 try stream.writeAll(", ");
702 try self.writeInstRef(stream, extra.init);
703 try stream.writeAll(") ");703 try stream.writeAll(") ");
704 try self.writeSrc(stream, inst_data.src());704 try self.writeSrc(stream, inst_data.src());
705 }705 }
test/behavior/union.zig+39-3
...@@ -785,8 +785,40 @@ test "return union init with void payload" {...@@ -785,8 +785,40 @@ test "return union init with void payload" {
785 comptime try S.entry();785 comptime try S.entry();
786}786}
787787
788test "@unionInit stored to a const" {
789 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
790 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
793 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
794
795 const S = struct {
796 const U = union(enum) {
797 boolean: bool,
798 byte: u8,
799 };
800 fn doTheTest() !void {
801 {
802 var t = true;
803 const u = @unionInit(U, "boolean", t);
804 try expect(u.boolean);
805 }
806 {
807 var byte: u8 = 69;
808 const u = @unionInit(U, "byte", byte);
809 try expect(u.byte == 69);
810 }
811 }
812 };
813
814 comptime try S.doTheTest();
815 try S.doTheTest();
816}
817
788test "@unionInit can modify a union type" {818test "@unionInit can modify a union type" {
789 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO819 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
821 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
790822
791 const UnionInitEnum = union(enum) {823 const UnionInitEnum = union(enum) {
792 Boolean: bool,824 Boolean: bool,
...@@ -807,7 +839,9 @@ test "@unionInit can modify a union type" {...@@ -807,7 +839,9 @@ test "@unionInit can modify a union type" {
807}839}
808840
809test "@unionInit can modify a pointer value" {841test "@unionInit can modify a pointer value" {
810 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO842 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
843 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
811845
812 const UnionInitEnum = union(enum) {846 const UnionInitEnum = union(enum) {
813 Boolean: bool,847 Boolean: bool,
...@@ -825,7 +859,9 @@ test "@unionInit can modify a pointer value" {...@@ -825,7 +859,9 @@ test "@unionInit can modify a pointer value" {
825}859}
826860
827test "union no tag with struct member" {861test "union no tag with struct member" {
828 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO862 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
863 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
864 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
829865
830 const Struct = struct {};866 const Struct = struct {};
831 const Union = union {867 const Union = union {