| author | |
| committer | |
| log | 09c7d5aebc4f7fe96a89f93c0cf99cc03977ea5f |
| tree | 7877d79040b38f43aea7fc192546b19d07821bc0 |
| parent | 84876fec582e13707a809c8136bb1eaf92b5da09 |
* 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 slices10 files changed, 157 insertions(+), 32 deletions(-)
src/Air.zig+5| ... | ... | @@ -384,6 +384,10 @@ pub const Inst = struct { |
| 384 | 384 | /// Result type is the element type of the slice operand. |
| 385 | 385 | /// Uses the `bin_op` field. |
| 386 | 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 | 391 | /// Given a pointer value, and element index, return the element value at that index. |
| 388 | 392 | /// Result type is the element type of the pointer operand. |
| 389 | 393 | /// Uses the `bin_op` field. |
| ... | ... | @@ -685,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 685 | 689 | .constant, |
| 686 | 690 | .struct_field_ptr, |
| 687 | 691 | .struct_field_val, |
| 692 | .slice_elem_ptr, | |
| 688 | 693 | .ptr_elem_ptr, |
| 689 | 694 | .cmpxchg_weak, |
| 690 | 695 | .cmpxchg_strong, |
src/Liveness.zig+1-1| ... | ... | @@ -360,7 +360,7 @@ fn analyzeInst( |
| 360 | 360 | const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data; |
| 361 | 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 | 364 | const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data; |
| 365 | 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 | 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 | ||
| 336 | 354 | pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { |
| 337 | 355 | return Air.indexToRef(try block.addInstAsIndex(inst)); |
| 338 | 356 | } |
| ... | ... | @@ -11476,18 +11494,39 @@ fn elemPtr( |
| 11476 | 11494 | else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}), |
| 11477 | 11495 | }; |
| 11478 | 11496 | if (!array_ty.isIndexable()) { |
| 11479 | return sema.fail(block, src, "array access of non-array 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); | |
| 11497 | return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty}); | |
| 11488 | 11498 | } |
| 11489 | 11499 | |
| 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 | } |
| 11492 | 11531 | |
| 11493 | 11532 | fn elemVal( |
| ... | ... | @@ -11529,7 +11568,7 @@ fn elemVal( |
| 11529 | 11568 | return block.addBinOp(.ptr_elem_val, array, elem_index); |
| 11530 | 11569 | }, |
| 11531 | 11570 | .One => { |
| 11532 | assert(array_ty.childType().zigTypeTag() == .Array); | |
| 11571 | assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable | |
| 11533 | 11572 | const elem_ptr = try sema.elemPtr(block, src, array, elem_index, elem_index_src); |
| 11534 | 11573 | return sema.analyzeLoad(block, src, elem_ptr, elem_index_src); |
| 11535 | 11574 | }, |
| ... | ... | @@ -11562,12 +11601,7 @@ fn elemPtrArray( |
| 11562 | 11601 | elem_index_src: LazySrcLoc, |
| 11563 | 11602 | ) CompileError!Air.Inst.Ref { |
| 11564 | 11603 | const array_ptr_ty = sema.typeOf(array_ptr); |
| 11565 | const pointee_type = array_ptr_ty.elemType().elemType(); | |
| 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 | }); | |
| 11604 | const result_ty = try array_ptr_ty.elemPtrType(sema.arena); | |
| 11571 | 11605 | |
| 11572 | 11606 | if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| { |
| 11573 | 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 | 500 | |
| 501 | 501 | .array_elem_val => try self.airArrayElemVal(inst), |
| 502 | 502 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 503 | .slice_elem_ptr => try self.airSliceElemPtr(inst), | |
| 503 | 504 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 504 | 505 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 505 | 506 | |
| ... | ... | @@ -1084,6 +1085,13 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1084 | 1085 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1085 | 1086 | } |
| 1086 | 1087 | |
| 1088 | fn 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 | ||
| 1087 | 1095 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1088 | 1096 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1089 | 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 | 848 | |
| 849 | 849 | .array_elem_val => try self.airArrayElemVal(inst), |
| 850 | 850 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 851 | .slice_elem_ptr => try self.airSliceElemPtr(inst), | |
| 851 | 852 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 852 | 853 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 853 | 854 | |
| ... | ... | @@ -1533,6 +1534,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1533 | 1534 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1534 | 1535 | } |
| 1535 | 1536 | |
| 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 | 1546 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 1537 | 1547 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1538 | 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 | 1083 | .ptr_elem_val => try airPtrElemVal(f, inst, "["), |
| 1084 | 1084 | .ptr_elem_ptr => try airPtrElemPtr(f, inst), |
| 1085 | 1085 | .slice_elem_val => try airSliceElemVal(f, inst, "["), |
| 1086 | .slice_elem_ptr => try airSliceElemPtr(f, inst), | |
| 1086 | 1087 | .array_elem_val => try airArrayElemVal(f, inst), |
| 1087 | 1088 | |
| 1088 | 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 | 1166 | return local; |
| 1166 | 1167 | } |
| 1167 | 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 | ||
| 1168 | 1187 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1169 | 1188 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 1170 | 1189 |
src/codegen/llvm.zig+22-3| ... | ... | @@ -1760,6 +1760,7 @@ pub const FuncGen = struct { |
| 1760 | 1760 | |
| 1761 | 1761 | .array_elem_val => try self.airArrayElemVal(inst), |
| 1762 | 1762 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 1763 | .slice_elem_ptr => try self.airSliceElemPtr(inst), | |
| 1763 | 1764 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 1764 | 1765 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 1765 | 1766 | |
| ... | ... | @@ -2157,12 +2158,20 @@ pub const FuncGen = struct { |
| 2157 | 2158 | |
| 2158 | 2159 | const slice = try self.resolveInst(bin_op.lhs); |
| 2159 | 2160 | const index = try self.resolveInst(bin_op.rhs); |
| 2160 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); | |
| 2161 | const indices: [1]*const llvm.Value = .{index}; | |
| 2162 | const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, ""); | |
| 2161 | const ptr = self.sliceElemPtr(slice, index); | |
| 2163 | 2162 | return self.load(ptr, slice_ty); |
| 2164 | 2163 | } |
| 2165 | 2164 | |
| 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 | 2175 | fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 2167 | 2176 | if (self.liveness.isUnused(inst)) return null; |
| 2168 | 2177 | |
| ... | ... | @@ -3575,6 +3584,16 @@ pub const FuncGen = struct { |
| 3575 | 3584 | return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, ""); |
| 3576 | 3585 | } |
| 3577 | 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 | ||
| 3578 | 3597 | fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value { |
| 3579 | 3598 | const id = llvm.lookupIntrinsicID(name.ptr, name.len); |
| 3580 | 3599 | assert(id != 0); |
src/print_air.zig+10| ... | ... | @@ -200,6 +200,7 @@ const Writer = struct { |
| 200 | 200 | .loop, |
| 201 | 201 | => try w.writeBlock(s, inst), |
| 202 | 202 | |
| 203 | .slice_elem_ptr => try w.writeSliceElemPtr(s, inst), | |
| 203 | 204 | .ptr_elem_ptr => try w.writePtrElemPtr(s, inst), |
| 204 | 205 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 205 | 206 | .struct_field_val => try w.writeStructField(s, inst), |
| ... | ... | @@ -281,6 +282,15 @@ const Writer = struct { |
| 281 | 282 | try s.print(", {d}", .{extra.field_index}); |
| 282 | 283 | } |
| 283 | 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 | ||
| 284 | 294 | fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 285 | 295 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 286 | 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 | 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 | 2537 | fn shallowElemType(child_ty: Type) Type { |
| 2524 | 2538 | return switch (child_ty.zigTypeTag()) { |
| 2525 | 2539 | .Array, .Vector => child_ty.childType(), |
src/value.zig+17-11| ... | ... | @@ -114,7 +114,7 @@ pub const Value = extern union { |
| 114 | 114 | /// This Tag will never be seen by machine codegen backends. It is changed into a |
| 115 | 115 | /// `decl_ref` when a comptime variable goes out of scope. |
| 116 | 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 | 118 | elem_ptr, |
| 119 | 119 | /// Pointer to a specific field of a struct or union. |
| 120 | 120 | field_ptr, |
| ... | ... | @@ -1792,17 +1792,23 @@ pub const Value = extern union { |
| 1792 | 1792 | |
| 1793 | 1793 | /// Returns a pointer to the element value at the index. |
| 1794 | 1794 | pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value { |
| 1795 | if (self.castTag(.elem_ptr)) |elem_ptr| { | |
| 1796 | return Tag.elem_ptr.create(allocator, .{ | |
| 1797 | .array_ptr = elem_ptr.data.array_ptr, | |
| 1798 | .index = elem_ptr.data.index + index, | |
| 1799 | }); | |
| 1795 | switch (self.tag()) { | |
| 1796 | .elem_ptr => { | |
| 1797 | const elem_ptr = self.castTag(.elem_ptr).?.data; | |
| 1798 | return Tag.elem_ptr.create(allocator, .{ | |
| 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 | 1814 | pub fn isUndef(self: Value) bool { |