authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-21 18:03:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-25 11:23:40-07:00
logedb5e493e6d9a4478b3d9c06aa590694757d8c03
tree5d5ccca94129e3a0e177845dbb5a9b251271cd07
parenta5c910adb610ae530db99f10aa77aaed3e85e830

update `@memcpy` to require equal src and dest lens

* Sema: upgrade operands to array pointers if possible when emitting AIR. * Implement safety checks for length mismatch and aliasing. * AIR: make ptrtoint support slice operands. Implement in LLVM backend. * C backend: implement new `@memset` semantics. `@memcpy` is not done yet.

12 files changed, 280 insertions(+), 78 deletions(-)

doc/langref.html.in+14-12
......@@ -8683,18 +8683,20 @@ test "integer cast panic" {
86838683 {#header_open|@memcpy#}
86848684 <pre>{#syntax#}@memcpy(noalias dest, noalias source) void{#endsyntax#}</pre>
86858685 <p>This function copies bytes from one region of memory to another.</p>
8686 <p>{#syntax#}dest{#endsyntax#} must be a mutable slice, or a mutable pointer to an array.
8687 It may have any alignment, and it may have any element type.</p>
8688 <p>{#syntax#}source{#endsyntax#} must be an array, pointer, or a slice
8689 with the same element type as {#syntax#}dest{#endsyntax#}. It may have
8690 any alignment. Only {#syntax#}const{#endsyntax#} access is required. It
8691 is sliced from 0 to the same length as
8692 {#syntax#}dest{#endsyntax#}, triggering the same set of safety checks and
8693 possible compile errors as
8694 {#syntax#}source[0..dest.len]{#endsyntax#}.</p>
8695 <p>It is illegal for {#syntax#}dest{#endsyntax#} and
8696 {#syntax#}source[0..dest.len]{#endsyntax#} to overlap. If safety
8697 checks are enabled, there will be a runtime check for such overlapping.</p>
8686 <p>{#syntax#}dest{#endsyntax#} must be a mutable slice, a mutable pointer to an array, or
8687 a mutable many-item {#link|pointer|Pointer#}. It may have any
8688 alignment, and it may have any element type.</p>
8689 <p>Likewise, {#syntax#}source{#endsyntax#} must be a mutable slice, a
8690 mutable pointer to an array, or a mutable many-item
8691 {#link|pointer|Pointer#}. It may have any alignment, and it may have any
8692 element type.</p>
8693 <p>The {#syntax#}source{#endsyntax#} element type must support {#link|Type Coercion#}
8694 into the {#syntax#}dest{#endsyntax#} element type. The element types may have
8695 different ABI size, however, that may incur a performance penalty.</p>
8696 <p>Similar to {#link|for#} loops, at least one of {#syntax#}source{#endsyntax#} and
8697 {#syntax#}dest{#endsyntax#} must provide a length, and if two lengths are provided,
8698 they must be equal.</p>
8699 <p>Finally, the two memory regions must not overlap.</p>
86988700 {#header_close#}
86998701
87008702 {#header_open|@memset#}
lib/std/builtin.zig+2
......@@ -1002,6 +1002,8 @@ pub const panic_messages = struct {
10021002 pub const index_out_of_bounds = "index out of bounds";
10031003 pub const start_index_greater_than_end = "start index is larger than end index";
10041004 pub const for_len_mismatch = "for loop over objects with non-equal lengths";
1005 pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
1006 pub const memcpy_alias = "@memcpy arguments alias";
10051007};
10061008
10071009pub noinline fn returnError(st: *StackTrace) void {
lib/std/crypto/aegis.zig+2-2
......@@ -209,7 +209,7 @@ fn Aegis128LGeneric(comptime tag_bits: u9) type {
209209 acc |= (computed_tag[j] ^ tag[j]);
210210 }
211211 if (acc != 0) {
212 @memset(m.ptr, undefined, m.len);
212 @memset(m, undefined);
213213 return error.AuthenticationFailed;
214214 }
215215 }
......@@ -390,7 +390,7 @@ fn Aegis256Generic(comptime tag_bits: u9) type {
390390 acc |= (computed_tag[j] ^ tag[j]);
391391 }
392392 if (acc != 0) {
393 @memset(m.ptr, undefined, m.len);
393 @memset(m, undefined);
394394 return error.AuthenticationFailed;
395395 }
396396 }
lib/std/hash/murmur.zig+5-6
......@@ -99,9 +99,8 @@ pub const Murmur2_64 = struct {
9999
100100 pub fn hashWithSeed(str: []const u8, seed: u64) u64 {
101101 const m: u64 = 0xc6a4a7935bd1e995;
102 const len = @as(u64, str.len);
103 var h1: u64 = seed ^ (len *% m);
104 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
102 var h1: u64 = seed ^ (@as(u64, str.len) *% m);
103 for (@ptrCast([*]align(1) const u64, str.ptr)[0..str.len / 8]) |v| {
105104 var k1: u64 = v;
106105 if (native_endian == .Big)
107106 k1 = @byteSwap(k1);
......@@ -111,11 +110,11 @@ pub const Murmur2_64 = struct {
111110 h1 ^= k1;
112111 h1 *%= m;
113112 }
114 const rest = len & 7;
115 const offset = len - rest;
113 const rest = str.len & 7;
114 const offset = str.len - rest;
116115 if (rest > 0) {
117116 var k1: u64 = 0;
118 @memcpy(@ptrCast([*]u8, &k1)[0..@intCast(usize, rest)], @ptrCast([*]const u8, &str[@intCast(usize, offset)]));
117 @memcpy(@ptrCast([*]u8, &k1)[0..rest], str[offset..]);
119118 if (native_endian == .Big)
120119 k1 = @byteSwap(k1);
121120 h1 ^= k1;
lib/std/mem/Allocator.zig+2-1
......@@ -282,7 +282,8 @@ pub fn reallocAdvanced(
282282
283283 const new_mem = self.rawAlloc(byte_count, log2a(Slice.alignment), return_address) orelse
284284 return error.OutOfMemory;
285 @memcpy(new_mem[0..@min(byte_count, old_byte_slice.len)], old_byte_slice);
285 const copy_len = @min(byte_count, old_byte_slice.len);
286 @memcpy(new_mem[0..copy_len], old_byte_slice[0..copy_len]);
286287 // TODO https://github.com/ziglang/zig/issues/4298
287288 @memset(old_byte_slice, undefined);
288289 self.rawFree(old_byte_slice, log2a(Slice.alignment), return_address);
src/Air.zig+1
......@@ -462,6 +462,7 @@ pub const Inst = struct {
462462 /// Uses the `ty_op` field.
463463 load,
464464 /// Converts a pointer to its address. Result type is always `usize`.
465 /// Pointer type size may be any, including slice.
465466 /// Uses the `un_op` field.
466467 ptrtoint,
467468 /// Given a boolean, returns 0 or 1.
src/AstGen.zig+1-1
......@@ -8455,7 +8455,7 @@ fn builtinCall(
84558455 .memcpy => {
84568456 _ = try gz.addPlNode(.memcpy, node, Zir.Inst.Bin{
84578457 .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
8458 .rhs = try expr(gz, scope, .{ .rl = .ref }, params[1]),
8458 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),
84598459 });
84608460 return rvalue(gz, ri, .void_value, node);
84618461 },
src/Liveness/Verify.zig+2-7
......@@ -254,6 +254,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
254254 .set_union_tag,
255255 .min,
256256 .max,
257 .memset,
258 .memcpy,
257259 => {
258260 const bin_op = data[inst].bin_op;
259261 try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -306,13 +308,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
306308 const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
307309 try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
308310 },
309 .memset,
310 .memcpy,
311 => {
312 const pl_op = data[inst].pl_op;
313 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
314 try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
315 },
316311 .cmpxchg_strong,
317312 .cmpxchg_weak,
318313 => {
src/Sema.zig+160-15
......@@ -3386,17 +3386,39 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
33863386 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
33873387 const src = inst_data.src();
33883388 const object = try sema.resolveInst(inst_data.operand);
3389 const object_ty = sema.typeOf(object);
3390
3391 const is_pointer_to = object_ty.isSinglePointer();
33923389
3393 const array_ty = if (is_pointer_to)
3394 object_ty.childType()
3395 else
3396 object_ty;
3390 return indexablePtrLen(sema, block, src, object);
3391}
33973392
3393fn indexablePtrLen(
3394 sema: *Sema,
3395 block: *Block,
3396 src: LazySrcLoc,
3397 object: Air.Inst.Ref,
3398) CompileError!Air.Inst.Ref {
3399 const object_ty = sema.typeOf(object);
3400 const is_pointer_to = object_ty.isSinglePointer();
3401 const array_ty = if (is_pointer_to) object_ty.childType() else object_ty;
33983402 try checkIndexable(sema, block, src, array_ty);
3403 return sema.fieldVal(block, src, object, "len", src);
3404}
33993405
3406fn indexablePtrLenOrNone(
3407 sema: *Sema,
3408 block: *Block,
3409 src: LazySrcLoc,
3410 object: Air.Inst.Ref,
3411) CompileError!Air.Inst.Ref {
3412 const object_ty = sema.typeOf(object);
3413 const array_ty = t: {
3414 const ptr_size = object_ty.ptrSizeOrNull() orelse break :t object_ty;
3415 break :t switch (ptr_size) {
3416 .Many => return .none,
3417 .One => object_ty.childType(),
3418 else => object_ty,
3419 };
3420 };
3421 try checkIndexable(sema, block, src, array_ty);
34003422 return sema.fieldVal(block, src, object, "len", src);
34013423}
34023424
......@@ -21773,6 +21795,29 @@ fn analyzeMinMax(
2177321795 return block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
2177421796}
2177521797
21798fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref {
21799 const mod = sema.mod;
21800 const info = sema.typeOf(ptr).ptrInfo().data;
21801 if (info.size == .One) {
21802 // Already an array pointer.
21803 return ptr;
21804 }
21805 const new_ty = try Type.ptr(sema.arena, mod, .{
21806 .pointee_type = try Type.array(sema.arena, len, info.sentinel, info.pointee_type, mod),
21807 .sentinel = null,
21808 .@"align" = info.@"align",
21809 .@"addrspace" = info.@"addrspace",
21810 .mutable = info.mutable,
21811 .@"allowzero" = info.@"allowzero",
21812 .@"volatile" = info.@"volatile",
21813 .size = .One,
21814 });
21815 if (info.size == .Slice) {
21816 return block.addTyOp(.slice_ptr, new_ty, ptr);
21817 }
21818 return block.addBitCast(new_ty, ptr);
21819}
21820
2177621821fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2177721822 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2177821823 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
......@@ -21780,27 +21825,125 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2178021825 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2178121826 const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
2178221827 const dest_ptr = try sema.resolveInst(extra.lhs);
21783 const src_ptr_ptr = try sema.resolveInst(extra.rhs);
21784 const dest_ptr_ty = sema.typeOf(dest_ptr);
21785 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
21828 const src_ptr = try sema.resolveInst(extra.rhs);
21829 const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr);
21830 const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr);
21831
21832 if (dest_len == .none and src_len == .none) {
21833 const msg = msg: {
21834 const msg = try sema.errMsg(block, src, "unknown @memcpy length", .{});
21835 errdefer msg.destroy(sema.gpa);
21836 try sema.errNote(block, dest_src, msg, "destination type {} provides no length", .{
21837 sema.typeOf(dest_ptr).fmt(sema.mod),
21838 });
21839 try sema.errNote(block, src_src, msg, "source type {} provides no length", .{
21840 sema.typeOf(src_ptr).fmt(sema.mod),
21841 });
21842 break :msg msg;
21843 };
21844 return sema.failWithOwnedErrorMsg(msg);
21845 }
2178621846
21787 const dest_len = try sema.fieldVal(block, dest_src, dest_ptr, "len", dest_src);
21788 const src_ptr = try sema.analyzeSlice(block, src_src, src_ptr_ptr, .zero_usize, dest_len, .none, .unneeded, src_src, src_src, src_src);
21847 var len_val: ?Value = null;
21848
21849 if (dest_len != .none and src_len != .none) check: {
21850 // If we can check at compile-time, no need for runtime safety.
21851 if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
21852 len_val = dest_len_val;
21853 if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
21854 if (!(try sema.valuesEqual(dest_len_val, src_len_val, Type.usize))) {
21855 const msg = msg: {
21856 const msg = try sema.errMsg(block, src, "non-matching @memcpy lengths", .{});
21857 errdefer msg.destroy(sema.gpa);
21858 try sema.errNote(block, dest_src, msg, "length {} here", .{
21859 dest_len_val.fmtValue(Type.usize, sema.mod),
21860 });
21861 try sema.errNote(block, src_src, msg, "length {} here", .{
21862 src_len_val.fmtValue(Type.usize, sema.mod),
21863 });
21864 break :msg msg;
21865 };
21866 return sema.failWithOwnedErrorMsg(msg);
21867 }
21868 break :check;
21869 }
21870 } else if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
21871 len_val = src_len_val;
21872 }
21873
21874 if (block.wantSafety()) {
21875 const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
21876 try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);
21877 }
21878 }
2178921879
2179021880 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
2179121881 if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;
2179221882 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| {
21793 if (!src_ptr_val.isComptimeMutablePtr()) break :rs src_src;
21883 _ = src_ptr_val;
2179421884 return sema.fail(block, src, "TODO: @memcpy at comptime", .{});
2179521885 } else break :rs src_src;
2179621886 } else dest_src;
2179721887
2179821888 try sema.requireRuntimeBlock(block, src, runtime_src);
21889
21890 const dest_ty = sema.typeOf(dest_ptr);
21891 const src_ty = sema.typeOf(src_ptr);
21892
21893 // If in-memory coercion is not allowed, explode this memcpy call into a
21894 // for loop that copies element-wise.
21895 // Likewise if this is an iterable rather than a pointer, do the same
21896 // lowering. The AIR instruction requires pointers with element types of
21897 // equal ABI size.
21898
21899 if (dest_ty.zigTypeTag() != .Pointer or src_ty.zigTypeTag() != .Pointer) {
21900 return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{});
21901 }
21902
21903 const dest_elem_ty = dest_ty.elemType2();
21904 const src_elem_ty = src_ty.elemType2();
21905 const target = sema.mod.getTarget();
21906 if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) {
21907 return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{});
21908 }
21909
21910 // If the length is comptime-known, then upgrade src and destination types
21911 // into pointer-to-array. At this point we know they are both pointers
21912 // already.
21913 var new_dest_ptr = dest_ptr;
21914 var new_src_ptr = src_ptr;
21915 if (len_val) |val| {
21916 const len = val.toUnsignedInt(target);
21917 new_dest_ptr = try upgradeToArrayPtr(sema, block, dest_ptr, len);
21918 new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len);
21919 }
21920
21921 // Aliasing safety check.
21922 if (block.wantSafety()) {
21923 const dest_int = try block.addUnOp(.ptrtoint, new_dest_ptr);
21924 const src_int = try block.addUnOp(.ptrtoint, new_src_ptr);
21925 const len = if (len_val) |v|
21926 try sema.addConstant(Type.usize, v)
21927 else if (dest_len != .none)
21928 dest_len
21929 else
21930 src_len;
21931
21932 // ok1: dest >= src + len
21933 // ok2: src >= dest + len
21934 const src_plus_len = try block.addBinOp(.add, src_int, len);
21935 const dest_plus_len = try block.addBinOp(.add, dest_int, len);
21936 const ok1 = try block.addBinOp(.cmp_gte, dest_int, src_plus_len);
21937 const ok2 = try block.addBinOp(.cmp_gte, src_int, dest_plus_len);
21938 const ok = try block.addBinOp(.bit_or, ok1, ok2);
21939 try sema.addSafetyCheck(block, ok, .memcpy_alias);
21940 }
21941
2179921942 _ = try block.addInst(.{
2180021943 .tag = .memcpy,
2180121944 .data = .{ .bin_op = .{
21802 .lhs = dest_ptr,
21803 .rhs = src_ptr,
21945 .lhs = new_dest_ptr,
21946 .rhs = new_src_ptr,
2180421947 } },
2180521948 });
2180621949}
......@@ -22949,6 +23092,8 @@ pub const PanicId = enum {
2294923092 index_out_of_bounds,
2295023093 start_index_greater_than_end,
2295123094 for_len_mismatch,
23095 memcpy_len_mismatch,
23096 memcpy_alias,
2295223097};
2295323098
2295423099fn addSafetyCheck(
src/codegen/c.zig+74-24
......@@ -6177,18 +6177,43 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
61776177}
61786178
61796179fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6180 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
6181 const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
6182 const dest_ty = f.air.typeOf(pl_op.operand);
6183 const dest_ptr = try f.resolveInst(pl_op.operand);
6184 const value = try f.resolveInst(extra.lhs);
6185 const len = try f.resolveInst(extra.rhs);
6186
6180 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
6181 const dest_ty = f.air.typeOf(bin_op.lhs);
6182 const dest_slice = try f.resolveInst(bin_op.lhs);
6183 const value = try f.resolveInst(bin_op.rhs);
6184 const elem_ty = f.air.typeOf(bin_op.rhs);
6185 const target = f.object.dg.module.getTarget();
6186 const elem_abi_size = elem_ty.abiSize(target);
6187 const val_is_undef = if (f.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
61876188 const writer = f.object.writer();
6188 if (dest_ty.isVolatilePtr()) {
6189 var u8_ptr_pl = dest_ty.ptrInfo();
6190 u8_ptr_pl.data.pointee_type = Type.u8;
6191 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
6189
6190 if (val_is_undef) {
6191 try writer.writeAll("memset(");
6192 switch (dest_ty.ptrSize()) {
6193 .Slice => {
6194 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
6195 try writer.writeAll(", 0xaa, ");
6196 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
6197 if (elem_abi_size > 1) {
6198 try writer.print(" * {d});\n", .{elem_abi_size});
6199 } else {
6200 try writer.writeAll(");\n");
6201 }
6202 },
6203 .One => {
6204 const array_ty = dest_ty.childType();
6205 const len = array_ty.arrayLen() * elem_abi_size;
6206
6207 try f.writeCValue(writer, dest_slice, .FunctionArgument);
6208 try writer.print(", 0xaa, {d});\n", .{len});
6209 },
6210 .Many, .C => unreachable,
6211 }
6212 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6213 return .none;
6214 }
6215
6216 if (elem_abi_size > 1 or dest_ty.isVolatilePtr()) {
61926217 const index = try f.allocLocal(inst, Type.usize);
61936218
61946219 try writer.writeAll("for (");
......@@ -6198,36 +6223,61 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
61986223 try writer.writeAll("; ");
61996224 try f.writeCValue(writer, index, .Other);
62006225 try writer.writeAll(" != ");
6201 try f.writeCValue(writer, len, .Other);
6226 switch (dest_ty.ptrSize()) {
6227 .Slice => {
6228 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
6229 },
6230 .One => {
6231 const array_ty = dest_ty.childType();
6232 const len = array_ty.arrayLen() * elem_abi_size;
6233 try writer.print("{d}", .{len});
6234 },
6235 .Many, .C => unreachable,
6236 }
62026237 try writer.writeAll("; ");
62036238 try f.writeCValue(writer, index, .Other);
62046239 try writer.writeAll(" += ");
62056240 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
6206 try writer.writeAll(") ((");
6207 try f.renderType(writer, u8_ptr_ty);
6208 try writer.writeByte(')');
6209 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
6241 try writer.writeAll(") (");
6242 switch (dest_ty.ptrSize()) {
6243 .Slice => try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }),
6244 .One => try f.writeCValue(writer, dest_slice, .FunctionArgument),
6245 .Many, .C => unreachable,
6246 }
62106247 try writer.writeAll(")[");
62116248 try f.writeCValue(writer, index, .Other);
62126249 try writer.writeAll("] = ");
62136250 try f.writeCValue(writer, value, .FunctionArgument);
62146251 try writer.writeAll(";\n");
62156252
6216 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
6253 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
62176254 try freeLocal(f, inst, index.new_local, 0);
62186255
62196256 return .none;
62206257 }
62216258
6222 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
62236259 try writer.writeAll("memset(");
6224 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
6225 try writer.writeAll(", ");
6226 try f.writeCValue(writer, value, .FunctionArgument);
6227 try writer.writeAll(", ");
6228 try f.writeCValue(writer, len, .FunctionArgument);
6229 try writer.writeAll(");\n");
6260 switch (dest_ty.ptrSize()) {
6261 .Slice => {
6262 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
6263 try writer.writeAll(", ");
6264 try f.writeCValue(writer, value, .FunctionArgument);
6265 try writer.writeAll(", ");
6266 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
6267 try writer.writeAll(");\n");
6268 },
6269 .One => {
6270 const array_ty = dest_ty.childType();
6271 const len = array_ty.arrayLen() * elem_abi_size;
62306272
6273 try f.writeCValue(writer, dest_slice, .FunctionArgument);
6274 try writer.writeAll(", ");
6275 try f.writeCValue(writer, value, .FunctionArgument);
6276 try writer.print(", {d});\n", .{len});
6277 },
6278 .Many, .C => unreachable,
6279 }
6280 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
62316281 return .none;
62326282}
62336283
src/codegen/llvm.zig+7-5
......@@ -5777,10 +5777,10 @@ pub const FuncGen = struct {
57775777 }
57785778
57795779 fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
5780 switch (ty.ptrSize()) {
5781 .Slice => return fg.builder.buildExtractValue(ptr, 0, ""),
5782 .One => return ptr,
5783 .Many, .C => unreachable,
5780 if (ty.isSlice()) {
5781 return fg.builder.buildExtractValue(ptr, 0, "");
5782 } else {
5783 return ptr;
57845784 }
57855785 }
57865786
......@@ -7917,8 +7917,10 @@ pub const FuncGen = struct {
79177917 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
79187918 const un_op = self.air.instructions.items(.data)[inst].un_op;
79197919 const operand = try self.resolveInst(un_op);
7920 const ptr_ty = self.air.typeOf(un_op);
7921 const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty);
79207922 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
7921 return self.builder.buildPtrToInt(operand, dest_llvm_ty, "");
7923 return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, "");
79227924 }
79237925
79247926 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
src/type.zig+10-5
......@@ -3843,9 +3843,14 @@ pub const Type = extern union {
38433843 };
38443844 }
38453845
3846 /// Asserts the `Type` is a pointer.
3847 pub fn ptrSize(self: Type) std.builtin.Type.Pointer.Size {
3848 return switch (self.tag()) {
3846 /// Asserts `ty` is a pointer.
3847 pub fn ptrSize(ty: Type) std.builtin.Type.Pointer.Size {
3848 return ptrSizeOrNull(ty).?;
3849 }
3850
3851 /// Returns `null` if `ty` is not a pointer.
3852 pub fn ptrSizeOrNull(ty: Type) ?std.builtin.Type.Pointer.Size {
3853 return switch (ty.tag()) {
38493854 .const_slice,
38503855 .mut_slice,
38513856 .const_slice_u8,
......@@ -3870,9 +3875,9 @@ pub const Type = extern union {
38703875 .inferred_alloc_mut,
38713876 => .One,
38723877
3873 .pointer => self.castTag(.pointer).?.data.size,
3878 .pointer => ty.castTag(.pointer).?.data.size,
38743879
3875 else => unreachable,
3880 else => null,
38763881 };
38773882 }
38783883