authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-25 19:41:19-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-10-25 19:41:19-04:00
logdf198ea60e05664b5b72a43aae815fa06d94c19c
treeedf13ce2d73ab17a56d6b07b4734b97260bde3eb
parent30d01c8fea68baab396081da040f49defa494088
parent21bf3b80666c14c9b2a2e1ec984a6b4bb23a5bb7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10034 from Snektron/stage2-slice

stage2: slice and optional improvements

7 files changed, 127 insertions(+), 77 deletions(-)

src/Sema.zig+43-11
......@@ -8013,14 +8013,24 @@ fn analyzePtrArithmetic(
80138013 const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
80148014 // TODO adjust the return type according to alignment and other factors
80158015 const runtime_src = rs: {
8016 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
8017 if (try sema.resolveDefinedValue(block, offset_src, offset)) |offset_val| {
8016 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
8017 if (try sema.resolveMaybeUndefVal(block, offset_src, offset)) |offset_val| {
80188018 const ptr_ty = sema.typeOf(ptr);
8019 const offset_int = offset_val.toUnsignedInt();
80208019 const new_ptr_ty = ptr_ty; // TODO modify alignment
8020
8021 if (ptr_val.isUndef() or offset_val.isUndef()) {
8022 return sema.addConstUndef(new_ptr_ty);
8023 }
8024
8025 const offset_int = offset_val.toUnsignedInt();
80218026 if (ptr_val.getUnsignedInt()) |addr| {
80228027 const target = sema.mod.getTarget();
8023 const elem_ty = ptr_ty.childType();
8028 const ptr_child_ty = ptr_ty.childType();
8029 const elem_ty = if (ptr_ty.isSinglePointer() and ptr_child_ty.zigTypeTag() == .Array)
8030 ptr_child_ty.childType()
8031 else
8032 ptr_child_ty;
8033
80248034 const elem_size = elem_ty.abiSize(target);
80258035 const new_addr = switch (air_tag) {
80268036 .ptr_add => addr + elem_size * offset_int,
......@@ -13217,8 +13227,8 @@ fn analyzeSlice(
1321713227 var elem_ty = ptr_ptr_child_ty.childType();
1321813228 switch (ptr_ptr_child_ty.zigTypeTag()) {
1321913229 .Array => {},
13220 .Pointer => {
13221 if (ptr_ptr_child_ty.isSinglePointer()) {
13230 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
13231 .One => {
1322213232 const double_child_ty = ptr_ptr_child_ty.childType();
1322313233 if (double_child_ty.zigTypeTag() == .Array) {
1322413234 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
......@@ -13228,10 +13238,23 @@ fn analyzeSlice(
1322813238 } else {
1322913239 return sema.fail(block, ptr_src, "slice of single-item pointer", .{});
1323013240 }
13231 }
13241 },
13242 .Many, .C => {
13243 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
13244 slice_ty = ptr_ptr_child_ty;
13245 array_ty = ptr_ptr_child_ty;
13246 elem_ty = ptr_ptr_child_ty.childType();
13247 },
13248 .Slice => {
13249 ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
13250 slice_ty = ptr_ptr_child_ty;
13251 array_ty = ptr_ptr_child_ty;
13252 elem_ty = ptr_ptr_child_ty.childType();
13253 },
1323213254 },
1323313255 else => return sema.fail(block, ptr_src, "slice of non-array type '{}'", .{ptr_ptr_child_ty}),
1323413256 }
13257
1323513258 const ptr = if (slice_ty.isSlice())
1323613259 try sema.analyzeSlicePtr(block, src, ptr_or_slice, slice_ty, ptr_src)
1323713260 else
......@@ -13263,7 +13286,6 @@ fn analyzeSlice(
1326313286
1326413287 const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src);
1326513288
13266 const opt_new_ptr_val = try sema.resolveDefinedValue(block, ptr_src, new_ptr);
1326713289 const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
1326813290
1326913291 const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
......@@ -13287,11 +13309,21 @@ fn analyzeSlice(
1328713309 .size = .One,
1328813310 });
1328913311
13290 if (opt_new_ptr_val) |new_ptr_val| {
13291 return sema.addConstant(return_ty, new_ptr_val);
13292 } else {
13312 const opt_new_ptr_val = try sema.resolveMaybeUndefVal(block, ptr_src, new_ptr);
13313 const new_ptr_val = opt_new_ptr_val orelse {
1329313314 return block.addBitCast(return_ty, new_ptr);
13315 };
13316
13317 if (!new_ptr_val.isUndef()) {
13318 return sema.addConstant(return_ty, new_ptr_val);
1329413319 }
13320
13321 // Special case: @as([]i32, undefined)[x..x]
13322 if (new_len_int == 0) {
13323 return sema.addConstUndef(return_ty);
13324 }
13325
13326 return sema.fail(block, ptr_src, "non-zero length slice of undefined pointer", .{});
1329513327 }
1329613328
1329713329 const return_ty = try Type.ptr(sema.arena, .{
src/codegen/llvm.zig+9-8
......@@ -767,7 +767,7 @@ pub const DeclGen = struct {
767767 }
768768 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
769769 const elem_ty = t.childType();
770 const llvm_elem_ty = if (elem_ty.hasCodeGenBits())
770 const llvm_elem_ty = if (elem_ty.hasCodeGenBits() or elem_ty.zigTypeTag() == .Array)
771771 try dg.llvmType(elem_ty)
772772 else
773773 dg.context.intType(8);
......@@ -1480,7 +1480,7 @@ pub const DeclGen = struct {
14801480 }
14811481
14821482 const llvm_type = try self.llvmType(tv.ty);
1483 if (!tv.ty.childType().hasCodeGenBits()) {
1483 if (!tv.ty.childType().hasCodeGenBits() or !decl.ty.hasCodeGenBits()) {
14841484 return self.lowerPtrToVoid(tv.ty);
14851485 }
14861486
......@@ -1502,7 +1502,7 @@ pub const DeclGen = struct {
15021502 // for non-optional pointers. We also need to respect the alignment, even though
15031503 // the address will never be dereferenced.
15041504 const llvm_usize = try dg.llvmType(Type.usize);
1505 const llvm_ptr_ty = dg.context.intType(8).pointerType(0);
1505 const llvm_ptr_ty = try dg.llvmType(ptr_ty);
15061506 if (alignment != 0) {
15071507 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);
15081508 }
......@@ -2475,6 +2475,12 @@ pub const FuncGen = struct {
24752475 const operand = try self.resolveInst(un_op);
24762476 const operand_ty = self.air.typeOf(un_op);
24772477 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
2478 if (optional_ty.isPtrLikeOptional()) {
2479 const optional_llvm_ty = try self.dg.llvmType(optional_ty);
2480 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
2481 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
2482 }
2483
24782484 var buf: Type.Payload.ElemType = undefined;
24792485 const payload_ty = optional_ty.optionalChild(&buf);
24802486 if (!payload_ty.hasCodeGenBits()) {
......@@ -2484,11 +2490,6 @@ pub const FuncGen = struct {
24842490 return operand;
24852491 }
24862492 }
2487 if (optional_ty.isPtrLikeOptional()) {
2488 const optional_llvm_ty = try self.dg.llvmType(optional_ty);
2489 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
2490 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
2491 }
24922493
24932494 if (operand_is_ptr or isByRef(optional_ty)) {
24942495 const index_type = self.context.intType(32);
src/type.zig+5-1
......@@ -2347,11 +2347,13 @@ pub const Type = extern union {
23472347 }
23482348 }
23492349
2350 /// Asserts that the type is an optional
2350 /// Asserts that the type is an optional or a pointer that can be null.
23512351 pub fn isPtrLikeOptional(self: Type) bool {
23522352 switch (self.tag()) {
23532353 .optional_single_const_pointer,
23542354 .optional_single_mut_pointer,
2355 .c_const_pointer,
2356 .c_mut_pointer,
23552357 => return true,
23562358
23572359 .optional => {
......@@ -2367,6 +2369,8 @@ pub const Type = extern union {
23672369 .Many, .One => return !info.@"allowzero",
23682370 }
23692371 },
2372
2373 .pointer => return self.castTag(.pointer).?.data.size == .C,
23702374 else => unreachable,
23712375 }
23722376 }
test/behavior.zig+1
......@@ -65,6 +65,7 @@ test {
6565 if (builtin.zig_is_stage2) {
6666 // When all comptime_memory.zig tests pass, #9646 can be closed.
6767 // _ = @import("behavior/comptime_memory.zig");
68 _ = @import("behavior/slice_stage2.zig");
6869 } else {
6970 _ = @import("behavior/align_stage1.zig");
7071 _ = @import("behavior/alignof.zig");
test/behavior/slice.zig+57
......@@ -109,3 +109,60 @@ test "slice of type" {
109109 }
110110 }
111111}
112
113test "generic malloc free" {
114 const a = memAlloc(u8, 10) catch unreachable;
115 memFree(u8, a);
116}
117var some_mem: [100]u8 = undefined;
118fn memAlloc(comptime T: type, n: usize) anyerror![]T {
119 return @ptrCast([*]T, &some_mem[0])[0..n];
120}
121fn memFree(comptime T: type, memory: []T) void {
122 _ = memory;
123}
124
125test "slice of hardcoded address to pointer" {
126 const S = struct {
127 fn doTheTest() !void {
128 const pointer = @intToPtr([*]u8, 0x04)[0..2];
129 comptime try expect(@TypeOf(pointer) == *[2]u8);
130 const slice: []const u8 = pointer;
131 try expect(@ptrToInt(slice.ptr) == 4);
132 try expect(slice.len == 2);
133 }
134 };
135
136 try S.doTheTest();
137}
138
139test "comptime slice of pointer preserves comptime var" {
140 comptime {
141 var buff: [10]u8 = undefined;
142 var a = @ptrCast([*]u8, &buff);
143 a[0..1][0] = 1;
144 try expect(buff[0..][0..][0] == 1);
145 }
146}
147
148test "comptime pointer cast array and then slice" {
149 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
150
151 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
152 const sliceA: []const u8 = ptrA[0..2];
153
154 const ptrB: [*]const u8 = &array;
155 const sliceB: []const u8 = ptrB[0..2];
156
157 try expect(sliceA[1] == 2);
158 try expect(sliceB[1] == 2);
159}
160
161test "slicing zero length array" {
162 const s1 = ""[0..];
163 const s2 = ([_]u32{})[0..];
164 try expect(s1.len == 0);
165 try expect(s2.len == 0);
166 try expect(mem.eql(u8, s1, ""));
167 try expect(mem.eql(u32, s2, &[_]u32{}));
168}
test/behavior/slice_stage1.zig-57
......@@ -4,15 +4,6 @@ const expectEqualSlices = std.testing.expectEqualSlices;
44const expectEqual = std.testing.expectEqual;
55const mem = std.mem;
66
7test "slicing zero length array" {
8 const s1 = ""[0..];
9 const s2 = ([_]u32{})[0..];
10 try expect(s1.len == 0);
11 try expect(s2.len == 0);
12 try expect(mem.eql(u8, s1, ""));
13 try expect(mem.eql(u32, s2, &[_]u32{}));
14}
15
167test "slice string literal has correct type" {
178 comptime {
189 try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
......@@ -25,18 +16,6 @@ test "slice string literal has correct type" {
2516 comptime try expect(@TypeOf(array[runtime_zero..]) == []const i32);
2617}
2718
28test "generic malloc free" {
29 const a = memAlloc(u8, 10) catch unreachable;
30 memFree(u8, a);
31}
32var some_mem: [100]u8 = undefined;
33fn memAlloc(comptime T: type, n: usize) anyerror![]T {
34 return @ptrCast([*]T, &some_mem[0])[0..n];
35}
36fn memFree(comptime T: type, memory: []T) void {
37 _ = memory;
38}
39
4019test "result location zero sized array inside struct field implicit cast to slice" {
4120 const E = struct {
4221 entries: []u32,
......@@ -307,20 +286,6 @@ test "slice syntax resulting in pointer-to-array" {
307286 comptime try S.doTheTest();
308287}
309288
310test "slice of hardcoded address to pointer" {
311 const S = struct {
312 fn doTheTest() !void {
313 const pointer = @intToPtr([*]u8, 0x04)[0..2];
314 comptime try expect(@TypeOf(pointer) == *[2]u8);
315 const slice: []const u8 = pointer;
316 try expect(@ptrToInt(slice.ptr) == 4);
317 try expect(slice.len == 2);
318 }
319 };
320
321 try S.doTheTest();
322}
323
324289test "type coercion of pointer to anon struct literal to pointer to slice" {
325290 const S = struct {
326291 const U = union {
......@@ -352,15 +317,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
352317 comptime try S.doTheTest();
353318}
354319
355test "comptime slice of pointer preserves comptime var" {
356 comptime {
357 var buff: [10]u8 = undefined;
358 var a = @ptrCast([*]u8, &buff);
359 a[0..1][0] = 1;
360 try expect(buff[0..][0..][0] == 1);
361 }
362}
363
364320test "array concat of slices gives slice" {
365321 comptime {
366322 var a: []const u8 = "aoeu";
......@@ -370,19 +326,6 @@ test "array concat of slices gives slice" {
370326 }
371327}
372328
373test "comptime pointer cast array and then slice" {
374 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
375
376 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
377 const sliceA: []const u8 = ptrA[0..2];
378
379 const ptrB: [*]const u8 = &array;
380 const sliceB: []const u8 = ptrB[0..2];
381
382 try expect(sliceA[1] == 2);
383 try expect(sliceB[1] == 2);
384}
385
386329test "slice bounds in comptime concatenation" {
387330 const bs = comptime blk: {
388331 const b = "........1........";
test/behavior/slice_stage2.zig created+12
......@@ -0,0 +1,12 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];
6test "compile time slice of pointer to hard coded address" {
7 try expect(@ptrToInt(x) == 0x1000);
8 try expect(x.len == 0x500);
9
10 try expect(@ptrToInt(y) == 0x1400);
11 try expect(y.len == 0x400);
12}