authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-03 15:12:02-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-03 15:12:02-05:00
loge91c16e38b58611217f225d002a3321aa24bb47f
treee86a89067a08d9c14d01334b4f054b51637afdb8
parent7deadf4301d5f5f5e2b8a1a8b2dc7109e2c82181
parent365aca0e9096ef7c69b3ba2eb682caf3f7234293
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11043 from topolarity/ptr-fixes

stage2: Improve `@ptrCast` support for sliced/optional operands

5 files changed, 53 insertions(+), 19 deletions(-)

src/Sema.zig+41-11
...@@ -12538,6 +12538,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -12538,6 +12538,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
12538 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);12538 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
12539 const operand = sema.resolveInst(extra.rhs);12539 const operand = sema.resolveInst(extra.rhs);
12540 const operand_ty = sema.typeOf(operand);12540 const operand_ty = sema.typeOf(operand);
12541 const target = sema.mod.getTarget();
12542
12541 try sema.checkPtrType(block, dest_ty_src, dest_ty);12543 try sema.checkPtrType(block, dest_ty_src, dest_ty);
12542 try sema.checkPtrOperand(block, operand_src, operand_ty);12544 try sema.checkPtrOperand(block, operand_src, operand_ty);
12543 if (dest_ty.isSlice()) {12545 if (dest_ty.isSlice()) {
...@@ -12547,7 +12549,28 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -12547,7 +12549,28 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
12547 try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)12549 try sema.analyzeSlicePtr(block, operand_src, operand, operand_ty)
12548 else12550 else
12549 operand;12551 operand;
12550 return sema.coerceCompatiblePtrs(block, dest_ty, ptr, operand_src);12552
12553 try sema.resolveTypeLayout(block, dest_ty_src, dest_ty.elemType2());
12554 const dest_align = dest_ty.ptrAlignment(target);
12555 try sema.resolveTypeLayout(block, operand_src, operand_ty.elemType2());
12556 const operand_align = operand_ty.ptrAlignment(target);
12557
12558 // If the destination is less aligned than the source, preserve the source alignment
12559 var aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
12560 // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result
12561 if (dest_ty.zigTypeTag() == .Optional) {
12562 var buf: Type.Payload.ElemType = undefined;
12563 var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data;
12564 dest_ptr_info.@"align" = operand_align;
12565 break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, target, dest_ptr_info));
12566 } else {
12567 var dest_ptr_info = dest_ty.ptrInfo().data;
12568 dest_ptr_info.@"align" = operand_align;
12569 break :blk try Type.ptr(sema.arena, target, dest_ptr_info);
12570 }
12571 };
12572
12573 return sema.coerceCompatiblePtrs(block, aligned_dest_ty, ptr, operand_src);
12551}12574}
1255212575
12553fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12576fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -15340,7 +15363,7 @@ fn unionFieldVal(...@@ -15340,7 +15363,7 @@ fn unionFieldVal(
15340 return sema.addConstant(field.ty, tag_and_val.val);15363 return sema.addConstant(field.ty, tag_and_val.val);
15341 } else {15364 } else {
15342 const old_ty = union_ty.unionFieldType(tag_and_val.tag);15365 const old_ty = union_ty.unionFieldType(tag_and_val.tag);
15343 const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty);15366 const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0);
15344 return sema.addConstant(field.ty, new_val);15367 return sema.addConstant(field.ty, new_val);
15345 }15368 }
15346 },15369 },
...@@ -16447,7 +16470,7 @@ fn storePtrVal(...@@ -16447,7 +16470,7 @@ fn storePtrVal(
16447 var kit = try beginComptimePtrMutation(sema, block, src, ptr_val);16470 var kit = try beginComptimePtrMutation(sema, block, src, ptr_val);
16448 try sema.checkComptimeVarStore(block, src, kit.decl_ref_mut);16471 try sema.checkComptimeVarStore(block, src, kit.decl_ref_mut);
1644916472
16450 const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, kit.ty);16473 const bitcasted_val = try sema.bitCastVal(block, src, operand_val, operand_ty, kit.ty, 0);
1645116474
16452 const arena = kit.beginArena(sema.gpa);16475 const arena = kit.beginArena(sema.gpa);
16453 defer kit.finishArena();16476 defer kit.finishArena();
...@@ -16741,6 +16764,8 @@ fn beginComptimePtrMutation(...@@ -16741,6 +16764,8 @@ fn beginComptimePtrMutation(
16741const ComptimePtrLoadKit = struct {16764const ComptimePtrLoadKit = struct {
16742 /// The Value of the Decl that owns this memory.16765 /// The Value of the Decl that owns this memory.
16743 root_val: Value,16766 root_val: Value,
16767 /// The Type of the Decl that owns this memory.
16768 root_ty: Type,
16744 /// Parent Value.16769 /// Parent Value.
16745 val: Value,16770 val: Value,
16746 /// The Type of the parent Value.16771 /// The Type of the parent Value.
...@@ -16771,6 +16796,7 @@ fn beginComptimePtrLoad(...@@ -16771,6 +16796,7 @@ fn beginComptimePtrLoad(
16771 if (decl_val.tag() == .variable) return error.RuntimeLoad;16796 if (decl_val.tag() == .variable) return error.RuntimeLoad;
16772 return ComptimePtrLoadKit{16797 return ComptimePtrLoadKit{
16773 .root_val = decl_val,16798 .root_val = decl_val,
16799 .root_ty = decl.ty,
16774 .val = decl_val,16800 .val = decl_val,
16775 .ty = decl.ty,16801 .ty = decl.ty,
16776 .byte_offset = 0,16802 .byte_offset = 0,
...@@ -16783,6 +16809,7 @@ fn beginComptimePtrLoad(...@@ -16783,6 +16809,7 @@ fn beginComptimePtrLoad(
16783 if (decl_val.tag() == .variable) return error.RuntimeLoad;16809 if (decl_val.tag() == .variable) return error.RuntimeLoad;
16784 return ComptimePtrLoadKit{16810 return ComptimePtrLoadKit{
16785 .root_val = decl_val,16811 .root_val = decl_val,
16812 .root_ty = decl.ty,
16786 .val = decl_val,16813 .val = decl_val,
16787 .ty = decl.ty,16814 .ty = decl.ty,
16788 .byte_offset = 0,16815 .byte_offset = 0,
...@@ -16817,6 +16844,7 @@ fn beginComptimePtrLoad(...@@ -16817,6 +16844,7 @@ fn beginComptimePtrLoad(
16817 };16844 };
16818 return ComptimePtrLoadKit{16845 return ComptimePtrLoadKit{
16819 .root_val = parent.root_val,16846 .root_val = parent.root_val,
16847 .root_ty = parent.ty,
16820 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),16848 .val = try parent.val.elemValue(sema.arena, elem_ptr.index),
16821 .ty = elem_ty,16849 .ty = elem_ty,
16822 .byte_offset = byte_offset,16850 .byte_offset = byte_offset,
...@@ -16832,6 +16860,7 @@ fn beginComptimePtrLoad(...@@ -16832,6 +16860,7 @@ fn beginComptimePtrLoad(
16832 }16860 }
16833 return ComptimePtrLoadKit{16861 return ComptimePtrLoadKit{
16834 .root_val = parent.root_val,16862 .root_val = parent.root_val,
16863 .root_ty = parent.ty,
16835 .val = parent.val,16864 .val = parent.val,
16836 .ty = parent.ty,16865 .ty = parent.ty,
16837 .byte_offset = parent.byte_offset,16866 .byte_offset = parent.byte_offset,
...@@ -16859,6 +16888,7 @@ fn beginComptimePtrLoad(...@@ -16859,6 +16888,7 @@ fn beginComptimePtrLoad(
16859 };16888 };
16860 return ComptimePtrLoadKit{16889 return ComptimePtrLoadKit{
16861 .root_val = parent.root_val,16890 .root_val = parent.root_val,
16891 .root_ty = parent.ty,
16862 .val = try parent.val.fieldValue(sema.arena, field_index),16892 .val = try parent.val.fieldValue(sema.arena, field_index),
16863 .ty = parent.ty.structFieldType(field_index),16893 .ty = parent.ty.structFieldType(field_index),
16864 .byte_offset = byte_offset,16894 .byte_offset = byte_offset,
...@@ -16870,6 +16900,7 @@ fn beginComptimePtrLoad(...@@ -16870,6 +16900,7 @@ fn beginComptimePtrLoad(
16870 const parent = try beginComptimePtrLoad(sema, block, src, err_union_ptr);16900 const parent = try beginComptimePtrLoad(sema, block, src, err_union_ptr);
16871 return ComptimePtrLoadKit{16901 return ComptimePtrLoadKit{
16872 .root_val = parent.root_val,16902 .root_val = parent.root_val,
16903 .root_ty = parent.root_ty,
16873 .val = parent.val.castTag(.eu_payload).?.data,16904 .val = parent.val.castTag(.eu_payload).?.data,
16874 .ty = parent.ty.errorUnionPayload(),16905 .ty = parent.ty.errorUnionPayload(),
16875 .byte_offset = null,16906 .byte_offset = null,
...@@ -16881,6 +16912,7 @@ fn beginComptimePtrLoad(...@@ -16881,6 +16912,7 @@ fn beginComptimePtrLoad(
16881 const parent = try beginComptimePtrLoad(sema, block, src, opt_ptr);16912 const parent = try beginComptimePtrLoad(sema, block, src, opt_ptr);
16882 return ComptimePtrLoadKit{16913 return ComptimePtrLoadKit{
16883 .root_val = parent.root_val,16914 .root_val = parent.root_val,
16915 .root_ty = parent.root_ty,
16884 .val = parent.val.castTag(.opt_payload).?.data,16916 .val = parent.val.castTag(.opt_payload).?.data,
16885 .ty = try parent.ty.optionalChildAlloc(sema.arena),16917 .ty = try parent.ty.optionalChildAlloc(sema.arena),
16886 .byte_offset = null,16918 .byte_offset = null,
...@@ -16918,7 +16950,7 @@ fn bitCast(...@@ -16918,7 +16950,7 @@ fn bitCast(
1691816950
16919 // TODO validate the type size and other compile errors16951 // TODO validate the type size and other compile errors
16920 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {16952 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
16921 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty);16953 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);
16922 return sema.addConstant(dest_ty, result_val);16954 return sema.addConstant(dest_ty, result_val);
16923 }16955 }
16924 try sema.requireRuntimeBlock(block, inst_src);16956 try sema.requireRuntimeBlock(block, inst_src);
...@@ -16932,6 +16964,7 @@ pub fn bitCastVal(...@@ -16932,6 +16964,7 @@ pub fn bitCastVal(
16932 val: Value,16964 val: Value,
16933 old_ty: Type,16965 old_ty: Type,
16934 new_ty: Type,16966 new_ty: Type,
16967 buffer_offset: usize,
16935) !Value {16968) !Value {
16936 if (old_ty.eql(new_ty)) return val;16969 if (old_ty.eql(new_ty)) return val;
1693716970
...@@ -16942,7 +16975,7 @@ pub fn bitCastVal(...@@ -16942,7 +16975,7 @@ pub fn bitCastVal(
16942 const buffer = try sema.gpa.alloc(u8, abi_size);16975 const buffer = try sema.gpa.alloc(u8, abi_size);
16943 defer sema.gpa.free(buffer);16976 defer sema.gpa.free(buffer);
16944 val.writeToMemory(old_ty, target, buffer);16977 val.writeToMemory(old_ty, target, buffer);
16945 return Value.readFromMemory(new_ty, target, buffer, sema.arena);16978 return Value.readFromMemory(new_ty, target, buffer[buffer_offset..], sema.arena);
16946}16979}
1694716980
16948fn coerceArrayPtrToSlice(16981fn coerceArrayPtrToSlice(
...@@ -19808,13 +19841,10 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr...@@ -19808,13 +19841,10 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
19808 // The Type it is stored as in the compiler has an ABI size greater or equal to19841 // The Type it is stored as in the compiler has an ABI size greater or equal to
19809 // the ABI size of `load_ty`. We may perform the bitcast based on19842 // the ABI size of `load_ty`. We may perform the bitcast based on
19810 // `parent.val` alone (more efficient).19843 // `parent.val` alone (more efficient).
19811 return try sema.bitCastVal(block, src, parent.val, parent.ty, load_ty);19844 return try sema.bitCastVal(block, src, parent.val, parent.ty, load_ty, 0);
19845 } else {
19846 return try sema.bitCastVal(block, src, parent.root_val, parent.root_ty, load_ty, parent.byte_offset.?);
19812 }19847 }
19813
19814 // The Type it is stored as in the compiler has an ABI size less than the ABI size
19815 // of `load_ty`. The bitcast must be performed based on the `parent.root_val`
19816 // and reinterpreted starting at `parent.byte_offset`.
19817 return sema.fail(block, src, "TODO: implement bitcast with index offset", .{});
19818}19848}
1981919849
19820/// Used to convert a u64 value to a usize value, emitting a compile error if the number19850/// Used to convert a u64 value to a usize value, emitting a compile error if the number
src/codegen/llvm.zig+1-1
...@@ -2882,7 +2882,7 @@ pub const FuncGen = struct {...@@ -2882,7 +2882,7 @@ pub const FuncGen = struct {
2882 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2882 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2883 const ptr_ty = self.air.typeOf(bin_op.lhs);2883 const ptr_ty = self.air.typeOf(bin_op.lhs);
2884 const elem_ty = ptr_ty.childType();2884 const elem_ty = ptr_ty.childType();
2885 if (!elem_ty.hasRuntimeBits()) return null;2885 if (!elem_ty.hasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);
28862886
2887 const base_ptr = try self.resolveInst(bin_op.lhs);2887 const base_ptr = try self.resolveInst(bin_op.lhs);
2888 const rhs = try self.resolveInst(bin_op.rhs);2888 const rhs = try self.resolveInst(bin_op.rhs);
src/type.zig+1-1
...@@ -2245,6 +2245,7 @@ pub const Type = extern union {...@@ -2245,6 +2245,7 @@ pub const Type = extern union {
2245 .prefetch_options,2245 .prefetch_options,
2246 .export_options,2246 .export_options,
2247 .extern_options,2247 .extern_options,
2248 .@"opaque",
2248 => return 1,2249 => return 1,
22492250
2250 .fn_noreturn_no_args, // represents machine code; not a pointer2251 .fn_noreturn_no_args, // represents machine code; not a pointer
...@@ -2432,7 +2433,6 @@ pub const Type = extern union {...@@ -2432,7 +2433,6 @@ pub const Type = extern union {
2432 .noreturn,2433 .noreturn,
2433 .inferred_alloc_const,2434 .inferred_alloc_const,
2434 .inferred_alloc_mut,2435 .inferred_alloc_mut,
2435 .@"opaque",
2436 .var_args_param,2436 .var_args_param,
2437 .bound_fn,2437 .bound_fn,
2438 => unreachable,2438 => unreachable,
test/behavior/optional.zig+4-1
...@@ -273,7 +273,10 @@ test "0-bit child type coerced to optional return ptr result location" {...@@ -273,7 +273,10 @@ test "0-bit child type coerced to optional return ptr result location" {
273}273}
274274
275test "0-bit child type coerced to optional" {275test "0-bit child type coerced to optional" {
276 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
277280
278 const S = struct {281 const S = struct {
279 fn doTheTest() !void {282 fn doTheTest() !void {
test/behavior/ptrcast.zig+6-5
...@@ -4,7 +4,9 @@ const expect = std.testing.expect;...@@ -4,7 +4,9 @@ const expect = std.testing.expect;
4const native_endian = builtin.target.cpu.arch.endian();4const native_endian = builtin.target.cpu.arch.endian();
55
6test "reinterpret bytes as integer with nonzero offset" {6test "reinterpret bytes as integer with nonzero offset" {
7 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
810
9 try testReinterpretBytesAsInteger();11 try testReinterpretBytesAsInteger();
10 comptime try testReinterpretBytesAsInteger();12 comptime try testReinterpretBytesAsInteger();
...@@ -43,7 +45,6 @@ fn testReinterpretBytesAsExternStruct() !void {...@@ -43,7 +45,6 @@ fn testReinterpretBytesAsExternStruct() !void {
43test "reinterpret struct field at comptime" {45test "reinterpret struct field at comptime" {
44 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4950
...@@ -67,8 +68,6 @@ const Bytes = struct {...@@ -67,8 +68,6 @@ const Bytes = struct {
67};68};
6869
69test "comptime ptrcast keeps larger alignment" {70test "comptime ptrcast keeps larger alignment" {
70 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
71
72 comptime {71 comptime {
73 const a: u32 = 1234;72 const a: u32 = 1234;
74 const p = @ptrCast([*]const u8, &a);73 const p = @ptrCast([*]const u8, &a);
...@@ -77,7 +76,9 @@ test "comptime ptrcast keeps larger alignment" {...@@ -77,7 +76,9 @@ test "comptime ptrcast keeps larger alignment" {
77}76}
7877
79test "implicit optional pointer to optional anyopaque pointer" {78test "implicit optional pointer to optional anyopaque pointer" {
80 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8182
82 var buf: [4]u8 = "aoeu".*;83 var buf: [4]u8 = "aoeu".*;
83 var x: ?[*]u8 = &buf;84 var x: ?[*]u8 = &buf;