stage2 Sema: implement @intToPtr (#9144)

Co-authored-by: Veikka Tuominen <git@vexu.eu>
This commit is contained in:
g-w1
2021-06-21 11:47:34 -04:00
committed by GitHub
parent a95fdb0635
commit e13a182990
5 changed files with 112 additions and 5 deletions

View File

@@ -5758,7 +5758,65 @@ fn zirIntToFloat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
fn zirIntToPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
return sema.mod.fail(&block.base, src, "TODO: Sema.zirIntToPtr", .{});
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const operand_res = try sema.resolveInst(extra.rhs);
const operand_coerced = try sema.coerce(block, Type.initTag(.usize), operand_res, operand_src);
const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const type_res = try sema.resolveType(block, src, extra.lhs);
if (type_res.zigTypeTag() != .Pointer)
return sema.mod.fail(&block.base, type_src, "expected pointer, found '{}'", .{type_res});
const ptr_align = type_res.ptrAlignment(sema.mod.getTarget());
const uncasted_operand = try sema.resolveInst(extra.rhs);
if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
const addr = val.toUnsignedInt();
if (!type_res.isAllowzeroPtr() and addr == 0)
return sema.mod.fail(&block.base, operand_src, "pointer type '{}' does not allow address zero", .{type_res});
if (addr != 0 and addr % ptr_align != 0)
return sema.mod.fail(&block.base, operand_src, "pointer type '{}' requires aligned address", .{type_res});
const val_payload = try sema.arena.create(Value.Payload.U64);
val_payload.* = .{
.base = .{ .tag = .int_u64 },
.data = addr,
};
return sema.mod.constInst(sema.arena, src, .{
.ty = type_res,
.val = Value.initPayload(&val_payload.base),
});
}
try sema.requireRuntimeBlock(block, src);
if (block.wantSafety()) {
const zero = try sema.mod.constInst(sema.arena, src, .{
.ty = Type.initTag(.u64),
.val = Value.initTag(.zero),
});
if (!type_res.isAllowzeroPtr()) {
const is_non_zero = try block.addBinOp(src, Type.initTag(.bool), .cmp_neq, operand_coerced, zero);
try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
}
if (ptr_align > 1) {
const val_payload = try sema.arena.create(Value.Payload.U64);
val_payload.* = .{
.base = .{ .tag = .int_u64 },
.data = ptr_align - 1,
};
const align_minus_1 = try sema.mod.constInst(sema.arena, src, .{
.ty = Type.initTag(.u64),
.val = Value.initPayload(&val_payload.base),
});
const remainder = try block.addBinOp(src, Type.initTag(.u64), .bit_and, operand_coerced, align_minus_1);
const is_aligned = try block.addBinOp(src, Type.initTag(.bool), .cmp_eq, remainder, zero);
try sema.addSafetyCheck(block, is_aligned, .incorrect_alignment);
}
}
return block.addUnOp(src, type_res, .bitcast, operand_coerced);
}
fn zirErrSetCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
@@ -6183,6 +6241,8 @@ pub const PanicId = enum {
unreach,
unwrap_null,
unwrap_errunion,
cast_to_null,
incorrect_alignment,
invalid_error_code,
};
@@ -6805,10 +6865,13 @@ fn storePtr(
if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
return;
if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| {
if (try sema.resolvePossiblyUndefinedValue(block, src, ptr)) |ptr_val| blk: {
const const_val = (try sema.resolvePossiblyUndefinedValue(block, src, value)) orelse
return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{});
if (ptr_val.tag() == .int_u64)
break :blk; // propogate it down to runtime
const comptime_alloc = ptr_val.castTag(.comptime_alloc).?;
if (comptime_alloc.data.runtime_index < block.runtime_index) {
if (block.runtime_cond) |cond_src| {
@@ -6947,7 +7010,10 @@ fn analyzeLoad(
.Pointer => ptr.ty.elemType(),
else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
};
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| blk: {
if (ptr_val.tag() == .int_u64)
break :blk; // do it at runtime
return sema.mod.constInst(sema.arena, src, .{
.ty = elem_ty,
.val = try ptr_val.pointerDeref(sema.arena),

View File

@@ -4169,6 +4169,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
}
}
if (typed_value.val.tag() == .int_u64) {
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
}
return self.fail(src, "TODO codegen more kinds of const pointers", .{});
},
.Int => {

View File

@@ -1538,7 +1538,7 @@ pub const Type = extern union {
.optional_single_const_pointer,
.optional_single_mut_pointer,
=> {
if (self.elemType().hasCodeGenBits()) return 1;
if (!self.elemType().hasCodeGenBits()) return 1;
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
},
@@ -1550,7 +1550,7 @@ pub const Type = extern union {
.c_mut_pointer,
.pointer,
=> {
if (self.elemType().hasCodeGenBits()) return 0;
if (!self.elemType().hasCodeGenBits()) return 0;
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
},

View File

@@ -979,6 +979,26 @@ pub const Value = extern union {
};
}
/// Asserts the value is numeric
pub fn isZero(self: Value) bool {
return switch (self.tag()) {
.zero => true,
.one => false,
.int_u64 => self.castTag(.int_u64).?.data == 0,
.int_i64 => self.castTag(.int_i64).?.data == 0,
.float_16 => self.castTag(.float_16).?.data == 0,
.float_32 => self.castTag(.float_32).?.data == 0,
.float_64 => self.castTag(.float_64).?.data == 0,
.float_128 => self.castTag(.float_128).?.data == 0,
.int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
.int_big_negative => self.castTag(.int_big_negative).?.asBigInt().eqZero(),
else => unreachable,
};
}
pub fn orderAgainstZero(lhs: Value) std.math.Order {
return switch (lhs.tag()) {
.zero,

View File

@@ -1000,6 +1000,24 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, &[_][]const u8{":2:3: error: this is an error"});
{
var case = ctx.exe("intToPtr", linux_x64);
case.addError(
\\pub fn main() void {
\\ _ = @intToPtr(*u8, 0);
\\}
, &[_][]const u8{
":2:24: error: pointer type '*u8' does not allow address zero",
});
case.addError(
\\pub fn main() void {
\\ _ = @intToPtr(*u32, 2);
\\}
, &[_][]const u8{
":2:25: error: pointer type '*u32' requires aligned address",
});
}
{
var case = ctx.obj("variable shadowing", linux_x64);
case.addError(