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(...@@ -1352,15 +1352,14 @@ fn arrayInitExprRlPtr(
1352 defer gpa.free(elem_ptr_list);1352 defer gpa.free(elem_ptr_list);
13531353
1354 for (elements) |elem_init, i| {1354 for (elements) |elem_init, i| {
1355 const index_inst = try gz.addInt(i);1355 const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{
1356 const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{1356 .ptr = result_ptr,
1357 .lhs = result_ptr,1357 .index = @intCast(u32, i),
1358 .rhs = index_inst,
1359 });1358 });
1360 elem_ptr_list[i] = refToIndex(elem_ptr).?;1359 elem_ptr_list[i] = refToIndex(elem_ptr).?;
1361 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);1360 _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init);
1362 }1361 }
1363 _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{1362 _ = try gz.addPlNode(.validate_array_init, node, Zir.Inst.Block{
1364 .body_len = @intCast(u32, elem_ptr_list.len),1363 .body_len = @intCast(u32, elem_ptr_list.len),
1365 });1364 });
1366 try astgen.extra.appendSlice(gpa, elem_ptr_list);1365 try astgen.extra.appendSlice(gpa, elem_ptr_list);
...@@ -1539,7 +1538,7 @@ fn structInitExprRlPtrInner(...@@ -1539,7 +1538,7 @@ fn structInitExprRlPtrInner(
1539 field_ptr_list[i] = refToIndex(field_ptr).?;1538 field_ptr_list[i] = refToIndex(field_ptr).?;
1540 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);1539 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
1541 }1540 }
1542 _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{1541 _ = try gz.addPlNode(.validate_struct_init, node, Zir.Inst.Block{
1543 .body_len = @intCast(u32, field_ptr_list.len),1542 .body_len = @intCast(u32, field_ptr_list.len),
1544 });1543 });
1545 try astgen.extra.appendSlice(gpa, field_ptr_list);1544 try astgen.extra.appendSlice(gpa, field_ptr_list);
...@@ -2040,6 +2039,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2040,6 +2039,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2040 .elem_ptr,2039 .elem_ptr,
2041 .elem_val,2040 .elem_val,
2042 .elem_ptr_node,2041 .elem_ptr_node,
2042 .elem_ptr_imm,
2043 .elem_val_node,2043 .elem_val_node,
2044 .field_ptr,2044 .field_ptr,
2045 .field_val,2045 .field_val,
...@@ -2246,8 +2246,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2246,8 +2246,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2246 .store_to_block_ptr,2246 .store_to_block_ptr,
2247 .store_to_inferred_ptr,2247 .store_to_inferred_ptr,
2248 .resolve_inferred_alloc,2248 .resolve_inferred_alloc,
2249 .validate_struct_init_ptr,2249 .validate_struct_init,
2250 .validate_array_init_ptr,2250 .validate_array_init,
2251 .set_align_stack,2251 .set_align_stack,
2252 .set_cold,2252 .set_cold,
2253 .set_float_mode,2253 .set_float_mode,
src/Sema.zig+39-14
...@@ -479,6 +479,7 @@ pub fn analyzeBody(...@@ -479,6 +479,7 @@ pub fn analyzeBody(
479 .load => try sema.zirLoad(block, inst),479 .load => try sema.zirLoad(block, inst),
480 .elem_ptr => try sema.zirElemPtr(block, inst),480 .elem_ptr => try sema.zirElemPtr(block, inst),
481 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),481 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
482 .elem_ptr_imm => try sema.zirElemPtrImm(block, inst),
482 .elem_val => try sema.zirElemVal(block, inst),483 .elem_val => try sema.zirElemVal(block, inst),
483 .elem_val_node => try sema.zirElemValNode(block, inst),484 .elem_val_node => try sema.zirElemValNode(block, inst),
484 .elem_type => try sema.zirElemType(block, inst),485 .elem_type => try sema.zirElemType(block, inst),
...@@ -741,13 +742,13 @@ pub fn analyzeBody(...@@ -741,13 +742,13 @@ pub fn analyzeBody(
741 i += 1;742 i += 1;
742 continue;743 continue;
743 },744 },
744 .validate_struct_init_ptr => {745 .validate_struct_init => {
745 try sema.zirValidateStructInitPtr(block, inst);746 try sema.zirValidateStructInit(block, inst);
746 i += 1;747 i += 1;
747 continue;748 continue;
748 },749 },
749 .validate_array_init_ptr => {750 .validate_array_init => {
750 try sema.zirValidateArrayInitPtr(block, inst);751 try sema.zirValidateArrayInit(block, inst);
751 i += 1;752 i += 1;
752 continue;753 continue;
753 },754 },
...@@ -2106,7 +2107,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2106,7 +2107,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2106 }2107 }
2107}2108}
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 {
2110 const tracy = trace(@src());2111 const tracy = trace(@src());
2111 defer tracy.end();2112 defer tracy.end();
21122113
...@@ -2117,15 +2118,15 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co...@@ -2117,15 +2118,15 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co
2117 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;2118 const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
2118 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;2119 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
2119 const object_ptr = sema.resolveInst(field_ptr_extra.lhs);2120 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();
2121 switch (agg_ty.zigTypeTag()) {2122 switch (agg_ty.zigTypeTag()) {
2122 .Struct => return sema.validateStructInitPtr(2123 .Struct => return sema.validateStructInit(
2123 block,2124 block,
2124 agg_ty.castTag(.@"struct").?.data,2125 agg_ty.castTag(.@"struct").?.data,
2125 init_src,2126 init_src,
2126 instrs,2127 instrs,
2127 ),2128 ),
2128 .Union => return sema.validateUnionInitPtr(2129 .Union => return sema.validateUnionInit(
2129 block,2130 block,
2130 agg_ty.cast(Type.Payload.Union).?.data,2131 agg_ty.cast(Type.Payload.Union).?.data,
2131 init_src,2132 init_src,
...@@ -2136,7 +2137,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co...@@ -2136,7 +2137,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co
2136 }2137 }
2137}2138}
21382139
2139fn validateUnionInitPtr(2140fn validateUnionInit(
2140 sema: *Sema,2141 sema: *Sema,
2141 block: *Block,2142 block: *Block,
2142 union_obj: *Module.Union,2143 union_obj: *Module.Union,
...@@ -2175,7 +2176,7 @@ fn validateUnionInitPtr(...@@ -2175,7 +2176,7 @@ fn validateUnionInitPtr(
2175 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);2176 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
2176}2177}
21772178
2178fn validateStructInitPtr(2179fn validateStructInit(
2179 sema: *Sema,2180 sema: *Sema,
2180 block: *Block,2181 block: *Block,
2181 struct_obj: *Module.Struct,2182 struct_obj: *Module.Struct,
...@@ -2239,10 +2240,22 @@ fn validateStructInitPtr(...@@ -2239,10 +2240,22 @@ fn validateStructInitPtr(
2239 }2240 }
2240}2241}
22412242
2242fn zirValidateArrayInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {2243fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
2243 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;2244 const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
2244 const src = inst_data.src();2245 const init_src = validate_inst.src();
2245 return sema.fail(block, src, "TODO implement Sema.zirValidateArrayInitPtr", .{});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 }
2246}2259}
22472260
2248fn failWithBadFieldAccess(2261fn failWithBadFieldAccess(
...@@ -5169,6 +5182,18 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -5169,6 +5182,18 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
5169 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);5182 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
5170}5183}
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
5172fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5197fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5173 const tracy = trace(@src());5198 const tracy = trace(@src());
5174 defer tracy.end();5199 defer tracy.end();
src/Zir.zig+20-8
...@@ -344,6 +344,11 @@ pub const Inst = struct {...@@ -344,6 +344,11 @@ pub const Inst = struct {
344 /// Same as `elem_ptr` except also stores a source location node.344 /// Same as `elem_ptr` except also stores a source location node.
345 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.345 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
346 elem_ptr_node,346 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,
347 /// Given an array, slice, or pointer, returns the element at the provided index.352 /// Given an array, slice, or pointer, returns the element at the provided index.
348 /// Uses the `bin` union field. Source location is implied to be the same353 /// Uses the `bin` union field. Source location is implied to be the same
349 /// as the previous instruction.354 /// as the previous instruction.
...@@ -675,14 +680,14 @@ pub const Inst = struct {...@@ -675,14 +680,14 @@ pub const Inst = struct {
675 /// This instruction asserts that there is at least one field_ptr instruction,680 /// This instruction asserts that there is at least one field_ptr instruction,
676 /// because it must use one of them to find out the struct type.681 /// because it must use one of them to find out the struct type.
677 /// Uses the `pl_node` field. Payload is `Block`.682 /// Uses the `pl_node` field. Payload is `Block`.
678 validate_struct_init_ptr,683 validate_struct_init,
679 /// Given a set of `elem_ptr_node` instructions, assumes they are all part of an684 /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an
680 /// array initialization expression, and emits a compile error if the number of685 /// array initialization expression, and emits a compile error if the number of
681 /// elements does not match the array type.686 /// 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,
683 /// because it must use one of them to find out the array type.688 /// because it must use one of them to find out the array type.
684 /// Uses the `pl_node` field. Payload is `Block`.689 /// Uses the `pl_node` field. Payload is `Block`.
685 validate_array_init_ptr,690 validate_array_init,
686 /// A struct literal with a specified type, with no fields.691 /// A struct literal with a specified type, with no fields.
687 /// Uses the `un_node` field.692 /// Uses the `un_node` field.
688 struct_init_empty,693 struct_init_empty,
...@@ -1023,6 +1028,7 @@ pub const Inst = struct {...@@ -1023,6 +1028,7 @@ pub const Inst = struct {
1023 .elem_ptr,1028 .elem_ptr,
1024 .elem_val,1029 .elem_val,
1025 .elem_ptr_node,1030 .elem_ptr_node,
1031 .elem_ptr_imm,
1026 .elem_val_node,1032 .elem_val_node,
1027 .ensure_result_used,1033 .ensure_result_used,
1028 .ensure_result_non_error,1034 .ensure_result_non_error,
...@@ -1114,8 +1120,8 @@ pub const Inst = struct {...@@ -1114,8 +1120,8 @@ pub const Inst = struct {
1114 .switch_block_ref_else_multi,1120 .switch_block_ref_else_multi,
1115 .switch_block_ref_under,1121 .switch_block_ref_under,
1116 .switch_block_ref_under_multi,1122 .switch_block_ref_under_multi,
1117 .validate_struct_init_ptr,1123 .validate_struct_init,
1118 .validate_array_init_ptr,1124 .validate_array_init,
1119 .struct_init_empty,1125 .struct_init_empty,
1120 .struct_init,1126 .struct_init,
1121 .struct_init_ref,1127 .struct_init_ref,
...@@ -1291,6 +1297,7 @@ pub const Inst = struct {...@@ -1291,6 +1297,7 @@ pub const Inst = struct {
1291 .div = .pl_node,1297 .div = .pl_node,
1292 .elem_ptr = .bin,1298 .elem_ptr = .bin,
1293 .elem_ptr_node = .pl_node,1299 .elem_ptr_node = .pl_node,
1300 .elem_ptr_imm = .pl_node,
1294 .elem_val = .bin,1301 .elem_val = .bin,
1295 .elem_val_node = .pl_node,1302 .elem_val_node = .pl_node,
1296 .ensure_result_used = .un_node,1303 .ensure_result_used = .un_node,
...@@ -1377,8 +1384,8 @@ pub const Inst = struct {...@@ -1377,8 +1384,8 @@ pub const Inst = struct {
1377 .switch_capture_multi_ref = .switch_capture,1384 .switch_capture_multi_ref = .switch_capture,
1378 .switch_capture_else = .switch_capture,1385 .switch_capture_else = .switch_capture,
1379 .switch_capture_else_ref = .switch_capture,1386 .switch_capture_else_ref = .switch_capture,
1380 .validate_struct_init_ptr = .pl_node,1387 .validate_struct_init = .pl_node,
1381 .validate_array_init_ptr = .pl_node,1388 .validate_array_init = .pl_node,
1382 .struct_init_empty = .un_node,1389 .struct_init_empty = .un_node,
1383 .field_type = .pl_node,1390 .field_type = .pl_node,
1384 .field_type_ref = .pl_node,1391 .field_type_ref = .pl_node,
...@@ -2459,6 +2466,11 @@ pub const Inst = struct {...@@ -2459,6 +2466,11 @@ pub const Inst = struct {
2459 operand: Ref,2466 operand: Ref,
2460 };2467 };
24612468
2469 pub const ElemPtrImm = struct {
2470 ptr: Ref,
2471 index: u32,
2472 };
2473
2462 /// This form is supported when there are no ranges, and exactly 1 item per block.2474 /// This form is supported when there are no ranges, and exactly 1 item per block.
2463 /// Depending on zir tag and len fields, extra fields trail2475 /// Depending on zir tag and len fields, extra fields trail
2464 /// this one in the extra array.2476 /// this one in the extra array.
src/print_zir.zig+13-2
...@@ -355,6 +355,8 @@ const Writer = struct {...@@ -355,6 +355,8 @@ const Writer = struct {
355 .elem_val_node,355 .elem_val_node,
356 => try self.writePlNodeBin(stream, inst),356 => try self.writePlNodeBin(stream, inst),
357357
358 .elem_ptr_imm => try self.writeElemPtrImm(stream, inst),
359
358 .@"export" => try self.writePlNodeExport(stream, inst),360 .@"export" => try self.writePlNodeExport(stream, inst),
359 .export_value => try self.writePlNodeExportValue(stream, inst),361 .export_value => try self.writePlNodeExportValue(stream, inst),
360362
...@@ -364,8 +366,8 @@ const Writer = struct {...@@ -364,8 +366,8 @@ const Writer = struct {
364 .block_inline,366 .block_inline,
365 .suspend_block,367 .suspend_block,
366 .loop,368 .loop,
367 .validate_struct_init_ptr,369 .validate_struct_init,
368 .validate_array_init_ptr,370 .validate_array_init,
369 .c_import,371 .c_import,
370 => try self.writePlNodeBlock(stream, inst),372 => try self.writePlNodeBlock(stream, inst),
371373
...@@ -809,6 +811,15 @@ const Writer = struct {...@@ -809,6 +811,15 @@ const Writer = struct {
809 try self.writeSrc(stream, inst_data.src());811 try self.writeSrc(stream, inst_data.src());
810 }812 }
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
812 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {823 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
813 const inst_data = self.code.instructions.items(.data)[inst].pl_node;824 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
814 const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;825 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" {...@@ -33,8 +33,13 @@ test "array init with mult" {
33 var i: [8]u8 = [2]u8{ a, 'b' } ** 4;33 var i: [8]u8 = [2]u8{ a, 'b' } ** 4;
34 try expect(std.mem.eql(u8, &i, "abababab"));34 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
38 var j: [4]u8 = [1]u8{'a'} ** 4;36 var j: [4]u8 = [1]u8{'a'} ** 4;
39 try expect(std.mem.eql(u8, &j, "aaaa"));37 try expect(std.mem.eql(u8, &j, "aaaa"));
40}38}
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;...@@ -4,6 +4,13 @@ const mem = std.mem;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;5const 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
7test "array with sentinels" {14test "array with sentinels" {
8 const S = struct {15 const S = struct {
9 fn doTheTest(is_ct: bool) !void {16 fn doTheTest(is_ct: bool) !void {
...@@ -39,13 +46,6 @@ test "void arrays" {...@@ -39,13 +46,6 @@ test "void arrays" {
39 try expect(array.len == 4);46 try expect(array.len == 4);
40}47}
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
49test "array dot len const expr" {49test "array dot len const expr" {
50 try expect(comptime x: {50 try expect(comptime x: {
51 break :x some_array.len == 4;51 break :x some_array.len == 4;