add ptrToInt builtin, remove usize(ptr) cast

closes #415
This commit is contained in:
Andrew Kelley 2017-08-08 17:38:25 -04:00
parent 9ca798bc75
commit 54675b060a
9 changed files with 110 additions and 80 deletions

View File

@ -1226,6 +1226,7 @@ enum BuiltinFnId {
BuiltinFnIdPtrCast,
BuiltinFnIdBitCast,
BuiltinFnIdIntToPtr,
BuiltinFnIdPtrToInt,
BuiltinFnIdEnumTagName,
BuiltinFnIdFieldParentPtr,
BuiltinFnIdOffsetOf,

View File

@ -4545,6 +4545,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrCast", 2);
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);

View File

@ -4372,6 +4372,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
}
case BuiltinFnIdPtrToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
return ir_build_ptr_to_int(irb, scope, node, arg0_value);
}
case BuiltinFnIdEnumTagName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@ -7336,30 +7345,6 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
return result;
}
static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, TypeTableEntry *wanted_type)
{
assert(wanted_type->id == TypeTableEntryIdInt);
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
return result;
}
}
IrInstruction *result = ir_build_ptr_to_int(&ira->new_irb, source_instr->scope,
source_instr->source_node, target);
result->value.type = wanted_type;
return result;
}
static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, TypeTableEntry *wanted_type)
{
@ -7500,7 +7485,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *wanted_type, IrInstruction *value)
{
TypeTableEntry *actual_type = value->value.type;
TypeTableEntry *usize_type = ira->codegen->builtin_types.entry_usize;
if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
return ira->codegen->invalid_instruction;
@ -7521,11 +7505,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
}
// explicit cast from pointer to usize
if (wanted_type == usize_type && type_is_codegen_pointer(actual_type)) {
return ir_analyze_ptr_to_int(ira, source_instr, value, wanted_type);
}
// explicit widening or shortening cast
if ((wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt) ||
@ -13937,6 +13916,47 @@ static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
zig_unreachable();
}
static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstructionPtrToInt *instruction) {
IrInstruction *target = instruction->target->other;
if (type_is_invalid(target->value.type))
return ira->codegen->builtin_types.entry_invalid;
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
if (!(target->value.type->id == TypeTableEntryIdPointer ||
target->value.type->id == TypeTableEntryIdFn ||
(target->value.type->id == TypeTableEntryIdMaybe &&
(target->value.type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
target->value.type->data.maybe.child_type->id == TypeTableEntryIdFn))))
{
ir_add_error(ira, target,
buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->builtin_types.entry_invalid;
if (target->value.type->id == TypeTableEntryIdMaybe) {
val = val->data.x_maybe;
}
if (val->type->id == TypeTableEntryIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, usize);
bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
ir_link_new_instruction(result, &instruction->base);
return usize;
}
}
IrInstruction *result = ir_build_ptr_to_int(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, target);
result->value.type = usize;
ir_link_new_instruction(result, &instruction->base);
return usize;
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -13948,7 +13968,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
case IrInstructionIdInitEnum:
case IrInstructionIdPtrToInt:
zig_unreachable();
case IrInstructionIdReturn:
return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
@ -14106,6 +14125,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
case IrInstructionIdIntToPtr:
return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdPtrToInt:
return ir_analyze_instruction_ptr_to_int(ira, (IrInstructionPtrToInt *)instruction);
case IrInstructionIdEnumTagName:
return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction);
case IrInstructionIdFieldParentPtr:

View File

@ -83,7 +83,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
var ignored_count: usize = 0;
var fp = usize(@frameAddress());
var fp = @ptrToInt(@frameAddress());
while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
if (ignored_count < ignore_frame_count) {
ignored_count += 1;

View File

@ -337,11 +337,11 @@ pub fn dup2(old: i32, new: i32) -> usize {
}
pub fn chdir(path: &const u8) -> usize {
arch.syscall1(arch.SYS_chdir, usize(path))
arch.syscall1(arch.SYS_chdir, @ptrToInt(path))
}
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
arch.syscall3(arch.SYS_execve, usize(path), usize(argv), usize(envp))
arch.syscall3(arch.SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp))
}
pub fn fork() -> usize {
@ -349,50 +349,50 @@ pub fn fork() -> usize {
}
pub fn getcwd(buf: &u8, size: usize) -> usize {
arch.syscall2(arch.SYS_getcwd, usize(buf), size)
arch.syscall2(arch.SYS_getcwd, @ptrToInt(buf), size)
}
pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {
arch.syscall3(arch.SYS_getdents, usize(fd), usize(dirp), usize(count))
arch.syscall3(arch.SYS_getdents, usize(fd), @ptrToInt(dirp), usize(count))
}
pub fn isatty(fd: i32) -> bool {
var wsz: winsize = undefined;
return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, usize(&wsz)) == 0;
return arch.syscall3(arch.SYS_ioctl, usize(fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
}
pub fn readlink(noalias path: &const u8, noalias buf_ptr: &u8, buf_len: usize) -> usize {
arch.syscall3(arch.SYS_readlink, usize(path), usize(buf_ptr), buf_len)
arch.syscall3(arch.SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len)
}
pub fn mkdir(path: &const u8, mode: usize) -> usize {
arch.syscall2(arch.SYS_mkdir, usize(path), mode)
arch.syscall2(arch.SYS_mkdir, @ptrToInt(path), mode)
}
pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
-> usize
{
arch.syscall6(arch.SYS_mmap, usize(address), length, prot, flags, usize(fd), offset)
arch.syscall6(arch.SYS_mmap, @ptrToInt(address), length, prot, flags, usize(fd), offset)
}
pub fn munmap(address: &u8, length: usize) -> usize {
arch.syscall2(arch.SYS_munmap, usize(address), length)
arch.syscall2(arch.SYS_munmap, @ptrToInt(address), length)
}
pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
arch.syscall3(arch.SYS_read, usize(fd), @ptrToInt(buf), count)
}
pub fn rmdir(path: &const u8) -> usize {
arch.syscall1(arch.SYS_rmdir, usize(path))
arch.syscall1(arch.SYS_rmdir, @ptrToInt(path))
}
pub fn symlink(existing: &const u8, new: &const u8) -> usize {
arch.syscall2(arch.SYS_symlink, usize(existing), usize(new))
arch.syscall2(arch.SYS_symlink, @ptrToInt(existing), @ptrToInt(new))
}
pub fn pread(fd: i32, buf: &u8, count: usize, offset: usize) -> usize {
arch.syscall4(arch.SYS_pread, usize(fd), usize(buf), count, offset)
arch.syscall4(arch.SYS_pread, usize(fd), @ptrToInt(buf), count, offset)
}
pub fn pipe(fd: &[2]i32) -> usize {
@ -400,31 +400,31 @@ pub fn pipe(fd: &[2]i32) -> usize {
}
pub fn pipe2(fd: &[2]i32, flags: usize) -> usize {
arch.syscall2(arch.SYS_pipe2, usize(fd), flags)
arch.syscall2(arch.SYS_pipe2, @ptrToInt(fd), flags)
}
pub fn write(fd: i32, buf: &const u8, count: usize) -> usize {
arch.syscall3(arch.SYS_write, usize(fd), usize(buf), count)
arch.syscall3(arch.SYS_write, usize(fd), @ptrToInt(buf), count)
}
pub fn pwrite(fd: i32, buf: &const u8, count: usize, offset: usize) -> usize {
arch.syscall4(arch.SYS_pwrite, usize(fd), usize(buf), count, offset)
arch.syscall4(arch.SYS_pwrite, usize(fd), @ptrToInt(buf), count, offset)
}
pub fn rename(old: &const u8, new: &const u8) -> usize {
arch.syscall2(arch.SYS_rename, usize(old), usize(new))
arch.syscall2(arch.SYS_rename, @ptrToInt(old), @ptrToInt(new))
}
pub fn open(path: &const u8, flags: usize, perm: usize) -> usize {
arch.syscall3(arch.SYS_open, usize(path), flags, perm)
arch.syscall3(arch.SYS_open, @ptrToInt(path), flags, perm)
}
pub fn create(path: &const u8, perm: usize) -> usize {
arch.syscall2(arch.SYS_creat, usize(path), perm)
arch.syscall2(arch.SYS_creat, @ptrToInt(path), perm)
}
pub fn openat(dirfd: i32, path: &const u8, flags: usize, mode: usize) -> usize {
arch.syscall4(arch.SYS_openat, usize(dirfd), usize(path), flags, mode)
arch.syscall4(arch.SYS_openat, usize(dirfd), @ptrToInt(path), flags, mode)
}
pub fn close(fd: i32) -> usize {
@ -441,7 +441,7 @@ pub fn exit(status: i32) -> noreturn {
}
pub fn getrandom(buf: &u8, count: usize, flags: u32) -> usize {
arch.syscall3(arch.SYS_getrandom, usize(buf), count, usize(flags))
arch.syscall3(arch.SYS_getrandom, @ptrToInt(buf), count, usize(flags))
}
pub fn kill(pid: i32, sig: i32) -> usize {
@ -449,11 +449,11 @@ pub fn kill(pid: i32, sig: i32) -> usize {
}
pub fn unlink(path: &const u8) -> usize {
arch.syscall1(arch.SYS_unlink, usize(path))
arch.syscall1(arch.SYS_unlink, @ptrToInt(path))
}
pub fn waitpid(pid: i32, status: &i32, options: i32) -> usize {
arch.syscall4(arch.SYS_wait4, usize(pid), usize(status), usize(options), 0)
arch.syscall4(arch.SYS_wait4, usize(pid), @ptrToInt(status), usize(options), 0)
}
const NSIG = 65;
@ -471,15 +471,15 @@ pub fn raise(sig: i32) -> i32 {
}
fn blockAllSignals(set: &sigset_t) {
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, usize(&all_mask), usize(set), NSIG/8);
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG/8);
}
fn blockAppSignals(set: &sigset_t) {
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, usize(&app_mask), usize(set), NSIG/8);
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG/8);
}
fn restoreSignals(set: &sigset_t) {
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, usize(set), 0, NSIG/8);
_ = arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG/8);
}
@ -537,11 +537,11 @@ pub const iovec = extern struct {
//
pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
arch.syscall3(arch.SYS_getsockname, usize(fd), usize(addr), usize(len))
arch.syscall3(arch.SYS_getsockname, usize(fd), @ptrToInt(addr), @ptrToInt(len))
}
pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
arch.syscall3(arch.SYS_getpeername, usize(fd), usize(addr), usize(len))
arch.syscall3(arch.SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len))
}
pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {
@ -549,29 +549,29 @@ pub fn socket(domain: i32, socket_type: i32, protocol: i32) -> usize {
}
pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) -> usize {
arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), usize(optlen))
arch.syscall5(arch.SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen))
}
pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) -> usize {
arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), usize(optval), usize(optlen))
arch.syscall5(arch.SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen))
}
pub fn sendmsg(fd: i32, msg: &const arch.msghdr, flags: u32) -> usize {
arch.syscall3(arch.SYS_sendmsg, usize(fd), usize(msg), flags)
arch.syscall3(arch.SYS_sendmsg, usize(fd), @ptrToInt(msg), flags)
}
pub fn connect(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
arch.syscall3(arch.SYS_connect, usize(fd), usize(addr), usize(len))
arch.syscall3(arch.SYS_connect, usize(fd), @ptrToInt(addr), usize(len))
}
pub fn recvmsg(fd: i32, msg: &arch.msghdr, flags: u32) -> usize {
arch.syscall3(arch.SYS_recvmsg, usize(fd), usize(msg), flags)
arch.syscall3(arch.SYS_recvmsg, usize(fd), @ptrToInt(msg), flags)
}
pub fn recvfrom(fd: i32, noalias buf: &u8, len: usize, flags: u32,
noalias addr: ?&sockaddr, noalias alen: ?&socklen_t) -> usize
{
arch.syscall6(arch.SYS_recvfrom, usize(fd), usize(buf), len, flags, usize(addr), usize(alen))
arch.syscall6(arch.SYS_recvfrom, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen))
}
pub fn shutdown(fd: i32, how: i32) -> usize {
@ -579,7 +579,7 @@ pub fn shutdown(fd: i32, how: i32) -> usize {
}
pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) -> usize {
arch.syscall3(arch.SYS_bind, usize(fd), usize(addr), usize(len))
arch.syscall3(arch.SYS_bind, usize(fd), @ptrToInt(addr), usize(len))
}
pub fn listen(fd: i32, backlog: i32) -> usize {
@ -587,11 +587,11 @@ pub fn listen(fd: i32, backlog: i32) -> usize {
}
pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) -> usize {
arch.syscall6(arch.SYS_sendto, usize(fd), usize(buf), len, flags, usize(addr), usize(alen))
arch.syscall6(arch.SYS_sendto, usize(fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), usize(alen))
}
pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> usize {
arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), usize(&fd[0]))
arch.syscall4(arch.SYS_socketpair, usize(domain), usize(socket_type), usize(protocol), @ptrToInt(&fd[0]))
}
pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usize {
@ -599,7 +599,7 @@ pub fn accept(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> usiz
}
pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: u32) -> usize {
arch.syscall4(arch.SYS_accept4, usize(fd), usize(addr), usize(len), flags)
arch.syscall4(arch.SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags)
}
// error NameTooLong;
@ -634,5 +634,5 @@ pub const stat = arch.stat;
pub const timespec = arch.timespec;
pub fn fstat(fd: i32, stat_buf: &stat) -> usize {
arch.syscall2(arch.SYS_fstat, usize(fd), usize(stat_buf))
arch.syscall2(arch.SYS_fstat, usize(fd), @ptrToInt(stat_buf))
}

View File

@ -4,13 +4,13 @@ const mem = @import("std").mem;
test "int to ptr cast" {
const x = usize(13);
const y = @intToPtr(&u8, x);
const z = usize(y);
const z = @ptrToInt(y);
assert(z == 13);
}
test "integer literal to pointer cast" {
const vga_mem = @intToPtr(&u16, 0xB8000);
assert(usize(vga_mem) == 0xB8000);
assert(@ptrToInt(vga_mem) == 0xB8000);
}
test "pointer reinterpret const float to int" {

View File

@ -28,7 +28,7 @@ test "offsetOf" {
// Non-packed struct fields can be moved/padded
const a: A = undefined;
assert(usize(&a.a) - usize(&a) == @offsetOf(A, "a"));
assert(usize(&a.b) - usize(&a) == @offsetOf(@typeOf(a), "b"));
assert(usize(&a.c) - usize(&a) == @offsetOf(@typeOf(a), "c"));
}
assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a"));
assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "b"));
assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "c"));
}

View File

@ -3,9 +3,9 @@ const assert = @import("std").debug.assert;
const x = @intToPtr(&i32, 0x1000)[0..0x500];
const y = x[0x100..];
test "compile time slice of pointer to hard coded address" {
assert(usize(x.ptr) == 0x1000);
assert(@ptrToInt(x.ptr) == 0x1000);
assert(x.len == 0x500);
assert(usize(y.ptr) == 0x1100);
assert(@ptrToInt(y.ptr) == 0x1100);
assert(y.len == 0x400);
}

View File

@ -1769,7 +1769,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
cases.add("save reference to inline function",
\\export fn foo() {
\\ quux(usize(bar));
\\ quux(@ptrToInt(bar));
\\}
\\inline fn bar() { }
\\extern fn quux(usize);
@ -1952,4 +1952,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
,
".tmp_source.zig:2:9: error: fractional component prevents float value 12.340000 from being casted to type 'i32'");
cases.add("non pointer given to @ptrToInt",
\\export fn entry(x: i32) -> usize {
\\ @ptrToInt(x)
\\}
,
".tmp_source.zig:2:15: error: expected pointer, found 'i32'");
}