authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 18:47:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 18:49:37-07:00
logf736cde397a6abb1399827ed5988c43001706580
treec1ce080f82846a4322eac7be653a78044338e740
parent017d3864de1f337d01726e87534a4e2093c7265f

Sema: implement pointer to tuple to pointer to array coercion

This involved an LLVM backend fix for the aggregate_init instruction.

8 files changed, 80 insertions(+), 41 deletions(-)

src/Sema.zig+44-18
......@@ -16005,9 +16005,17 @@ fn coerce(
1600516005 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1600616006 }
1600716007
16008 // coercion to C pointer
16009 if (dest_info.size == .C) {
16010 switch (inst_ty.zigTypeTag()) {
16008 // cast from *T and [*]T to *anyopaque
16009 // but don't do it if the source type is a double pointer
16010 if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
16011 inst_ty.childType().zigTypeTag() != .Pointer)
16012 {
16013 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
16014 }
16015
16016 switch (dest_info.size) {
16017 // coercion to C pointer
16018 .C => switch (inst_ty.zigTypeTag()) {
1601116019 .Null => {
1601216020 return sema.addConstant(dest_ty, Value.@"null");
1601316021 },
......@@ -16041,22 +16049,10 @@ fn coerce(
1604116049 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
1604216050 },
1604316051 else => {},
16044 }
16045 }
16046
16047 // cast from *T and [*]T to *anyopaque
16048 // but don't do it if the source type is a double pointer
16049 if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer and
16050 inst_ty.childType().zigTypeTag() != .Pointer)
16051 {
16052 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
16053 }
16054
16055 switch (dest_info.size) {
16056 .C, .Many => {},
16052 },
1605716053 .One => switch (dest_info.pointee_type.zigTypeTag()) {
1605816054 .Union => {
16059 // cast from pointer to anonymous struct to pointer to union
16055 // pointer to anonymous struct to pointer to union
1606016056 if (inst_ty.isSinglePointer() and
1606116057 inst_ty.childType().isAnonStruct() and
1606216058 !dest_info.mutable)
......@@ -16065,7 +16061,7 @@ fn coerce(
1606516061 }
1606616062 },
1606716063 .Struct => {
16068 // cast from pointer to anonymous struct to pointer to struct
16064 // pointer to anonymous struct to pointer to struct
1606916065 if (inst_ty.isSinglePointer() and
1607016066 inst_ty.childType().isAnonStruct() and
1607116067 !dest_info.mutable)
......@@ -16073,6 +16069,15 @@ fn coerce(
1607316069 return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
1607416070 }
1607516071 },
16072 .Array => {
16073 // pointer to tuple to pointer to array
16074 if (inst_ty.isSinglePointer() and
16075 inst_ty.childType().isTuple() and
16076 !dest_info.mutable)
16077 {
16078 return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
16079 }
16080 },
1607616081 else => {},
1607716082 },
1607816083 .Slice => {
......@@ -16084,6 +16089,7 @@ fn coerce(
1608416089 return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
1608516090 }
1608616091 },
16092 .Many => {},
1608716093 }
1608816094
1608916095 // This will give an extra hint on top of what the bottom of this func would provide.
......@@ -17554,6 +17560,26 @@ fn coerceTupleToSlicePtrs(
1755417560 return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
1755517561}
1755617562
17563/// If the lengths match, coerces element-wise.
17564fn coerceTupleToArrayPtrs(
17565 sema: *Sema,
17566 block: *Block,
17567 ptr_array_ty: Type,
17568 array_ty_src: LazySrcLoc,
17569 ptr_tuple: Air.Inst.Ref,
17570 tuple_src: LazySrcLoc,
17571) !Air.Inst.Ref {
17572 const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
17573 const ptr_info = ptr_array_ty.ptrInfo().data;
17574 const array_ty = ptr_info.pointee_type;
17575 const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
17576 if (ptr_info.@"align" != 0) {
17577 return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{});
17578 }
17579 const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst);
17580 return ptr_array;
17581}
17582
1755717583/// Handles both tuples and anon struct literals. Coerces field-wise. Reports
1755817584/// errors for both extra fields and missing fields.
1755917585fn coerceTupleToStruct(
src/codegen/llvm.zig+17-4
......@@ -5838,8 +5838,15 @@ pub const FuncGen = struct {
58385838 const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?;
58395839 indices[1] = llvm_u32.constInt(llvm_i, .False);
58405840 const field_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
5841 const store_inst = self.builder.buildStore(llvm_elem, field_ptr);
5842 store_inst.setAlignment(result_ty.structFieldAlign(i, target));
5841 var field_ptr_payload: Type.Payload.Pointer = .{
5842 .data = .{
5843 .pointee_type = self.air.typeOf(elem),
5844 .@"align" = result_ty.structFieldAlign(i, target),
5845 .@"addrspace" = .generic,
5846 },
5847 };
5848 const field_ptr_ty = Type.initPayload(&field_ptr_payload.base);
5849 self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic);
58435850 }
58445851
58455852 return alloca_inst;
......@@ -5871,8 +5878,14 @@ pub const FuncGen = struct {
58715878 };
58725879 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
58735880 const llvm_elem = try self.resolveInst(elem);
5874 const store_inst = self.builder.buildStore(llvm_elem, elem_ptr);
5875 store_inst.setAlignment(elem_ty.abiAlignment(target));
5881 var elem_ptr_payload: Type.Payload.Pointer = .{
5882 .data = .{
5883 .pointee_type = elem_ty,
5884 .@"addrspace" = .generic,
5885 },
5886 };
5887 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);
5888 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
58765889 }
58775890
58785891 return alloca_inst;
test/behavior/align.zig+4-6
......@@ -193,11 +193,9 @@ test "function alignment" {
193193}
194194
195195test "implicitly decreasing fn alignment" {
196 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
197196 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
198 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
199197 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
198 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
201199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
202200
203201 // function alignment is a compile error on wasm32/wasm64
......@@ -321,7 +319,6 @@ const DefaultAligned = struct {
321319
322320test "read 128-bit field from default aligned struct in stack memory" {
323321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
324 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
325322 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
326323 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
327324 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -353,10 +350,10 @@ test "read 128-bit field from default aligned struct in global memory" {
353350
354351test "struct field explicit alignment" {
355352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
356 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
357353 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
358354 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
359355 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
360357
361358 const S = struct {
362359 const Node = struct {
......@@ -402,8 +399,9 @@ test "align(@alignOf(T)) T does not force resolution of T" {
402399}
403400
404401test "align(N) on functions" {
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
406402 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
403
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407405 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
408406 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
409407 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/array.zig+2-3
......@@ -553,12 +553,11 @@ test "type coercion of anon struct literal to array" {
553553}
554554
555555test "type coercion of pointer to anon struct literal to pointer to array" {
556 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
557 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
558556 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
559557 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
560 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
561559 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
560 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
562561
563562 const S = struct {
564563 const U = union {
test/behavior/basic.zig+2-1
......@@ -760,7 +760,8 @@ test "pointer to thread local array" {
760760threadlocal var buffer: [11]u8 = undefined;
761761
762762test "auto created variables have correct alignment" {
763 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
763 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764765
765766 const S = struct {
766767 fn foo(str: [*]const u8) u32 {
test/behavior/slice.zig+6-4
......@@ -518,7 +518,11 @@ test "slice syntax resulting in pointer-to-array" {
518518}
519519
520520test "type coercion of pointer to anon struct literal to pointer to slice" {
521 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
521 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
522 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
523 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
522526
523527 const S = struct {
524528 const U = union {
......@@ -546,7 +550,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
546550 try expect(mem.eql(u8, slice2[2], "world!"));
547551 }
548552 };
549 // try S.doTheTest();
553 try S.doTheTest();
550554 comptime try S.doTheTest();
551555}
552556
......@@ -578,8 +582,6 @@ test "slice bounds in comptime concatenation" {
578582}
579583
580584test "slice sentinel access at comptime" {
581 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
582
583585 {
584586 const str0 = &[_:0]u8{ '1', '2', '3' };
585587 const slice0: [:0]const u8 = str0;
test/behavior/struct.zig+1-1
......@@ -426,7 +426,7 @@ test "packed struct 24bits" {
426426 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
427427 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
428428 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_llvm and builtin.stage2_arch == .wasm32) return error.SkipZigTest; // TODO
429 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
430430
431431 comptime {
432432 try expect(@sizeOf(Foo24Bits) == 4);
test/behavior/while.zig+4-4
......@@ -289,9 +289,8 @@ test "while bool 2 break statements and an else" {
289289}
290290
291291test "while optional 2 break statements and an else" {
292 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
293 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
294 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
292 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
295294
296295 const S = struct {
297296 fn entry(opt_t: ?bool, f: bool) !void {
......@@ -308,7 +307,8 @@ test "while optional 2 break statements and an else" {
308307}
309308
310309test "while error 2 break statements and an else" {
311 if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
312312
313313 const S = struct {
314314 fn entry(opt_t: anyerror!bool, f: bool) !void {