authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-21 16:17:21+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-21 16:24:18+02:00
log09c7d5aebc4f7fe96a89f93c0cf99cc03977ea5f
tree7877d79040b38f43aea7fc192546b19d07821bc0
parent84876fec582e13707a809c8136bb1eaf92b5da09

stage2: elemPtr for slices

* Restructure elemPtr a bit * New AIR instruction: slice_elem_ptr, which returns a pointer to an element of a slice * Value: adapt elemPtr to work on slices

10 files changed, 157 insertions(+), 32 deletions(-)

src/Air.zig+5
...@@ -384,6 +384,10 @@ pub const Inst = struct {...@@ -384,6 +384,10 @@ pub const Inst = struct {
384 /// Result type is the element type of the slice operand.384 /// Result type is the element type of the slice operand.
385 /// Uses the `bin_op` field.385 /// Uses the `bin_op` field.
386 slice_elem_val,386 slice_elem_val,
387 /// Given a slice value and element index, return a pointer to the element value at that index.
388 /// Result type is a pointer to the element type of the slice operand.
389 /// Uses the `ty_pl` field with payload `Bin`.
390 slice_elem_ptr,
387 /// Given a pointer value, and element index, return the element value at that index.391 /// Given a pointer value, and element index, return the element value at that index.
388 /// Result type is the element type of the pointer operand.392 /// Result type is the element type of the pointer operand.
389 /// Uses the `bin_op` field.393 /// Uses the `bin_op` field.
...@@ -685,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -685,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
685 .constant,689 .constant,
686 .struct_field_ptr,690 .struct_field_ptr,
687 .struct_field_val,691 .struct_field_val,
692 .slice_elem_ptr,
688 .ptr_elem_ptr,693 .ptr_elem_ptr,
689 .cmpxchg_weak,694 .cmpxchg_weak,
690 .cmpxchg_strong,695 .cmpxchg_strong,
src/Liveness.zig+1-1
...@@ -360,7 +360,7 @@ fn analyzeInst(...@@ -360,7 +360,7 @@ fn analyzeInst(
360 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;360 const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
361 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });361 return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
362 },362 },
363 .ptr_elem_ptr => {363 .ptr_elem_ptr, .slice_elem_ptr => {
364 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;364 const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
365 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });365 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
366 },366 },
src/Sema.zig+51-17
...@@ -333,6 +333,24 @@ pub const Block = struct {...@@ -333,6 +333,24 @@ pub const Block = struct {
333 });333 });
334 }334 }
335335
336 pub fn addSliceElemPtr(
337 block: *Block,
338 slice: Air.Inst.Ref,
339 elem_index: Air.Inst.Ref,
340 elem_ptr_ty: Type,
341 ) !Air.Inst.Ref {
342 return block.addInst(.{
343 .tag = .slice_elem_ptr,
344 .data = .{ .ty_pl = .{
345 .ty = try block.sema.addType(elem_ptr_ty),
346 .payload = try block.sema.addExtra(Air.Bin{
347 .lhs = slice,
348 .rhs = elem_index,
349 }),
350 } },
351 });
352 }
353
336 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {354 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
337 return Air.indexToRef(try block.addInstAsIndex(inst));355 return Air.indexToRef(try block.addInstAsIndex(inst));
338 }356 }
...@@ -11476,18 +11494,39 @@ fn elemPtr(...@@ -11476,18 +11494,39 @@ fn elemPtr(
11476 else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}),11494 else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}),
11477 };11495 };
11478 if (!array_ty.isIndexable()) {11496 if (!array_ty.isIndexable()) {
11479 return sema.fail(block, src, "array access of non-array type '{}'", .{array_ty});11497 return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty});
11480 }
11481 if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
11482 // we have to deref the ptr operand to get the actual array pointer
11483 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
11484 return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
11485 }
11486 if (array_ty.zigTypeTag() == .Array) {
11487 return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
11488 }11498 }
1148911499
11490 return sema.fail(block, src, "TODO implement more analyze elemptr", .{});11500 switch (array_ty.zigTypeTag()) {
11501 .Pointer => {
11502 // In all below cases, we have to deref the ptr operand to get the actual array pointer.
11503 const array = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
11504 switch (array_ty.ptrSize()) {
11505 .Slice => {
11506 const result_ty = try array_ty.elemPtrType(sema.arena);
11507 const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
11508 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11509 const runtime_src = if (maybe_slice_val) |slice_val| rs: {
11510 const index_val = maybe_index_val orelse break :rs elem_index_src;
11511 const index = @intCast(usize, index_val.toUnsignedInt());
11512 const elem_ptr = try slice_val.elemPtr(sema.arena, index);
11513 return sema.addConstant(result_ty, elem_ptr);
11514 } else array_ptr_src;
11515
11516 try sema.requireRuntimeBlock(block, runtime_src);
11517 return block.addSliceElemPtr(array, elem_index, result_ty);
11518 },
11519 .Many, .C => return sema.fail(block, src, "TODO implement Sema for elemPtr for many/c pointer", .{}),
11520 .One => {
11521 assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
11522 return sema.elemPtrArray(block, src, array, elem_index, elem_index_src);
11523 },
11524 }
11525 },
11526 .Array => return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src),
11527 .Vector => return sema.fail(block, src, "TODO implement Sema for elemPtr for vector", .{}),
11528 else => unreachable,
11529 }
11491}11530}
1149211531
11493fn elemVal(11532fn elemVal(
...@@ -11529,7 +11568,7 @@ fn elemVal(...@@ -11529,7 +11568,7 @@ fn elemVal(
11529 return block.addBinOp(.ptr_elem_val, array, elem_index);11568 return block.addBinOp(.ptr_elem_val, array, elem_index);
11530 },11569 },
11531 .One => {11570 .One => {
11532 assert(array_ty.childType().zigTypeTag() == .Array);11571 assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
11533 const elem_ptr = try sema.elemPtr(block, src, array, elem_index, elem_index_src);11572 const elem_ptr = try sema.elemPtr(block, src, array, elem_index, elem_index_src);
11534 return sema.analyzeLoad(block, src, elem_ptr, elem_index_src);11573 return sema.analyzeLoad(block, src, elem_ptr, elem_index_src);
11535 },11574 },
...@@ -11562,12 +11601,7 @@ fn elemPtrArray(...@@ -11562,12 +11601,7 @@ fn elemPtrArray(
11562 elem_index_src: LazySrcLoc,11601 elem_index_src: LazySrcLoc,
11563) CompileError!Air.Inst.Ref {11602) CompileError!Air.Inst.Ref {
11564 const array_ptr_ty = sema.typeOf(array_ptr);11603 const array_ptr_ty = sema.typeOf(array_ptr);
11565 const pointee_type = array_ptr_ty.elemType().elemType();11604 const result_ty = try array_ptr_ty.elemPtrType(sema.arena);
11566 const result_ty = try Type.ptr(sema.arena, .{
11567 .pointee_type = pointee_type,
11568 .mutable = array_ptr_ty.ptrIsMutable(),
11569 .@"addrspace" = array_ptr_ty.ptrAddressSpace(),
11570 });
1157111605
11572 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {11606 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
11573 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {11607 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
src/arch/aarch64/CodeGen.zig+8
...@@ -500,6 +500,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -500,6 +500,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
500500
501 .array_elem_val => try self.airArrayElemVal(inst),501 .array_elem_val => try self.airArrayElemVal(inst),
502 .slice_elem_val => try self.airSliceElemVal(inst),502 .slice_elem_val => try self.airSliceElemVal(inst),
503 .slice_elem_ptr => try self.airSliceElemPtr(inst),
503 .ptr_elem_val => try self.airPtrElemVal(inst),504 .ptr_elem_val => try self.airPtrElemVal(inst),
504 .ptr_elem_ptr => try self.airPtrElemPtr(inst),505 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
505506
...@@ -1084,6 +1085,13 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1084,6 +1085,13 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1084 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1085 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1085}1086}
10861087
1088fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1089 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1090 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1091 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch});
1092 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1093}
1094
1087fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {1095fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1088 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1096 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1089 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});1097 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
src/codegen.zig+10
...@@ -848,6 +848,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -848,6 +848,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
848848
849 .array_elem_val => try self.airArrayElemVal(inst),849 .array_elem_val => try self.airArrayElemVal(inst),
850 .slice_elem_val => try self.airSliceElemVal(inst),850 .slice_elem_val => try self.airSliceElemVal(inst),
851 .slice_elem_ptr => try self.airSliceElemPtr(inst),
851 .ptr_elem_val => try self.airPtrElemVal(inst),852 .ptr_elem_val => try self.airPtrElemVal(inst),
852 .ptr_elem_ptr => try self.airPtrElemPtr(inst),853 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
853854
...@@ -1533,6 +1534,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1533,6 +1534,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1533 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1534 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1534 }1535 }
15351536
1537 fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1538 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1539 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1540 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1541 else => return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}),
1542 };
1543 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1544 }
1545
1536 fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {1546 fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1537 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1547 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1538 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {1548 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
src/codegen/c.zig+19
...@@ -1083,6 +1083,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1083,6 +1083,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1083 .ptr_elem_val => try airPtrElemVal(f, inst, "["),1083 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
1084 .ptr_elem_ptr => try airPtrElemPtr(f, inst),1084 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
1085 .slice_elem_val => try airSliceElemVal(f, inst, "["),1085 .slice_elem_val => try airSliceElemVal(f, inst, "["),
1086 .slice_elem_ptr => try airSliceElemPtr(f, inst),
1086 .array_elem_val => try airArrayElemVal(f, inst),1087 .array_elem_val => try airArrayElemVal(f, inst),
10871088
1088 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),1089 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
...@@ -1165,6 +1166,24 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CVal...@@ -1165,6 +1166,24 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CVal
1165 return local;1166 return local;
1166}1167}
11671168
1169fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
1170 if (f.liveness.isUnused(inst))
1171 return CValue.none;
1172 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1173 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
1174
1175 const slice = try f.resolveInst(bin_op.lhs);
1176 const index = try f.resolveInst(bin_op.rhs);
1177 const writer = f.object.writer();
1178 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
1179 try writer.writeAll(" = &");
1180 try f.writeCValue(writer, slice);
1181 try writer.writeByte('[');
1182 try f.writeCValue(writer, index);
1183 try writer.writeAll("];\n");
1184 return local;
1185}
1186
1168fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {1187fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
1169 if (f.liveness.isUnused(inst)) return CValue.none;1188 if (f.liveness.isUnused(inst)) return CValue.none;
11701189
src/codegen/llvm.zig+22-3
...@@ -1760,6 +1760,7 @@ pub const FuncGen = struct {...@@ -1760,6 +1760,7 @@ pub const FuncGen = struct {
17601760
1761 .array_elem_val => try self.airArrayElemVal(inst),1761 .array_elem_val => try self.airArrayElemVal(inst),
1762 .slice_elem_val => try self.airSliceElemVal(inst),1762 .slice_elem_val => try self.airSliceElemVal(inst),
1763 .slice_elem_ptr => try self.airSliceElemPtr(inst),
1763 .ptr_elem_val => try self.airPtrElemVal(inst),1764 .ptr_elem_val => try self.airPtrElemVal(inst),
1764 .ptr_elem_ptr => try self.airPtrElemPtr(inst),1765 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
17651766
...@@ -2157,12 +2158,20 @@ pub const FuncGen = struct {...@@ -2157,12 +2158,20 @@ pub const FuncGen = struct {
21572158
2158 const slice = try self.resolveInst(bin_op.lhs);2159 const slice = try self.resolveInst(bin_op.lhs);
2159 const index = try self.resolveInst(bin_op.rhs);2160 const index = try self.resolveInst(bin_op.rhs);
2160 const base_ptr = self.builder.buildExtractValue(slice, 0, "");2161 const ptr = self.sliceElemPtr(slice, index);
2161 const indices: [1]*const llvm.Value = .{index};
2162 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
2163 return self.load(ptr, slice_ty);2162 return self.load(ptr, slice_ty);
2164 }2163 }
21652164
2165 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2166 if (self.liveness.isUnused(inst)) return null;
2167 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2168 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2169
2170 const slice = try self.resolveInst(bin_op.lhs);
2171 const index = try self.resolveInst(bin_op.rhs);
2172 return self.sliceElemPtr(slice, index);
2173 }
2174
2166 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2175 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2167 if (self.liveness.isUnused(inst)) return null;2176 if (self.liveness.isUnused(inst)) return null;
21682177
...@@ -3575,6 +3584,16 @@ pub const FuncGen = struct {...@@ -3575,6 +3584,16 @@ pub const FuncGen = struct {
3575 return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");3584 return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
3576 }3585 }
35773586
3587 fn sliceElemPtr(
3588 self: *FuncGen,
3589 slice: *const llvm.Value,
3590 index: *const llvm.Value,
3591 ) *const llvm.Value {
3592 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
3593 const indices: [1]*const llvm.Value = .{index};
3594 return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
3595 }
3596
3578 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {3597 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
3579 const id = llvm.lookupIntrinsicID(name.ptr, name.len);3598 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
3580 assert(id != 0);3599 assert(id != 0);
src/print_air.zig+10
...@@ -200,6 +200,7 @@ const Writer = struct {...@@ -200,6 +200,7 @@ const Writer = struct {
200 .loop,200 .loop,
201 => try w.writeBlock(s, inst),201 => try w.writeBlock(s, inst),
202202
203 .slice_elem_ptr => try w.writeSliceElemPtr(s, inst),
203 .ptr_elem_ptr => try w.writePtrElemPtr(s, inst),204 .ptr_elem_ptr => try w.writePtrElemPtr(s, inst),
204 .struct_field_ptr => try w.writeStructField(s, inst),205 .struct_field_ptr => try w.writeStructField(s, inst),
205 .struct_field_val => try w.writeStructField(s, inst),206 .struct_field_val => try w.writeStructField(s, inst),
...@@ -281,6 +282,15 @@ const Writer = struct {...@@ -281,6 +282,15 @@ const Writer = struct {
281 try s.print(", {d}", .{extra.field_index});282 try s.print(", {d}", .{extra.field_index});
282 }283 }
283284
285 fn writeSliceElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
286 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
287 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
288
289 try w.writeOperand(s, inst, 0, extra.lhs);
290 try s.writeAll(", ");
291 try w.writeOperand(s, inst, 1, extra.rhs);
292 }
293
284 fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {294 fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
285 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;295 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
286 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;296 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
src/type.zig+14
...@@ -2520,6 +2520,20 @@ pub const Type = extern union {...@@ -2520,6 +2520,20 @@ pub const Type = extern union {
2520 };2520 };
2521 }2521 }
25222522
2523 /// Returns the type of a pointer to an element.
2524 /// Asserts that the type is a pointer, and that the element type is indexable.
2525 /// For *[N]T, return *T
2526 /// For [*]T, returns *T
2527 /// For []T, returns *T
2528 /// Handles const-ness and address spaces in particular.
2529 pub fn elemPtrType(ptr_ty: Type, arena: *Allocator) !Type {
2530 return try Type.ptr(arena, .{
2531 .pointee_type = ptr_ty.elemType2(),
2532 .mutable = ptr_ty.ptrIsMutable(),
2533 .@"addrspace" = ptr_ty.ptrAddressSpace(),
2534 });
2535 }
2536
2523 fn shallowElemType(child_ty: Type) Type {2537 fn shallowElemType(child_ty: Type) Type {
2524 return switch (child_ty.zigTypeTag()) {2538 return switch (child_ty.zigTypeTag()) {
2525 .Array, .Vector => child_ty.childType(),2539 .Array, .Vector => child_ty.childType(),
src/value.zig+17-11
...@@ -114,7 +114,7 @@ pub const Value = extern union {...@@ -114,7 +114,7 @@ pub const Value = extern union {
114 /// This Tag will never be seen by machine codegen backends. It is changed into a114 /// This Tag will never be seen by machine codegen backends. It is changed into a
115 /// `decl_ref` when a comptime variable goes out of scope.115 /// `decl_ref` when a comptime variable goes out of scope.
116 decl_ref_mut,116 decl_ref_mut,
117 /// Pointer to a specific element of an array.117 /// Pointer to a specific element of an array, vector or slice.
118 elem_ptr,118 elem_ptr,
119 /// Pointer to a specific field of a struct or union.119 /// Pointer to a specific field of a struct or union.
120 field_ptr,120 field_ptr,
...@@ -1792,17 +1792,23 @@ pub const Value = extern union {...@@ -1792,17 +1792,23 @@ pub const Value = extern union {
17921792
1793 /// Returns a pointer to the element value at the index.1793 /// Returns a pointer to the element value at the index.
1794 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {1794 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
1795 if (self.castTag(.elem_ptr)) |elem_ptr| {1795 switch (self.tag()) {
1796 return Tag.elem_ptr.create(allocator, .{1796 .elem_ptr => {
1797 .array_ptr = elem_ptr.data.array_ptr,1797 const elem_ptr = self.castTag(.elem_ptr).?.data;
1798 .index = elem_ptr.data.index + index,1798 return Tag.elem_ptr.create(allocator, .{
1799 });1799 .array_ptr = elem_ptr.array_ptr,
1800 .index = elem_ptr.index + index,
1801 });
1802 },
1803 .slice => return Tag.elem_ptr.create(allocator, .{
1804 .array_ptr = self.castTag(.slice).?.data.ptr,
1805 .index = index,
1806 }),
1807 else => return Tag.elem_ptr.create(allocator, .{
1808 .array_ptr = self,
1809 .index = index,
1810 }),
1800 }1811 }
1801
1802 return Tag.elem_ptr.create(allocator, .{
1803 .array_ptr = self,
1804 .index = index,
1805 });
1806 }1812 }
18071813
1808 pub fn isUndef(self: Value) bool {1814 pub fn isUndef(self: Value) bool {