authorgravatar for 58830309+g-w1@users.noreply.github.comg-w1 <58830309+g-w1@users.noreply.github.com> 2021-06-21 11:47:34-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-21 18:47:34+03:00
loge13a182990c638bb69cd04e253ad6e0ecd734407
tree2a27981e6f412fbfa8ad52cc46a98f62f0b0c007
parenta95fdb06352a6a1e60d0167bad62f5a46345177a
signature Signed by PGP key 4AEE18F83AFDEB23

stage2 Sema: implement @intToPtr (#9144)

Co-authored-by: Veikka Tuominen <git@vexu.eu>

5 files changed, 112 insertions(+), 5 deletions(-)

src/Sema.zig+69-3
...@@ -5758,7 +5758,65 @@ fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr...@@ -5758,7 +5758,65 @@ fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
5758fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5758fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
5759 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;5759 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5760 const src = inst_data.src();5760 const src = inst_data.src();
5761 return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{});5761
5762 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
5763
5764 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
5765 const operand_res = try sema.resolveInst(extra.rhs);
5766 const operand_coerced = try sema.coerce(block, Type.initTag(.usize), operand_res, operand_src);
5767
5768 const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5769 const type_res = try sema.resolveType(block, src, extra.lhs);
5770 if (type_res.zigTypeTag() != .Pointer)
5771 return sema.mod.fail(&block.base, type_src, "expected pointer, found '{}'", .{type_res});
5772 const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
5773
5774 const uncasted_operand = try sema.resolveInst(extra.rhs);
5775 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
5776 const addr = val.toUnsignedInt();
5777 if (!type_res.isAllowzeroPtr() and addr == 0)
5778 return sema.mod.fail(&block.base, operand_src, "pointer type '{}' does not allow address zero", .{type_res});
5779 if (addr != 0 and addr % ptr_align != 0)
5780 return sema.mod.fail(&block.base, operand_src, "pointer type '{}' requires aligned address", .{type_res});
5781
5782 const val_payload = try sema.arena.create(Value.Payload.U64);
5783 val_payload.* = .{
5784 .base = .{ .tag = .int_u64 },
5785 .data = addr,
5786 };
5787 return sema.mod.constInst(sema.arena, src, .{
5788 .ty = type_res,
5789 .val = Value.initPayload(&val_payload.base),
5790 });
5791 }
5792
5793 try sema.requireRuntimeBlock(block, src);
5794 if (block.wantSafety()) {
5795 const zero = try sema.mod.constInst(sema.arena, src, .{
5796 .ty = Type.initTag(.u64),
5797 .val = Value.initTag(.zero),
5798 });
5799 if (!type_res.isAllowzeroPtr()) {
5800 const is_non_zero = try block.addBinOp(src, Type.initTag(.bool), .cmp_neq, operand_coerced, zero);
5801 try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
5802 }
5803
5804 if (ptr_align > 1) {
5805 const val_payload = try sema.arena.create(Value.Payload.U64);
5806 val_payload.* = .{
5807 .base = .{ .tag = .int_u64 },
5808 .data = ptr_align - 1,
5809 };
5810 const align_minus_1 = try sema.mod.constInst(sema.arena, src, .{
5811 .ty = Type.initTag(.u64),
5812 .val = Value.initPayload(&val_payload.base),
5813 });
5814 const remainder = try block.addBinOp(src, Type.initTag(.u64), .bit_and, operand_coerced, align_minus_1);
5815 const is_aligned = try block.addBinOp(src, Type.initTag(.bool), .cmp_eq, remainder, zero);
5816 try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
5817 }
5818 }
5819 return block.addUnOp(src, type_res, .bitcast, operand_coerced);
5762}5820}
57635821
5764fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {5822fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -6183,6 +6241,8 @@ pub const PanicId = enum {...@@ -6183,6 +6241,8 @@ pub const PanicId = enum {
6183 unreach,6241 unreach,
6184 unwrap_null,6242 unwrap_null,
6185 unwrap_errunion,6243 unwrap_errunion,
6244 cast_to_null,
6245 incorrect_alignment,
6186 invalid_error_code,6246 invalid_error_code,
6187};6247};
61886248
...@@ -6805,10 +6865,13 @@ fn storePtr(...@@ -6805,10 +6865,13 @@ fn storePtr(
6805 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)6865 if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
6806 return;6866 return;
68076867
6808 if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| {6868 if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {
6809 const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse6869 const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse
6810 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});6870 return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
68116871
6872 if (ptr_val.tag() == .int_u64)
6873 break :blk; // propogate it down to runtime
6874
6812 const comptime_alloc = ptr_val.castTag(.comptime_alloc).?;6875 const comptime_alloc = ptr_val.castTag(.comptime_alloc).?;
6813 if (comptime_alloc.data.runtime_index < block.runtime_index) {6876 if (comptime_alloc.data.runtime_index < block.runtime_index) {
6814 if (block.runtime_cond) |cond_src| {6877 if (block.runtime_cond) |cond_src| {
...@@ -6947,7 +7010,10 @@ fn analyzeLoad(...@@ -6947,7 +7010,10 @@ fn analyzeLoad(
6947 .Pointer => ptr.ty.elemType(),7010 .Pointer => ptr.ty.elemType(),
6948 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),7011 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
6949 };7012 };
6950 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {7013 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| blk: {
7014 if (ptr_val.tag() == .int_u64)
7015 break :blk; // do it at runtime
7016
6951 return sema.mod.constInst(sema.arena, src, .{7017 return sema.mod.constInst(sema.arena, src, .{
6952 .ty = elem_ty,7018 .ty = elem_ty,
6953 .val = try ptr_val.pointerDeref(sema.arena),7019 .val = try ptr_val.pointerDeref(sema.arena),
src/codegen.zig+3
...@@ -4169,6 +4169,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4169,6 +4169,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4169 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});4169 return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
4170 }4170 }
4171 }4171 }
4172 if (typed_value.val.tag() == .int_u64) {
4173 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4174 }
4172 return self.fail(src, "TODO codegen more kinds of const pointers", .{});4175 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
4173 },4176 },
4174 .Int => {4177 .Int => {
src/type.zig+2-2
...@@ -1538,7 +1538,7 @@ pub const Type = extern union {...@@ -1538,7 +1538,7 @@ pub const Type = extern union {
1538 .optional_single_const_pointer,1538 .optional_single_const_pointer,
1539 .optional_single_mut_pointer,1539 .optional_single_mut_pointer,
1540 => {1540 => {
1541 if (self.elemType().hasCodeGenBits()) return 1;1541 if (!self.elemType().hasCodeGenBits()) return 1;
1542 return @divExact(target.cpu.arch.ptrBitWidth(), 8);1542 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
1543 },1543 },
15441544
...@@ -1550,7 +1550,7 @@ pub const Type = extern union {...@@ -1550,7 +1550,7 @@ pub const Type = extern union {
1550 .c_mut_pointer,1550 .c_mut_pointer,
1551 .pointer,1551 .pointer,
1552 => {1552 => {
1553 if (self.elemType().hasCodeGenBits()) return 0;1553 if (!self.elemType().hasCodeGenBits()) return 0;
1554 return @divExact(target.cpu.arch.ptrBitWidth(), 8);1554 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
1555 },1555 },
15561556
src/value.zig+20
...@@ -979,6 +979,26 @@ pub const Value = extern union {...@@ -979,6 +979,26 @@ pub const Value = extern union {
979 };979 };
980 }980 }
981981
982 /// Asserts the value is numeric
983 pub fn isZero(self: Value) bool {
984 return switch (self.tag()) {
985 .zero => true,
986 .one => false,
987
988 .int_u64 => self.castTag(.int_u64).?.data == 0,
989 .int_i64 => self.castTag(.int_i64).?.data == 0,
990
991 .float_16 => self.castTag(.float_16).?.data == 0,
992 .float_32 => self.castTag(.float_32).?.data == 0,
993 .float_64 => self.castTag(.float_64).?.data == 0,
994 .float_128 => self.castTag(.float_128).?.data == 0,
995
996 .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
997 .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(),
998 else => unreachable,
999 };
1000 }
1001
982 pub fn orderAgainstZero(lhs: Value) std.math.Order {1002 pub fn orderAgainstZero(lhs: Value) std.math.Order {
983 return switch (lhs.tag()) {1003 return switch (lhs.tag()) {
984 .zero,1004 .zero,
test/stage2/test.zig+18
...@@ -1000,6 +1000,24 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1000,6 +1000,24 @@ pub fn addCases(ctx: *TestContext) !void {
1000 \\}1000 \\}
1001 , &[_][]const u8{":2:3: error: this is an error"});1001 , &[_][]const u8{":2:3: error: this is an error"});
10021002
1003 {
1004 var case = ctx.exe("intToPtr", linux_x64);
1005 case.addError(
1006 \\pub fn main() void {
1007 \\ _ = @intToPtr(*u8, 0);
1008 \\}
1009 , &[_][]const u8{
1010 ":2:24: error: pointer type '*u8' does not allow address zero",
1011 });
1012 case.addError(
1013 \\pub fn main() void {
1014 \\ _ = @intToPtr(*u32, 2);
1015 \\}
1016 , &[_][]const u8{
1017 ":2:25: error: pointer type '*u32' requires aligned address",
1018 });
1019 }
1020
1003 {1021 {
1004 var case = ctx.obj("variable shadowing", linux_x64);1022 var case = ctx.obj("variable shadowing", linux_x64);
1005 case.addError(1023 case.addError(