diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-10-23 19:46:48 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-23 19:47:32 -0700 |
| commit | 22b4c9e1a9595bd94ada4c500a430e2668ffcd07 (patch) | |
| tree | 325e312f063422e19b0427373194b703b8cc3b53 /src | |
| parent | ee98d8700818aa667137e3aa580b16df2ba6d680 (diff) | |
| download | zig-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.zig | 75 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 7 | ||||
| -rw-r--r-- | src/type.zig | 1 | ||||
| -rw-r--r-- | src/value.zig | 22 |
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()) { |
