authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-21 17:12:04-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-10-21 17:12:04-04:00
logd49c601d623d0b5a90f47c95cb931fe21a13d89e
tree76f107482d2b7bcf6279ce469da566df4197dc34
parente2a2e6c14fe181989187d6b59a79c5fc32961250
parentfc034ca94f0682a06795616992f176f19ec9a83d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9993 from Snektron/more-field-elem

stage2: More elemVal and elemPtr stuff

10 files changed, 225 insertions(+), 212 deletions(-)

src/Air.zig+5-14
...@@ -384,10 +384,10 @@ pub const Inst = struct {...@@ -384,10 +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 pointer to a slice, and element index, return the element value at that index.387 /// Given a slice value and element index, return a pointer to the element value at that index.
388 /// Result type is the element type of the slice operand (2 element type operations).388 /// Result type is a pointer to the element type of the slice operand.
389 /// Uses the `bin_op` field.389 /// Uses the `ty_pl` field with payload `Bin`.
390 ptr_slice_elem_val,390 slice_elem_ptr,
391 /// 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.
392 /// Result type is the element type of the pointer operand.392 /// Result type is the element type of the pointer operand.
393 /// Uses the `bin_op` field.393 /// Uses the `bin_op` field.
...@@ -396,11 +396,6 @@ pub const Inst = struct {...@@ -396,11 +396,6 @@ pub const Inst = struct {
396 /// Result type is pointer to the element type of the pointer operand.396 /// Result type is pointer to the element type of the pointer operand.
397 /// Uses the `ty_pl` field with payload `Bin`.397 /// Uses the `ty_pl` field with payload `Bin`.
398 ptr_elem_ptr,398 ptr_elem_ptr,
399 /// Given a pointer to a pointer, and element index, return the element value of the inner
400 /// pointer at that index.
401 /// Result type is the element type of the inner pointer operand.
402 /// Uses the `bin_op` field.
403 ptr_ptr_elem_val,
404 /// Given a pointer to an array, return a slice.399 /// Given a pointer to an array, return a slice.
405 /// Uses the `ty_op` field.400 /// Uses the `ty_op` field.
406 array_to_slice,401 array_to_slice,
...@@ -694,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -694,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
694 .constant,689 .constant,
695 .struct_field_ptr,690 .struct_field_ptr,
696 .struct_field_val,691 .struct_field_val,
692 .slice_elem_ptr,
697 .ptr_elem_ptr,693 .ptr_elem_ptr,
698 .cmpxchg_weak,694 .cmpxchg_weak,
699 .cmpxchg_strong,695 .cmpxchg_strong,
...@@ -772,11 +768,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -772,11 +768,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
772 const ptr_ty = air.typeOf(datas[inst].bin_op.lhs);768 const ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
773 return ptr_ty.elemType();769 return ptr_ty.elemType();
774 },770 },
775 .ptr_slice_elem_val, .ptr_ptr_elem_val => {
776 const outer_ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
777 const inner_ptr_ty = outer_ptr_ty.elemType();
778 return inner_ptr_ty.elemType();
779 },
780 .atomic_load => {771 .atomic_load => {
781 const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr);772 const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr);
782 return ptr_ty.elemType();773 return ptr_ty.elemType();
src/Liveness.zig+1-3
...@@ -252,9 +252,7 @@ fn analyzeInst(...@@ -252,9 +252,7 @@ fn analyzeInst(
252 .store,252 .store,
253 .array_elem_val,253 .array_elem_val,
254 .slice_elem_val,254 .slice_elem_val,
255 .ptr_slice_elem_val,
256 .ptr_elem_val,255 .ptr_elem_val,
257 .ptr_ptr_elem_val,
258 .shl,256 .shl,
259 .shl_exact,257 .shl_exact,
260 .shl_sat,258 .shl_sat,
...@@ -362,7 +360,7 @@ fn analyzeInst(...@@ -362,7 +360,7 @@ fn analyzeInst(
362 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;
363 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 });
364 },362 },
365 .ptr_elem_ptr => {363 .ptr_elem_ptr, .slice_elem_ptr => {
366 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;
367 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 });
368 },366 },
src/Sema.zig+123-112
...@@ -333,6 +333,42 @@ pub const Block = struct {...@@ -333,6 +333,42 @@ 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
354 pub fn addPtrElemPtr(
355 block: *Block,
356 array_ptr: Air.Inst.Ref,
357 elem_index: Air.Inst.Ref,
358 elem_ptr_ty: Type,
359 ) !Air.Inst.Ref {
360 return block.addInst(.{
361 .tag = .ptr_elem_ptr,
362 .data = .{ .ty_pl = .{
363 .ty = try block.sema.addType(elem_ptr_ty),
364 .payload = try block.sema.addExtra(Air.Bin{
365 .lhs = array_ptr,
366 .rhs = elem_index,
367 }),
368 } },
369 });
370 }
371
336 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {372 pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
337 return Air.indexToRef(try block.addInstAsIndex(inst));373 return Air.indexToRef(try block.addInstAsIndex(inst));
338 }374 }
...@@ -11476,135 +11512,124 @@ fn elemPtr(...@@ -11476,135 +11512,124 @@ fn elemPtr(
11476 else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}),11512 else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}),
11477 };11513 };
11478 if (!array_ty.isIndexable()) {11514 if (!array_ty.isIndexable()) {
11479 return sema.fail(block, src, "array access of non-array type '{}'", .{array_ty});11515 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 }11516 }
1148911517
11490 return sema.fail(block, src, "TODO implement more analyze elemptr", .{});11518 switch (array_ty.zigTypeTag()) {
11519 .Pointer => {
11520 // In all below cases, we have to deref the ptr operand to get the actual array pointer.
11521 const array = try sema.analyzeLoad(block, array_ptr_src, array_ptr, array_ptr_src);
11522 const result_ty = try array_ty.elemPtrType(sema.arena);
11523 switch (array_ty.ptrSize()) {
11524 .Slice => {
11525 const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
11526 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11527 const runtime_src = if (maybe_slice_val) |slice_val| rs: {
11528 const index_val = maybe_index_val orelse break :rs elem_index_src;
11529 const index = @intCast(usize, index_val.toUnsignedInt());
11530 const elem_ptr = try slice_val.elemPtr(sema.arena, index);
11531 return sema.addConstant(result_ty, elem_ptr);
11532 } else array_ptr_src;
11533
11534 try sema.requireRuntimeBlock(block, runtime_src);
11535 return block.addSliceElemPtr(array, elem_index, result_ty);
11536 },
11537 .Many, .C => {
11538 const maybe_ptr_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
11539 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11540
11541 const runtime_src = rs: {
11542 const ptr_val = maybe_ptr_val orelse break :rs array_ptr_src;
11543 const index_val = maybe_index_val orelse break :rs elem_index_src;
11544 const index = @intCast(usize, index_val.toUnsignedInt());
11545 const elem_ptr = try ptr_val.elemPtr(sema.arena, index);
11546 return sema.addConstant(result_ty, elem_ptr);
11547 };
11548
11549 try sema.requireRuntimeBlock(block, runtime_src);
11550 return block.addPtrElemPtr(array, elem_index, result_ty);
11551 },
11552 .One => {
11553 assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
11554 return sema.elemPtrArray(block, array_ptr_src, array, elem_index, elem_index_src);
11555 },
11556 }
11557 },
11558 .Array => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src),
11559 .Vector => return sema.fail(block, src, "TODO implement Sema for elemPtr for vector", .{}),
11560 else => unreachable,
11561 }
11491}11562}
1149211563
11493fn elemVal(11564fn elemVal(
11494 sema: *Sema,11565 sema: *Sema,
11495 block: *Block,11566 block: *Block,
11496 src: LazySrcLoc,11567 src: LazySrcLoc,
11497 array_maybe_ptr: Air.Inst.Ref,11568 array: Air.Inst.Ref,
11498 elem_index: Air.Inst.Ref,11569 elem_index: Air.Inst.Ref,
11499 elem_index_src: LazySrcLoc,11570 elem_index_src: LazySrcLoc,
11500) CompileError!Air.Inst.Ref {11571) CompileError!Air.Inst.Ref {
11501 const array_ptr_src = src; // TODO better source location11572 const array_src = src; // TODO better source location
11502 const maybe_ptr_ty = sema.typeOf(array_maybe_ptr);11573 const array_ty = sema.typeOf(array);
11503 switch (maybe_ptr_ty.zigTypeTag()) {11574
11504 .Pointer => switch (maybe_ptr_ty.ptrSize()) {11575 if (!array_ty.isIndexable()) {
11576 return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty});
11577 }
11578
11579 switch (array_ty.zigTypeTag()) {
11580 .Pointer => switch (array_ty.ptrSize()) {
11505 .Slice => {11581 .Slice => {
11506 const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array_maybe_ptr);11582 const maybe_slice_val = try sema.resolveDefinedValue(block, array_src, array);
11507 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);11583 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11508 const runtime_src = if (maybe_slice_val) |slice_val| rs: {11584 const runtime_src = if (maybe_slice_val) |slice_val| rs: {
11509 const index_val = maybe_index_val orelse break :rs elem_index_src;11585 const index_val = maybe_index_val orelse break :rs elem_index_src;
11510 const index = @intCast(usize, index_val.toUnsignedInt());11586 const index = @intCast(usize, index_val.toUnsignedInt());
11511 const elem_val = try slice_val.elemValue(sema.arena, index);11587 const elem_val = try slice_val.elemValue(sema.arena, index);
11512 return sema.addConstant(maybe_ptr_ty.elemType2(), elem_val);11588 return sema.addConstant(array_ty.elemType2(), elem_val);
11513 } else array_ptr_src;11589 } else array_src;
1151411590
11515 try sema.requireRuntimeBlock(block, runtime_src);11591 try sema.requireRuntimeBlock(block, runtime_src);
11516 return block.addBinOp(.slice_elem_val, array_maybe_ptr, elem_index);11592 return block.addBinOp(.slice_elem_val, array, elem_index);
11517 },11593 },
11518 .Many, .C => {11594 .Many, .C => {
11519 if (try sema.resolveDefinedValue(block, src, array_maybe_ptr)) |ptr_val| {11595 const maybe_ptr_val = try sema.resolveDefinedValue(block, array_src, array);
11520 _ = ptr_val;11596 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11521 return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known pointer", .{});11597
11522 }11598 const runtime_src = rs: {
11523 try sema.requireRuntimeBlock(block, src);11599 const ptr_val = maybe_ptr_val orelse break :rs array_src;
11524 return block.addBinOp(.ptr_elem_val, array_maybe_ptr, elem_index);11600 const index_val = maybe_index_val orelse break :rs elem_index_src;
11601 const index = @intCast(usize, index_val.toUnsignedInt());
11602 const maybe_array_val = try ptr_val.pointerDeref(sema.arena);
11603 const array_val = maybe_array_val orelse break :rs array_src;
11604 const elem_val = try array_val.elemValue(sema.arena, index);
11605 return sema.addConstant(array_ty.elemType2(), elem_val);
11606 };
11607
11608 try sema.requireRuntimeBlock(block, runtime_src);
11609 return block.addBinOp(.ptr_elem_val, array, elem_index);
11525 },11610 },
11526 .One => {11611 .One => {
11527 const indexable_ty = maybe_ptr_ty.childType();11612 assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
11528 switch (indexable_ty.zigTypeTag()) {11613 const elem_ptr = try sema.elemPtr(block, array_src, array, elem_index, elem_index_src);
11529 .Pointer => switch (indexable_ty.ptrSize()) {11614 return sema.analyzeLoad(block, array_src, elem_ptr, elem_index_src);
11530 .Slice => {
11531 // We have a pointer to a slice and we want an element value.
11532 if (try sema.isComptimeKnown(block, src, array_maybe_ptr)) {
11533 const slice = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
11534 if (try sema.resolveDefinedValue(block, src, slice)) |slice_val| {
11535 _ = slice_val;
11536 return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known slice", .{});
11537 }
11538 try sema.requireRuntimeBlock(block, src);
11539 return block.addBinOp(.slice_elem_val, slice, elem_index);
11540 }
11541 try sema.requireRuntimeBlock(block, src);
11542 return block.addBinOp(.ptr_slice_elem_val, array_maybe_ptr, elem_index);
11543 },
11544 .Many, .C => {
11545 // We have a pointer to a pointer and we want an element value.
11546 if (try sema.isComptimeKnown(block, src, array_maybe_ptr)) {
11547 const ptr = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
11548 if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
11549 _ = ptr_val;
11550 return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known pointer", .{});
11551 }
11552 try sema.requireRuntimeBlock(block, src);
11553 return block.addBinOp(.ptr_elem_val, ptr, elem_index);
11554 }
11555 try sema.requireRuntimeBlock(block, src);
11556 return block.addBinOp(.ptr_ptr_elem_val, array_maybe_ptr, elem_index);
11557 },
11558 .One => {
11559 const array_ty = indexable_ty.childType();
11560 if (array_ty.zigTypeTag() == .Array) {
11561 // We have a double pointer to an array, and we want an element
11562 // value. This can happen with this code for example:
11563 // var a: *[1]u8 = undefined; _ = a[0];
11564 const array_ptr = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
11565 const ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
11566 return sema.analyzeLoad(block, src, ptr, elem_index_src);
11567 } else return sema.fail(
11568 block,
11569 array_ptr_src,
11570 "expected pointer, found '{}'",
11571 .{array_ty},
11572 );
11573 },
11574 },
11575 .Array => {
11576 const ptr = try sema.elemPtr(block, src, array_maybe_ptr, elem_index, elem_index_src);
11577 return sema.analyzeLoad(block, src, ptr, elem_index_src);
11578 },
11579 else => return sema.fail(
11580 block,
11581 array_ptr_src,
11582 "expected pointer, found '{}'",
11583 .{indexable_ty},
11584 ),
11585 }
11586 },11615 },
11587 },11616 },
11588 .Array => {11617 .Array => {
11589 if (try sema.resolveMaybeUndefVal(block, src, array_maybe_ptr)) |array_val| {11618 if (try sema.resolveMaybeUndefVal(block, array_src, array)) |array_val| {
11590 const elem_ty = maybe_ptr_ty.childType();11619 const elem_ty = array_ty.childType();
11591 const opt_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11592 if (array_val.isUndef()) return sema.addConstUndef(elem_ty);11620 if (array_val.isUndef()) return sema.addConstUndef(elem_ty);
11593 if (opt_index_val) |index_val| {11621 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
11622 if (maybe_index_val) |index_val| {
11594 const index = @intCast(usize, index_val.toUnsignedInt());11623 const index = @intCast(usize, index_val.toUnsignedInt());
11595 const elem_val = try array_val.elemValue(sema.arena, index);11624 const elem_val = try array_val.elemValue(sema.arena, index);
11596 return sema.addConstant(elem_ty, elem_val);11625 return sema.addConstant(elem_ty, elem_val);
11597 }11626 }
11598 }11627 }
11599 try sema.requireRuntimeBlock(block, src);11628 try sema.requireRuntimeBlock(block, array_src);
11600 return block.addBinOp(.array_elem_val, array_maybe_ptr, elem_index);11629 return block.addBinOp(.array_elem_val, array, elem_index);
11601 },11630 },
11602 else => return sema.fail(11631 .Vector => return sema.fail(block, array_src, "TODO implement Sema for elemVal for vector", .{}),
11603 block,11632 else => unreachable,
11604 array_ptr_src,
11605 "expected pointer or array; found '{}'",
11606 .{maybe_ptr_ty},
11607 ),
11608 }11633 }
11609}11634}
1161011635
...@@ -11617,12 +11642,7 @@ fn elemPtrArray(...@@ -11617,12 +11642,7 @@ fn elemPtrArray(
11617 elem_index_src: LazySrcLoc,11642 elem_index_src: LazySrcLoc,
11618) CompileError!Air.Inst.Ref {11643) CompileError!Air.Inst.Ref {
11619 const array_ptr_ty = sema.typeOf(array_ptr);11644 const array_ptr_ty = sema.typeOf(array_ptr);
11620 const pointee_type = array_ptr_ty.elemType().elemType();11645 const result_ty = try array_ptr_ty.elemPtrType(sema.arena);
11621 const result_ty = try Type.ptr(sema.arena, .{
11622 .pointee_type = pointee_type,
11623 .mutable = array_ptr_ty.ptrIsMutable(),
11624 .@"addrspace" = array_ptr_ty.ptrAddressSpace(),
11625 });
1162611646
11627 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {11647 if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
11628 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {11648 if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
...@@ -11636,16 +11656,7 @@ fn elemPtrArray(...@@ -11636,16 +11656,7 @@ fn elemPtrArray(
11636 }11656 }
11637 // TODO safety check for array bounds11657 // TODO safety check for array bounds
11638 try sema.requireRuntimeBlock(block, src);11658 try sema.requireRuntimeBlock(block, src);
11639 return block.addInst(.{11659 return block.addPtrElemPtr(array_ptr, elem_index, result_ty);
11640 .tag = .ptr_elem_ptr,
11641 .data = .{ .ty_pl = .{
11642 .ty = try sema.addType(result_ty),
11643 .payload = try sema.addExtra(Air.Bin{
11644 .lhs = array_ptr,
11645 .rhs = elem_index,
11646 }),
11647 } },
11648 });
11649}11660}
1165011661
11651fn coerce(11662fn coerce(
src/arch/aarch64/CodeGen.zig+8-16
...@@ -500,10 +500,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -500,10 +500,9 @@ 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 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),503 .slice_elem_ptr => try self.airSliceElemPtr(inst),
504 .ptr_elem_val => try self.airPtrElemVal(inst),504 .ptr_elem_val => try self.airPtrElemVal(inst),
505 .ptr_elem_ptr => try self.airPtrElemPtr(inst),505 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
506 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
507506
508 .constant => unreachable, // excluded from function bodies507 .constant => unreachable, // excluded from function bodies
509 .const_ty => unreachable, // excluded from function bodies508 .const_ty => unreachable, // excluded from function bodies
...@@ -1086,16 +1085,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -1086,16 +1085,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
1086 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 });
1087}1086}
10881087
1089fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {1088fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1090 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1089 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1091 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});1090 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1092 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });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}1093}
10941094
1095fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1095fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1096 const is_volatile = false; // TODO
1097 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1096 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1098 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_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});
1099 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1098 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1100}1099}
11011100
...@@ -1113,13 +1112,6 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1113,13 +1112,6 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1113 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });1112 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1114}1113}
11151114
1116fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
1117 const is_volatile = false; // TODO
1118 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1119 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_ptr_elem_val for {}", .{self.target.cpu.arch});
1120 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1121}
1122
1123fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {1115fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
1124 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1116 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1125 _ = bin_op;1117 _ = bin_op;
src/codegen.zig+9-19
...@@ -848,10 +848,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -848,10 +848,9 @@ 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 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),851 .slice_elem_ptr => try self.airSliceElemPtr(inst),
852 .ptr_elem_val => try self.airPtrElemVal(inst),852 .ptr_elem_val => try self.airPtrElemVal(inst),
853 .ptr_elem_ptr => try self.airPtrElemPtr(inst),853 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
854 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
855854
856 .constant => unreachable, // excluded from function bodies855 .constant => unreachable, // excluded from function bodies
857 .const_ty => unreachable, // excluded from function bodies856 .const_ty => unreachable, // excluded from function bodies
...@@ -1535,19 +1534,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1535,19 +1534,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1535 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 });
1536 }1535 }
15371536
1538 fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {1537 fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
1539 const bin_op = self.air.instructions.items(.data)[inst].bin_op;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) {1540 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1541 else => return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch}),1541 else => return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}),
1542 };1542 };
1543 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1543 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1544 }1544 }
15451545
1546 fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {1546 fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
1547 const is_volatile = false; // TODO
1548 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1547 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1549 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else switch (arch) {1548 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1550 else => return self.fail("TODO implement ptr_slice_elem_val for {}", .{self.target.cpu.arch}),1549 else => return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch}),
1551 };1550 };
1552 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1551 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1553 }1552 }
...@@ -1570,15 +1569,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1570,15 +1569,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1570 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });1569 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
1571 }1570 }
15721571
1573 fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
1574 const is_volatile = false; // TODO
1575 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1576 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else switch (arch) {
1577 else => return self.fail("TODO implement ptr_ptr_elem_val for {}", .{self.target.cpu.arch}),
1578 };
1579 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1580 }
1581
1582 fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {1572 fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
1583 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1573 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1584 const result: MCValue = switch (arch) {1574 const result: MCValue = switch (arch) {
src/codegen/c.zig+19-2
...@@ -1081,10 +1081,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1081,10 +1081,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1081 .ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"),1081 .ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"),
10821082
1083 .ptr_elem_val => try airPtrElemVal(f, inst, "["),1083 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
1084 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
1085 .ptr_elem_ptr => try airPtrElemPtr(f, inst),1084 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
1086 .slice_elem_val => try airSliceElemVal(f, inst, "["),1085 .slice_elem_val => try airSliceElemVal(f, inst, "["),
1087 .ptr_slice_elem_val => try airSliceElemVal(f, inst, "[0]["),1086 .slice_elem_ptr => try airSliceElemPtr(f, inst),
1088 .array_elem_val => try airArrayElemVal(f, inst),1087 .array_elem_val => try airArrayElemVal(f, inst),
10891088
1090 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),1089 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
...@@ -1167,6 +1166,24 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CVal...@@ -1167,6 +1166,24 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CVal
1167 return local;1166 return local;
1168}1167}
11691168
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
1170fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {1187fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
1171 if (f.liveness.isUnused(inst)) return CValue.none;1188 if (f.liveness.isUnused(inst)) return CValue.none;
11721189
src/codegen/llvm.zig+19-33
...@@ -1760,10 +1760,9 @@ pub const FuncGen = struct {...@@ -1760,10 +1760,9 @@ 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 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),1763 .slice_elem_ptr => try self.airSliceElemPtr(inst),
1764 .ptr_elem_val => try self.airPtrElemVal(inst),1764 .ptr_elem_val => try self.airPtrElemVal(inst),
1765 .ptr_elem_ptr => try self.airPtrElemPtr(inst),1765 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
1766 .ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
17671766
1768 .optional_payload => try self.airOptionalPayload(inst, false),1767 .optional_payload => try self.airOptionalPayload(inst, false),
1769 .optional_payload_ptr => try self.airOptionalPayload(inst, true),1768 .optional_payload_ptr => try self.airOptionalPayload(inst, true),
...@@ -2159,28 +2158,18 @@ pub const FuncGen = struct {...@@ -2159,28 +2158,18 @@ pub const FuncGen = struct {
21592158
2160 const slice = try self.resolveInst(bin_op.lhs);2159 const slice = try self.resolveInst(bin_op.lhs);
2161 const index = try self.resolveInst(bin_op.rhs);2160 const index = try self.resolveInst(bin_op.rhs);
2162 const base_ptr = self.builder.buildExtractValue(slice, 0, "");2161 const ptr = self.sliceElemPtr(slice, index);
2163 const indices: [1]*const llvm.Value = .{index};
2164 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
2165 return self.load(ptr, slice_ty);2162 return self.load(ptr, slice_ty);
2166 }2163 }
21672164
2168 fn airPtrSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2165 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2169 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2166 if (self.liveness.isUnused(inst)) return null;
2170 const slice_ty = self.air.typeOf(bin_op.lhs).childType();2167 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2171 if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;2168 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2172
2173 const lhs = try self.resolveInst(bin_op.lhs);
2174 const rhs = try self.resolveInst(bin_op.rhs);
2175
2176 const base_ptr = ptr: {
2177 const ptr_field_ptr = self.builder.buildStructGEP(lhs, 0, "");
2178 break :ptr self.builder.buildLoad(ptr_field_ptr, "");
2179 };
21802169
2181 const indices: [1]*const llvm.Value = .{rhs};2170 const slice = try self.resolveInst(bin_op.lhs);
2182 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");2171 const index = try self.resolveInst(bin_op.rhs);
2183 return self.load(ptr, slice_ty);2172 return self.sliceElemPtr(slice, index);
2184 }2173 }
21852174
2186 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2175 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -2240,19 +2229,6 @@ pub const FuncGen = struct {...@@ -2240,19 +2229,6 @@ pub const FuncGen = struct {
2240 }2229 }
2241 }2230 }
22422231
2243 fn airPtrPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2244 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2245 const ptr_ty = self.air.typeOf(bin_op.lhs).childType();
2246 if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
2247
2248 const lhs = try self.resolveInst(bin_op.lhs);
2249 const rhs = try self.resolveInst(bin_op.rhs);
2250 const base_ptr = self.builder.buildLoad(lhs, "");
2251 const indices: [1]*const llvm.Value = .{rhs};
2252 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
2253 return self.load(ptr, ptr_ty);
2254 }
2255
2256 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2232 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2257 if (self.liveness.isUnused(inst))2233 if (self.liveness.isUnused(inst))
2258 return null;2234 return null;
...@@ -3608,6 +3584,16 @@ pub const FuncGen = struct {...@@ -3608,6 +3584,16 @@ pub const FuncGen = struct {
3608 return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");3584 return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
3609 }3585 }
36103586
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
3611 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {3597 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
3612 const id = llvm.lookupIntrinsicID(name.ptr, name.len);3598 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
3613 assert(id != 0);3599 assert(id != 0);
src/print_air.zig+10-2
...@@ -130,9 +130,7 @@ const Writer = struct {...@@ -130,9 +130,7 @@ const Writer = struct {
130 .store,130 .store,
131 .array_elem_val,131 .array_elem_val,
132 .slice_elem_val,132 .slice_elem_val,
133 .ptr_slice_elem_val,
134 .ptr_elem_val,133 .ptr_elem_val,
135 .ptr_ptr_elem_val,
136 .shl,134 .shl,
137 .shl_exact,135 .shl_exact,
138 .shl_sat,136 .shl_sat,
...@@ -202,6 +200,7 @@ const Writer = struct {...@@ -202,6 +200,7 @@ const Writer = struct {
202 .loop,200 .loop,
203 => try w.writeBlock(s, inst),201 => try w.writeBlock(s, inst),
204202
203 .slice_elem_ptr => try w.writeSliceElemPtr(s, inst),
205 .ptr_elem_ptr => try w.writePtrElemPtr(s, inst),204 .ptr_elem_ptr => try w.writePtrElemPtr(s, inst),
206 .struct_field_ptr => try w.writeStructField(s, inst),205 .struct_field_ptr => try w.writeStructField(s, inst),
207 .struct_field_val => try w.writeStructField(s, inst),206 .struct_field_val => try w.writeStructField(s, inst),
...@@ -283,6 +282,15 @@ const Writer = struct {...@@ -283,6 +282,15 @@ const Writer = struct {
283 try s.print(", {d}", .{extra.field_index});282 try s.print(", {d}", .{extra.field_index});
284 }283 }
285284
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
286 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 {
287 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;295 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
288 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 {