authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-24 19:47:42+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-24 19:48:34+02:00
logb034c45b2bcb3a28ad260037dfa34c40b6c9313b
treeef3140c8f3d471791f9adeb7a0befc13808dce57
parent6249a24e81b9b3df3d5ca99b57f22470b9ac486c

stage2: implement fieldParentPtr


16 files changed, 161 insertions(+), 20 deletions(-)

src/Air.zig+10
......@@ -574,6 +574,10 @@ pub const Inst = struct {
574574 /// Uses the `prefetch` field.
575575 prefetch,
576576
577 /// Implements @fieldParentPtr builtin.
578 /// Uses the `ty_pl` field.
579 field_parent_ptr,
580
577581 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
578582 return switch (op) {
579583 .lt => .cmp_lt,
......@@ -703,6 +707,11 @@ pub const Bin = struct {
703707 rhs: Inst.Ref,
704708};
705709
710pub const FieldParentPtr = struct {
711 field_ptr: Inst.Ref,
712 field_index: u32,
713};
714
706715/// Trailing:
707716/// 0. `Inst.Ref` for every outputs_len
708717/// 1. `Inst.Ref` for every inputs_len
......@@ -856,6 +865,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
856865 .cmpxchg_strong,
857866 .slice,
858867 .vector_init,
868 .field_parent_ptr,
859869 => return air.getRefType(datas[inst].ty_pl.ty),
860870
861871 .not,
src/AstGen.zig+1-3
......@@ -2296,7 +2296,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22962296 .atomic_rmw,
22972297 .mul_add,
22982298 .builtin_call,
2299 .field_ptr_type,
23002299 .field_parent_ptr,
23012300 .maximum,
23022301 .minimum,
......@@ -7403,11 +7402,10 @@ fn builtinCall(
74037402 .field_parent_ptr => {
74047403 const parent_type = try typeExpr(gz, scope, params[0]);
74057404 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
7406 const field_ptr_type = try gz.addBin(.field_ptr_type, parent_type, field_name);
74077405 const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{
74087406 .parent_type = parent_type,
74097407 .field_name = field_name,
7410 .field_ptr = try expr(gz, scope, .{ .ty = field_ptr_type }, params[2]),
7408 .field_ptr = try expr(gz, scope, .none, params[2]),
74117409 });
74127410 return rvalue(gz, rl, result, node);
74137411 },
src/Liveness.zig+4
......@@ -446,6 +446,10 @@ fn analyzeInst(
446446 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
447447 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
448448 },
449 .field_parent_ptr => {
450 const extra = a.air.extraData(Air.FieldParentPtr, inst_datas[inst].ty_pl.payload).data;
451 return trackOperands(a, new_set, inst, main_tomb, .{ extra.field_ptr, .none, .none });
452 },
449453 .ptr_elem_ptr, .slice_elem_ptr, .slice => {
450454 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
451455 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
src/Sema.zig+59-8
......@@ -732,7 +732,6 @@ fn analyzeBodyInner(
732732 .atomic_rmw => try sema.zirAtomicRmw(block, inst),
733733 .mul_add => try sema.zirMulAdd(block, inst),
734734 .builtin_call => try sema.zirBuiltinCall(block, inst),
735 .field_ptr_type => try sema.zirFieldPtrType(block, inst),
736735 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
737736 .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
738737 .@"resume" => try sema.zirResume(block, inst),
......@@ -12839,16 +12838,68 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1283912838 return sema.fail(block, src, "TODO: Sema.zirBuiltinCall", .{});
1284012839}
1284112840
12842fn zirFieldPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
12843 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
12844 const src = inst_data.src();
12845 return sema.fail(block, src, "TODO: Sema.zirFieldPtrType", .{});
12846}
12847
1284812841fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1284912842 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
12843 const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data;
1285012844 const src = inst_data.src();
12851 return sema.fail(block, src, "TODO: Sema.zirFieldParentPtr", .{});
12845 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
12846 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
12847 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
12848
12849 const struct_ty = try sema.resolveType(block, ty_src, extra.parent_type);
12850 const field_name = try sema.resolveConstString(block, name_src, extra.field_name);
12851 const field_ptr = sema.resolveInst(extra.field_ptr);
12852 const field_ptr_ty = sema.typeOf(field_ptr);
12853
12854 if (struct_ty.zigTypeTag() != .Struct) {
12855 return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty});
12856 }
12857 try sema.resolveTypeLayout(block, ty_src, struct_ty);
12858
12859 const struct_obj = struct_ty.castTag(.@"struct").?.data;
12860 const field_index = struct_obj.fields.getIndex(field_name) orelse
12861 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);
12862
12863 if (field_ptr_ty.zigTypeTag() != .Pointer) {
12864 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty});
12865 }
12866 const field = struct_obj.fields.values()[field_index];
12867 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
12868
12869 var ptr_ty_data: Type.Payload.Pointer.Data = .{
12870 .pointee_type = field.ty,
12871 .mutable = field_ptr_ty_info.mutable,
12872 .@"addrspace" = field_ptr_ty_info.@"addrspace",
12873 };
12874
12875 if (struct_obj.layout == .Packed) {
12876 // TODO handle packed structs
12877 } else if (field.abi_align.tag() != .abi_align_default) {
12878 ptr_ty_data.@"align" = @intCast(u32, field.abi_align.toUnsignedInt());
12879 }
12880
12881 const actual_field_ptr_ty = try Type.ptr(sema.arena, ptr_ty_data);
12882 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
12883
12884 ptr_ty_data.pointee_type = struct_ty;
12885 const result_ptr = try Type.ptr(sema.arena, ptr_ty_data);
12886
12887 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
12888 const payload = field_ptr_val.castTag(.field_ptr).?.data;
12889 return sema.addConstant(result_ptr, payload.container_ptr);
12890 }
12891
12892 try sema.requireRuntimeBlock(block, src);
12893 return block.addInst(.{
12894 .tag = .field_parent_ptr,
12895 .data = .{ .ty_pl = .{
12896 .ty = try sema.addType(result_ptr),
12897 .payload = try block.sema.addExtra(Air.FieldParentPtr{
12898 .field_ptr = casted_field_ptr,
12899 .field_index = @intCast(u32, field_index),
12900 }),
12901 } },
12902 });
1285212903}
1285312904
1285412905fn zirMinMax(
src/Zir.zig-6
......@@ -892,10 +892,6 @@ pub const Inst = struct {
892892 /// Implements the `@call` builtin.
893893 /// Uses the `pl_node` union field with payload `BuiltinCall`.
894894 builtin_call,
895 /// Given a type and a field name, returns a pointer to the field type.
896 /// Assumed to be part of a `@fieldParentPtr` builtin call.
897 /// Uses the `bin` union field. LHS is type, RHS is field name.
898 field_ptr_type,
899895 /// Implements the `@fieldParentPtr` builtin.
900896 /// Uses the `pl_node` union field with payload `FieldParentPtr`.
901897 field_parent_ptr,
......@@ -1192,7 +1188,6 @@ pub const Inst = struct {
11921188 .atomic_store,
11931189 .mul_add,
11941190 .builtin_call,
1195 .field_ptr_type,
11961191 .field_parent_ptr,
11971192 .maximum,
11981193 .memcpy,
......@@ -1466,7 +1461,6 @@ pub const Inst = struct {
14661461 .atomic_store = .pl_node,
14671462 .mul_add = .pl_node,
14681463 .builtin_call = .pl_node,
1469 .field_ptr_type = .bin,
14701464 .field_parent_ptr = .pl_node,
14711465 .maximum = .pl_node,
14721466 .memcpy = .pl_node,
src/arch/aarch64/CodeGen.zig+9
......@@ -638,6 +638,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
638638 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
639639 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
640640
641 .field_parent_ptr => try self.airFieldParentPtr(inst),
642
641643 .switch_br => try self.airSwitch(inst),
642644 .slice_ptr => try self.airSlicePtr(inst),
643645 .slice_len => try self.airSliceLen(inst),
......@@ -2118,6 +2120,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
21182120 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
21192121}
21202122
2123fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2124 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2125 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
2126 _ = extra;
2127 return self.fail("TODO implement codegen airFieldParentPtr", .{});
2128}
2129
21212130fn airArg(self: *Self, inst: Air.Inst.Index) !void {
21222131 const arg_index = self.arg_index;
21232132 self.arg_index += 1;
src/arch/arm/CodeGen.zig+9
......@@ -622,6 +622,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
622622 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
623623 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
624624
625 .field_parent_ptr => try self.airFieldParentPtr(inst),
626
625627 .switch_br => try self.airSwitch(inst),
626628 .slice_ptr => try self.airSlicePtr(inst),
627629 .slice_len => try self.airSliceLen(inst),
......@@ -1735,6 +1737,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
17351737 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
17361738}
17371739
1740fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
1741 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1742 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1743 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airFieldParentPtr", .{});
1744 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1745}
1746
17381747/// Don't call this function directly. Use binOp instead.
17391748///
17401749/// Calling this function signals an intention to generate a Mir
src/arch/riscv64/CodeGen.zig+8
......@@ -609,6 +609,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
609609 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
610610 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
611611
612 .field_parent_ptr => try self.airFieldParentPtr(inst),
613
612614 .switch_br => try self.airSwitch(inst),
613615 .slice_ptr => try self.airSlicePtr(inst),
614616 .slice_len => try self.airSliceLen(inst),
......@@ -1360,6 +1362,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
13601362 //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
13611363}
13621364
1365fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
1366 _ = self;
1367 _ = inst;
1368 return self.fail("TODO implement codegen airFieldParentPtr", .{});
1369}
1370
13631371fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
13641372 const ty = self.air.instructions.items(.data)[inst].ty;
13651373 const name = self.mod_fn.getParamName(arg_index);
src/arch/wasm/CodeGen.zig+1
......@@ -1730,6 +1730,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
17301730 .tag_name,
17311731 .error_name,
17321732 .errunion_payload_ptr_set,
1733 .field_parent_ptr,
17331734
17341735 // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248
17351736 // is implemented in the frontend before implementing them here in the wasm backend.
src/arch/x86_64/CodeGen.zig+11
......@@ -721,6 +721,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
721721 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
722722 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
723723
724 .field_parent_ptr => try self.airFieldParentPtr(inst),
725
724726 .switch_br => try self.airSwitch(inst),
725727 .slice_ptr => try self.airSlicePtr(inst),
726728 .slice_len => try self.airSliceLen(inst),
......@@ -2656,6 +2658,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
26562658 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
26572659}
26582660
2661fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2662 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2663 const result: MCValue = if (self.liveness.isUnused(inst))
2664 .dead
2665 else
2666 return self.fail("TODO implement airFieldParentPtr for {}", .{self.target.cpu.arch});
2667 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2668}
2669
26592670/// Perform "binary" operators, excluding comparisons.
26602671/// Currently, the following ops are supported:
26612672/// ADD, SUB, XOR, OR, AND
src/codegen/c.zig+7
......@@ -1734,6 +1734,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17341734 .struct_field_ptr_index_2 => try airStructFieldPtrIndex(f, inst, 2),
17351735 .struct_field_ptr_index_3 => try airStructFieldPtrIndex(f, inst, 3),
17361736
1737 .field_parent_ptr => try airFieldParentPtr(f, inst),
1738
17371739 .struct_field_val => try airStructFieldVal(f, inst),
17381740 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),
17391741 .slice_len => try airSliceField(f, inst, ".len;\n"),
......@@ -3026,6 +3028,11 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
30263028 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
30273029}
30283030
3031fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3032 _ = inst;
3033 return f.fail("TODO: C backend: implement airFieldParentPtr", .{});
3034}
3035
30293036fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
30303037 const writer = f.object.writer();
30313038 const struct_ty = struct_ptr_ty.elemType();
src/codegen/llvm.zig+25
......@@ -2191,6 +2191,8 @@ pub const FuncGen = struct {
21912191 .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
21922192 .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
21932193
2194 .field_parent_ptr => try self.airFieldParentPtr(inst),
2195
21942196 .array_elem_val => try self.airArrayElemVal(inst),
21952197 .slice_elem_val => try self.airSliceElemVal(inst),
21962198 .slice_elem_ptr => try self.airSliceElemPtr(inst),
......@@ -2853,6 +2855,29 @@ pub const FuncGen = struct {
28532855 }
28542856 }
28552857
2858 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2859 if (self.liveness.isUnused(inst)) return null;
2860
2861 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2862 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
2863
2864 const field_ptr = try self.resolveInst(extra.field_ptr);
2865
2866 const target = self.dg.module.getTarget();
2867 const struct_ty = self.air.getRefType(ty_pl.ty).childType();
2868 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
2869
2870 const res_ty = try self.dg.llvmType(self.air.getRefType(ty_pl.ty));
2871 if (field_offset == 0) {
2872 return self.builder.buildBitCast(field_ptr, res_ty, "");
2873 }
2874 const llvm_usize_ty = self.context.intType(target.cpu.arch.ptrBitWidth());
2875
2876 const field_ptr_int = self.builder.buildPtrToInt(field_ptr, llvm_usize_ty, "");
2877 const base_ptr_int = self.builder.buildNUWSub(field_ptr_int, llvm_usize_ty.constInt(field_offset, .False), "");
2878 return self.builder.buildIntToPtr(base_ptr_int, res_ty, "");
2879 }
2880
28562881 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
28572882 if (self.liveness.isUnused(inst))
28582883 return null;
src/print_air.zig+9
......@@ -247,6 +247,7 @@ const Writer = struct {
247247 .atomic_rmw => try w.writeAtomicRmw(s, inst),
248248 .memcpy => try w.writeMemcpy(s, inst),
249249 .memset => try w.writeMemset(s, inst),
250 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
250251
251252 .add_with_overflow,
252253 .sub_with_overflow,
......@@ -412,6 +413,14 @@ const Writer = struct {
412413 try w.writeOperand(s, inst, 2, extra.rhs);
413414 }
414415
416 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
417 const pl_op = w.air.instructions.items(.data)[inst].ty_pl;
418 const extra = w.air.extraData(Air.FieldParentPtr, pl_op.payload).data;
419
420 try w.writeOperand(s, inst, 0, extra.field_ptr);
421 try s.print(", {d}", .{extra.field_index});
422 }
423
415424 fn writeMemcpy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
416425 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
417426 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
src/print_zir.zig-1
......@@ -150,7 +150,6 @@ const Writer = struct {
150150 .store,
151151 .store_to_block_ptr,
152152 .store_to_inferred_ptr,
153 .field_ptr_type,
154153 => try self.writeBin(stream, inst),
155154
156155 .alloc,
src/value.zig+7-1
......@@ -1852,7 +1852,13 @@ pub const Value = extern union {
18521852 return eql(a_payload.ptr, b_payload.ptr, ptr_ty);
18531853 },
18541854 .elem_ptr => @panic("TODO: Implement more pointer eql cases"),
1855 .field_ptr => @panic("TODO: Implement more pointer eql cases"),
1855 .field_ptr => {
1856 const a_payload = a.castTag(.field_ptr).?.data;
1857 const b_payload = b.castTag(.field_ptr).?.data;
1858 if (a_payload.field_index != b_payload.field_index) return false;
1859
1860 return eql(a_payload.container_ptr, b_payload.container_ptr, ty);
1861 },
18561862 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
18571863 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
18581864 .array => {
test/behavior.zig+1-1
......@@ -129,6 +129,7 @@ test {
129129 _ = @import("behavior/switch_prong_err_enum.zig");
130130 _ = @import("behavior/switch_prong_implicit_cast.zig");
131131 _ = @import("behavior/union_with_members.zig");
132 _ = @import("behavior/field_parent_ptr.zig");
132133
133134 if (builtin.zig_backend == .stage1) {
134135 // Tests that only pass for the stage1 backend.
......@@ -160,7 +161,6 @@ test {
160161 _ = @import("behavior/bugs/10147.zig");
161162 _ = @import("behavior/const_slice_child.zig");
162163 _ = @import("behavior/export_self_referential_type_info.zig");
163 _ = @import("behavior/field_parent_ptr.zig");
164164 _ = @import("behavior/misc.zig");
165165 _ = @import("behavior/muladd.zig");
166166 _ = @import("behavior/select.zig");