authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-07 15:27:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-07 15:27:05-07:00
log76335bc7badd41af0ebb7dd196e1550d7e99d8e7
tree4057c1def983d9ea39d67e617e52820fed61331f
parent601ac82041653adc2acbcfd947a54286944df9df

stage2: implement array literal with explicit type

New ZIR instruction: elem_ptr_imm This saves some memory for array literals since the element indexes are communicated as immediate values rather than as references to other ZIR instructions.

6 files changed, 94 insertions(+), 41 deletions(-)

src/AstGen.zig+8-8
......@@ -1352,15 +1352,14 @@ fn arrayInitExprRlPtr(
13521352 defer gpa.free(elem_ptr_list);
13531353
13541354 for (elements) |elem_init, i| {
1355 const index_inst = try gz.addInt(i);
1356 const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{
1357 .lhs = result_ptr,
1358 .rhs = index_inst,
1355 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{
1356 .ptr = result_ptr,
1357 .index = @intCast(u32, i),
13591358 });
13601359 elem_ptr_list[i] = refToIndex(elem_ptr).?;
13611360 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);
13621361 }
1363 _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{
1362 _ = try gz.addPlNode(.validate_array_init, node, Zir.Inst.Block{
13641363 .body_len = @intCast(u32, elem_ptr_list.len),
13651364 });
13661365 try astgen.extra.appendSlice(gpa, elem_ptr_list);
......@@ -1539,7 +1538,7 @@ fn structInitExprRlPtrInner(
15391538 field_ptr_list[i] = refToIndex(field_ptr).?;
15401539 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
15411540 }
1542 _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
1541 _ = try gz.addPlNode(.validate_struct_init, node, Zir.Inst.Block{
15431542 .body_len = @intCast(u32, field_ptr_list.len),
15441543 });
15451544 try astgen.extra.appendSlice(gpa, field_ptr_list);
......@@ -2040,6 +2039,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
20402039 .elem_ptr,
20412040 .elem_val,
20422041 .elem_ptr_node,
2042 .elem_ptr_imm,
20432043 .elem_val_node,
20442044 .field_ptr,
20452045 .field_val,
......@@ -2246,8 +2246,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22462246 .store_to_block_ptr,
22472247 .store_to_inferred_ptr,
22482248 .resolve_inferred_alloc,
2249 .validate_struct_init_ptr,
2250 .validate_array_init_ptr,
2249 .validate_struct_init,
2250 .validate_array_init,
22512251 .set_align_stack,
22522252 .set_cold,
22532253 .set_float_mode,
src/Sema.zig+39-14
......@@ -479,6 +479,7 @@ pub fn analyzeBody(
479479 .load => try sema.zirLoad(block, inst),
480480 .elem_ptr => try sema.zirElemPtr(block, inst),
481481 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
482 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst),
482483 .elem_val => try sema.zirElemVal(block, inst),
483484 .elem_val_node => try sema.zirElemValNode(block, inst),
484485 .elem_type => try sema.zirElemType(block, inst),
......@@ -741,13 +742,13 @@ pub fn analyzeBody(
741742 i += 1;
742743 continue;
743744 },
744 .validate_struct_init_ptr => {
745 try sema.zirValidateStructInitPtr(block, inst);
745 .validate_struct_init => {
746 try sema.zirValidateStructInit(block, inst);
746747 i += 1;
747748 continue;
748749 },
749 .validate_array_init_ptr => {
750 try sema.zirValidateArrayInitPtr(block, inst);
750 .validate_array_init => {
751 try sema.zirValidateArrayInit(block, inst);
751752 i += 1;
752753 continue;
753754 },
......@@ -2106,7 +2107,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
21062107 }
21072108}
21082109
2109fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2110fn zirValidateStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
21102111 const tracy = trace(@src());
21112112 defer tracy.end();
21122113
......@@ -2117,15 +2118,15 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co
21172118 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
21182119 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
21192120 const object_ptr = sema.resolveInst(field_ptr_extra.lhs);
2120 const agg_ty = sema.typeOf(object_ptr).elemType();
2121 const agg_ty = sema.typeOf(object_ptr).childType();
21212122 switch (agg_ty.zigTypeTag()) {
2122 .Struct => return sema.validateStructInitPtr(
2123 .Struct => return sema.validateStructInit(
21232124 block,
21242125 agg_ty.castTag(.@"struct").?.data,
21252126 init_src,
21262127 instrs,
21272128 ),
2128 .Union => return sema.validateUnionInitPtr(
2129 .Union => return sema.validateUnionInit(
21292130 block,
21302131 agg_ty.cast(Type.Payload.Union).?.data,
21312132 init_src,
......@@ -2136,7 +2137,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co
21362137 }
21372138}
21382139
2139fn validateUnionInitPtr(
2140fn validateUnionInit(
21402141 sema: *Sema,
21412142 block: *Block,
21422143 union_obj: *Module.Union,
......@@ -2175,7 +2176,7 @@ fn validateUnionInitPtr(
21752176 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
21762177}
21772178
2178fn validateStructInitPtr(
2179fn validateStructInit(
21792180 sema: *Sema,
21802181 block: *Block,
21812182 struct_obj: *Module.Struct,
......@@ -2239,10 +2240,22 @@ fn validateStructInitPtr(
22392240 }
22402241}
22412242
2242fn zirValidateArrayInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2243 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2244 const src = inst_data.src();
2245 return sema.fail(block, src, "TODO implement Sema.zirValidateArrayInitPtr", .{});
2243fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2244 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
2245 const init_src = validate_inst.src();
2246 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
2247 const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len];
2248 const elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
2249 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, elem_ptr_data.payload_index).data;
2250 const array_ptr = sema.resolveInst(elem_ptr_extra.ptr);
2251 const array_ty = sema.typeOf(array_ptr).childType();
2252 const array_len = array_ty.arrayLen();
2253
2254 if (instrs.len != array_len) {
2255 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
2256 array_len, instrs.len,
2257 });
2258 }
22462259}
22472260
22482261fn failWithBadFieldAccess(
......@@ -5169,6 +5182,18 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
51695182 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
51705183}
51715184
5185fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5186 const tracy = trace(@src());
5187 defer tracy.end();
5188
5189 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
5190 const src = inst_data.src();
5191 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
5192 const array_ptr = sema.resolveInst(extra.ptr);
5193 const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);
5194 return sema.elemPtr(block, src, array_ptr, elem_index, src);
5195}
5196
51725197fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
51735198 const tracy = trace(@src());
51745199 defer tracy.end();
src/Zir.zig+20-8
......@@ -344,6 +344,11 @@ pub const Inst = struct {
344344 /// Same as `elem_ptr` except also stores a source location node.
345345 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
346346 elem_ptr_node,
347 /// Same as `elem_ptr_node` except the index is stored immediately rather than
348 /// as a reference to another ZIR instruction.
349 /// Uses the `pl_node` union field. AST node is an element inside array initialization
350 /// syntax. Payload is `ElemPtrImm`.
351 elem_ptr_imm,
347352 /// Given an array, slice, or pointer, returns the element at the provided index.
348353 /// Uses the `bin` union field. Source location is implied to be the same
349354 /// as the previous instruction.
......@@ -675,14 +680,14 @@ pub const Inst = struct {
675680 /// This instruction asserts that there is at least one field_ptr instruction,
676681 /// because it must use one of them to find out the struct type.
677682 /// Uses the `pl_node` field. Payload is `Block`.
678 validate_struct_init_ptr,
679 /// Given a set of `elem_ptr_node` instructions, assumes they are all part of an
683 validate_struct_init,
684 /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an
680685 /// array initialization expression, and emits a compile error if the number of
681686 /// elements does not match the array type.
682 /// This instruction asserts that there is at least one elem_ptr_node instruction,
687 /// This instruction asserts that there is at least one `elem_ptr_imm` instruction,
683688 /// because it must use one of them to find out the array type.
684689 /// Uses the `pl_node` field. Payload is `Block`.
685 validate_array_init_ptr,
690 validate_array_init,
686691 /// A struct literal with a specified type, with no fields.
687692 /// Uses the `un_node` field.
688693 struct_init_empty,
......@@ -1023,6 +1028,7 @@ pub const Inst = struct {
10231028 .elem_ptr,
10241029 .elem_val,
10251030 .elem_ptr_node,
1031 .elem_ptr_imm,
10261032 .elem_val_node,
10271033 .ensure_result_used,
10281034 .ensure_result_non_error,
......@@ -1114,8 +1120,8 @@ pub const Inst = struct {
11141120 .switch_block_ref_else_multi,
11151121 .switch_block_ref_under,
11161122 .switch_block_ref_under_multi,
1117 .validate_struct_init_ptr,
1118 .validate_array_init_ptr,
1123 .validate_struct_init,
1124 .validate_array_init,
11191125 .struct_init_empty,
11201126 .struct_init,
11211127 .struct_init_ref,
......@@ -1291,6 +1297,7 @@ pub const Inst = struct {
12911297 .div = .pl_node,
12921298 .elem_ptr = .bin,
12931299 .elem_ptr_node = .pl_node,
1300 .elem_ptr_imm = .pl_node,
12941301 .elem_val = .bin,
12951302 .elem_val_node = .pl_node,
12961303 .ensure_result_used = .un_node,
......@@ -1377,8 +1384,8 @@ pub const Inst = struct {
13771384 .switch_capture_multi_ref = .switch_capture,
13781385 .switch_capture_else = .switch_capture,
13791386 .switch_capture_else_ref = .switch_capture,
1380 .validate_struct_init_ptr = .pl_node,
1381 .validate_array_init_ptr = .pl_node,
1387 .validate_struct_init = .pl_node,
1388 .validate_array_init = .pl_node,
13821389 .struct_init_empty = .un_node,
13831390 .field_type = .pl_node,
13841391 .field_type_ref = .pl_node,
......@@ -2459,6 +2466,11 @@ pub const Inst = struct {
24592466 operand: Ref,
24602467 };
24612468
2469 pub const ElemPtrImm = struct {
2470 ptr: Ref,
2471 index: u32,
2472 };
2473
24622474 /// This form is supported when there are no ranges, and exactly 1 item per block.
24632475 /// Depending on zir tag and len fields, extra fields trail
24642476 /// this one in the extra array.
src/print_zir.zig+13-2
......@@ -355,6 +355,8 @@ const Writer = struct {
355355 .elem_val_node,
356356 => try self.writePlNodeBin(stream, inst),
357357
358 .elem_ptr_imm => try self.writeElemPtrImm(stream, inst),
359
358360 .@"export" => try self.writePlNodeExport(stream, inst),
359361 .export_value => try self.writePlNodeExportValue(stream, inst),
360362
......@@ -364,8 +366,8 @@ const Writer = struct {
364366 .block_inline,
365367 .suspend_block,
366368 .loop,
367 .validate_struct_init_ptr,
368 .validate_array_init_ptr,
369 .validate_struct_init,
370 .validate_array_init,
369371 .c_import,
370372 => try self.writePlNodeBlock(stream, inst),
371373
......@@ -809,6 +811,15 @@ const Writer = struct {
809811 try self.writeSrc(stream, inst_data.src());
810812 }
811813
814 fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
815 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
816 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
817
818 try self.writeInstRef(stream, extra.ptr);
819 try stream.print(", {d}) ", .{extra.index});
820 try self.writeSrc(stream, inst_data.src());
821 }
822
812823 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
813824 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
814825 const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
test/behavior/array.zig+7-2
......@@ -33,8 +33,13 @@ test "array init with mult" {
3333 var i: [8]u8 = [2]u8{ a, 'b' } ** 4;
3434 try expect(std.mem.eql(u8, &i, "abababab"));
3535
36 // this should cause a Value.repeated to be emitted in AIR.
37 // TODO: find a way to test that this is actually getting emmited
3836 var j: [4]u8 = [1]u8{'a'} ** 4;
3937 try expect(std.mem.eql(u8, &j, "aaaa"));
4038}
39
40test "array literal with explicit type" {
41 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
42
43 try expect(hex_mult.len == 4);
44 try expect(hex_mult[1] == 256);
45}
test/behavior/array_stage1.zig+7-7
......@@ -4,6 +4,13 @@ const mem = std.mem;
44const expect = testing.expect;
55const expectEqual = testing.expectEqual;
66
7test "array literal with inferred length" {
8 const hex_mult = [_]u16{ 4096, 256, 16, 1 };
9
10 try expect(hex_mult.len == 4);
11 try expect(hex_mult[1] == 256);
12}
13
714test "array with sentinels" {
815 const S = struct {
916 fn doTheTest(is_ct: bool) !void {
......@@ -39,13 +46,6 @@ test "void arrays" {
3946 try expect(array.len == 4);
4047}
4148
42test "array literal" {
43 const hex_mult = [_]u16{ 4096, 256, 16, 1 };
44
45 try expect(hex_mult.len == 4);
46 try expect(hex_mult[1] == 256);
47}
48
4949test "array dot len const expr" {
5050 try expect(comptime x: {
5151 break :x some_array.len == 4;