aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-23 19:46:48 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-23 19:47:32 -0700
commit22b4c9e1a9595bd94ada4c500a430e2668ffcd07 (patch)
tree325e312f063422e19b0427373194b703b8cc3b53 /src
parentee98d8700818aa667137e3aa580b16df2ba6d680 (diff)
downloadzig-22b4c9e1a9595bd94ada4c500a430e2668ffcd07.tar.gz
zig-22b4c9e1a9595bd94ada4c500a430e2668ffcd07.zip
stage2: implement more C pointer Sema and comptime ptr arith
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig75
-rw-r--r--src/codegen/llvm.zig7
-rw-r--r--src/type.zig1
-rw-r--r--src/value.zig22
4 files changed, 78 insertions, 27 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 80c299d1b0..6e01b894fd 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -7983,12 +7983,25 @@ fn analyzePtrArithmetic(
const runtime_src = rs: {
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try sema.resolveDefinedValue(block, offset_src, offset)) |offset_val| {
+ const ptr_ty = sema.typeOf(ptr);
+ const offset_int = offset_val.toUnsignedInt();
+ const new_ptr_ty = ptr_ty; // TODO modify alignment
+ if (ptr_val.getUnsignedInt()) |addr| {
+ const target = sema.mod.getTarget();
+ const elem_ty = ptr_ty.childType();
+ const elem_size = elem_ty.abiSize(target);
+ const new_addr = switch (air_tag) {
+ .ptr_add => addr + elem_size * offset_int,
+ .ptr_sub => addr - elem_size * offset_int,
+ else => unreachable,
+ };
+ const new_ptr_val = try Value.Tag.int_u64.create(sema.arena, new_addr);
+ return sema.addConstant(new_ptr_ty, new_ptr_val);
+ }
if (air_tag == .ptr_sub) {
return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
}
- const offset_int = offset_val.toUnsignedInt();
const new_ptr_val = try ptr_val.elemPtr(sema.arena, offset_int);
- const new_ptr_ty = sema.typeOf(ptr);
return sema.addConstant(new_ptr_ty, new_ptr_val);
} else break :rs offset_src;
} else break :rs ptr_src;
@@ -11979,6 +11992,8 @@ fn coerce(
return sema.wrapOptional(block, dest_ty, intermediate, inst_src);
},
.Pointer => {
+ const dest_info = dest_ty.ptrInfo().data;
+
// Function body to function pointer.
if (inst_ty.zigTypeTag() == .Fn) {
const fn_val = try sema.resolveConstValue(block, inst_src, inst);
@@ -11989,16 +12004,16 @@ fn coerce(
// *T to *[1]T
single_item: {
- if (!dest_ty.isSinglePointer()) break :single_item;
+ if (dest_info.size != .One) break :single_item;
if (!inst_ty.isSinglePointer()) break :single_item;
const ptr_elem_ty = inst_ty.childType();
- const array_ty = dest_ty.childType();
+ const array_ty = dest_info.pointee_type;
if (array_ty.zigTypeTag() != .Array) break :single_item;
const array_elem_ty = array_ty.childType();
- const dest_is_mut = !dest_ty.isConstPtr();
+ const dest_is_mut = dest_info.mutable;
if (inst_ty.isConstPtr() and dest_is_mut) break :single_item;
- if (inst_ty.isVolatilePtr() and !dest_ty.isVolatilePtr()) break :single_item;
- if (inst_ty.ptrAddressSpace() != dest_ty.ptrAddressSpace()) break :single_item;
+ if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :single_item;
+ if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
switch (coerceInMemoryAllowed(array_elem_ty, ptr_elem_ty, dest_is_mut, target)) {
.ok => {},
.no_match => break :single_item,
@@ -12012,18 +12027,18 @@ fn coerce(
const array_ty = inst_ty.childType();
if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
const array_elem_type = array_ty.childType();
- const dest_is_mut = !dest_ty.isConstPtr();
+ const dest_is_mut = dest_info.mutable;
if (inst_ty.isConstPtr() and dest_is_mut) break :src_array_ptr;
- if (inst_ty.isVolatilePtr() and !dest_ty.isVolatilePtr()) break :src_array_ptr;
- if (inst_ty.ptrAddressSpace() != dest_ty.ptrAddressSpace()) break :src_array_ptr;
+ if (inst_ty.isVolatilePtr() and !dest_info.@"volatile") break :src_array_ptr;
+ if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :src_array_ptr;
- const dst_elem_type = dest_ty.childType();
+ const dst_elem_type = dest_info.pointee_type;
switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type, dest_is_mut, target)) {
.ok => {},
.no_match => break :src_array_ptr,
}
- switch (dest_ty.ptrSize()) {
+ switch (dest_info.size) {
.Slice => {
// *[N]T to []T
return sema.coerceArrayPtrToSlice(block, dest_ty, inst, inst_src);
@@ -12036,7 +12051,7 @@ fn coerce(
// *[N]T to [*]T
// *[N:s]T to [*:s]T
// *[N:s]T to [*]T
- if (dest_ty.sentinel()) |dst_sentinel| {
+ if (dest_info.sentinel) |dst_sentinel| {
if (array_ty.sentinel()) |src_sentinel| {
if (src_sentinel.eql(dst_sentinel, dst_elem_type)) {
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
@@ -12051,9 +12066,24 @@ fn coerce(
}
// coercion to C pointer
- if (dest_ty.ptrSize() == .C) {
- if (inst_ty.zigTypeTag() == .Null) {
- return sema.addConstant(dest_ty, Value.@"null");
+ if (dest_info.size == .C) {
+ switch (inst_ty.zigTypeTag()) {
+ .Null => {
+ return sema.addConstant(dest_ty, Value.@"null");
+ },
+ .ComptimeInt => {
+ const addr = try sema.coerce(block, Type.usize, inst, inst_src);
+ return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
+ },
+ .Int => {
+ const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
+ .signed => Type.isize,
+ .unsigned => Type.usize,
+ };
+ const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src);
+ return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
+ },
+ else => {},
}
}
},
@@ -13632,6 +13662,19 @@ fn resolvePeerTypes(
continue;
}
+ if (chosen_ty_tag == .Pointer and chosen_ty.ptrSize() == .C and
+ (candidate_ty_tag == .Int or candidate_ty_tag == .ComptimeInt))
+ {
+ continue;
+ }
+ if (candidate_ty_tag == .Pointer and candidate_ty.ptrSize() == .C and
+ (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt))
+ {
+ chosen = candidate;
+ chosen_i = candidate_i + 1;
+ continue;
+ }
+
if (chosen_ty_tag == .ComptimeFloat and candidate_ty_tag == .ComptimeInt)
continue;
if (chosen_ty_tag == .ComptimeInt and candidate_ty_tag == .ComptimeFloat) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 3a01440135..aa0a99ea6c 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1106,7 +1106,7 @@ pub const DeclGen = struct {
return parent_ptr.constInBoundsGEP(&indices, indices.len);
}
},
- .null_value => {
+ .null_value, .zero => {
const llvm_type = try self.llvmType(tv.ty);
return llvm_type.constNull();
},
@@ -3180,8 +3180,9 @@ pub const FuncGen = struct {
const inst_ty = self.air.typeOfIndex(inst);
const llvm_dest_ty = try self.dg.llvmType(inst_ty);
- // TODO look into pulling this logic out into a different AIR instruction than bitcast
- if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {
+ if (operand_ty.zigTypeTag() == .Int and inst_ty.zigTypeTag() == .Pointer) {
+ return self.builder.buildIntToPtr(operand, llvm_dest_ty, "");
+ } else if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) {
const target = self.dg.module.getTarget();
const elem_ty = operand_ty.childType();
if (!isByRef(inst_ty)) {
diff --git a/src/type.zig b/src/type.zig
index 380c75ca77..e77780d9ca 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -4006,6 +4006,7 @@ pub const Type = extern union {
pub const @"u8" = initTag(.u8);
pub const @"bool" = initTag(.bool);
pub const @"usize" = initTag(.usize);
+ pub const @"isize" = initTag(.isize);
pub const @"comptime_int" = initTag(.comptime_int);
pub const @"void" = initTag(.void);
pub const @"type" = initTag(.type);
diff --git a/src/value.zig b/src/value.zig
index 3a4cdb1438..af1216f652 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -937,9 +937,10 @@ pub const Value = extern union {
}
}
- /// Asserts the value is an integer and it fits in a u64
- pub fn toUnsignedInt(self: Value) u64 {
- switch (self.tag()) {
+ /// If the value fits in a u64, return it, otherwise null.
+ /// Asserts not undefined.
+ pub fn getUnsignedInt(val: Value) ?u64 {
+ switch (val.tag()) {
.zero,
.bool_false,
.the_only_possible_value, // i0, u0
@@ -949,16 +950,21 @@ pub const Value = extern union {
.bool_true,
=> return 1,
- .int_u64 => return self.castTag(.int_u64).?.data,
- .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
- .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
- .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
+ .int_u64 => return val.castTag(.int_u64).?.data,
+ .int_i64 => return @intCast(u64, val.castTag(.int_i64).?.data),
+ .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null,
+ .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null,
.undef => unreachable,
- else => unreachable,
+ else => return null,
}
}
+ /// Asserts the value is an integer and it fits in a u64
+ pub fn toUnsignedInt(val: Value) u64 {
+ return getUnsignedInt(val).?;
+ }
+
/// Asserts the value is an integer and it fits in a i64
pub fn toSignedInt(self: Value) i64 {
switch (self.tag()) {