| author | |
| committer | |
| log | d49c601d623d0b5a90f47c95cb931fe21a13d89e |
| tree | 76f107482d2b7bcf6279ce469da566df4197dc34 |
| parent | e2a2e6c14fe181989187d6b59a79c5fc32961250 |
| parent | fc034ca94f0682a06795616992f176f19ec9a83d |
| signature |
stage2: More elemVal and elemPtr stuff10 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 | } |
| 335 | 335 | ||
| 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 | } |
| 11489 | 11517 | ||
| 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 | } |
| 11492 | 11563 | ||
| 11493 | fn elemVal( | 11564 | fn 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 location | 11572 | 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; |
| 11514 | 11590 | ||
| 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 | } |
| 11610 | 11635 | ||
| ... | @@ -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 | }); | ||
| 11626 | 11646 | ||
| 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 bounds | 11657 | // 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 | } |
| 11650 | 11661 | ||
| 11651 | fn coerce( | 11662 | fn 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 { |
| 500 | 500 | ||
| 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), | ||
| 507 | 506 | ||
| 508 | .constant => unreachable, // excluded from function bodies | 507 | .constant => unreachable, // excluded from function bodies |
| 509 | .const_ty => unreachable, // excluded from function bodies | 508 | .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 | } |
| 1088 | 1087 | ||
| 1089 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1088 | fn 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 | } |
| 1094 | 1094 | ||
| 1095 | fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 1095 | fn 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 | } |
| 1101 | 1100 | ||
| ... | @@ -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 | } |
| 1115 | 1114 | ||
| 1116 | fn 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 | |||
| 1123 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 1115 | fn 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 { |
| 848 | 848 | ||
| 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), | ||
| 855 | 854 | ||
| 856 | .constant => unreachable, // excluded from function bodies | 855 | .constant => unreachable, // excluded from function bodies |
| 857 | .const_ty => unreachable, // excluded from function bodies | 856 | .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 | } |
| 1537 | 1536 | ||
| 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 | } |
| 1545 | 1545 | ||
| 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 | } |
| 1572 | 1571 | ||
| 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"), |
| 1082 | 1082 | ||
| 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), |
| 1089 | 1088 | ||
| 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 | } |
| 1169 | 1168 | ||
| 1169 | fn 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 | |||
| 1170 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 1187 | fn 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; |
| 1172 | 1189 |
src/codegen/llvm.zig+19-33| ... | @@ -1760,10 +1760,9 @@ pub const FuncGen = struct { | ... | @@ -1760,10 +1760,9 @@ pub const FuncGen = struct { |
| 1760 | 1760 | ||
| 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), | ||
| 1767 | 1766 | ||
| 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 { |
| 2159 | 2158 | ||
| 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 | } |
| 2167 | 2164 | ||
| 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 | }; | ||
| 2180 | 2169 | ||
| 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 | } |
| 2185 | 2174 | ||
| 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 | } |
| 2242 | 2231 | ||
| 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 | } |
| 3610 | 3586 | ||
| 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), |
| 204 | 202 | ||
| 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 | } |
| 285 | 284 | ||
| 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 | } |
| 2522 | 2522 | ||
| 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 a | 114 | /// 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 { |
| 1792 | 1792 | ||
| 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 | } |
| 1807 | 1813 | ||
| 1808 | pub fn isUndef(self: Value) bool { | 1814 | pub fn isUndef(self: Value) bool { |