diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-10-07 15:27:05 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-07 15:27:05 -0700 |
| commit | 76335bc7badd41af0ebb7dd196e1550d7e99d8e7 (patch) | |
| tree | 4057c1def983d9ea39d67e617e52820fed61331f /src | |
| parent | 601ac82041653adc2acbcfd947a54286944df9df (diff) | |
| download | zig-76335bc7badd41af0ebb7dd196e1550d7e99d8e7.tar.gz zig-76335bc7badd41af0ebb7dd196e1550d7e99d8e7.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 16 | ||||
| -rw-r--r-- | src/Sema.zig | 53 | ||||
| -rw-r--r-- | src/Zir.zig | 28 | ||||
| -rw-r--r-- | src/print_zir.zig | 15 |
4 files changed, 80 insertions, 32 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 6e7f376b16..423e11e582 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1352,15 +1352,14 @@ fn arrayInitExprRlPtr( defer gpa.free(elem_ptr_list); for (elements) |elem_init, i| { - const index_inst = try gz.addInt(i); - const elem_ptr = try gz.addPlNode(.elem_ptr_node, elem_init, Zir.Inst.Bin{ - .lhs = result_ptr, - .rhs = index_inst, + const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{ + .ptr = result_ptr, + .index = @intCast(u32, i), }); elem_ptr_list[i] = refToIndex(elem_ptr).?; _ = try expr(gz, scope, .{ .ptr = elem_ptr }, elem_init); } - _ = try gz.addPlNode(.validate_array_init_ptr, node, Zir.Inst.Block{ + _ = try gz.addPlNode(.validate_array_init, node, Zir.Inst.Block{ .body_len = @intCast(u32, elem_ptr_list.len), }); try astgen.extra.appendSlice(gpa, elem_ptr_list); @@ -1539,7 +1538,7 @@ fn structInitExprRlPtrInner( field_ptr_list[i] = refToIndex(field_ptr).?; _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init); } - _ = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{ + _ = try gz.addPlNode(.validate_struct_init, node, Zir.Inst.Block{ .body_len = @intCast(u32, field_ptr_list.len), }); try astgen.extra.appendSlice(gpa, field_ptr_list); @@ -2040,6 +2039,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .elem_ptr, .elem_val, .elem_ptr_node, + .elem_ptr_imm, .elem_val_node, .field_ptr, .field_val, @@ -2246,8 +2246,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .store_to_block_ptr, .store_to_inferred_ptr, .resolve_inferred_alloc, - .validate_struct_init_ptr, - .validate_array_init_ptr, + .validate_struct_init, + .validate_array_init, .set_align_stack, .set_cold, .set_float_mode, diff --git a/src/Sema.zig b/src/Sema.zig index 32970ccd40..8fc25a9278 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -479,6 +479,7 @@ pub fn analyzeBody( .load => try sema.zirLoad(block, inst), .elem_ptr => try sema.zirElemPtr(block, inst), .elem_ptr_node => try sema.zirElemPtrNode(block, inst), + .elem_ptr_imm => try sema.zirElemPtrImm(block, inst), .elem_val => try sema.zirElemVal(block, inst), .elem_val_node => try sema.zirElemValNode(block, inst), .elem_type => try sema.zirElemType(block, inst), @@ -741,13 +742,13 @@ pub fn analyzeBody( i += 1; continue; }, - .validate_struct_init_ptr => { - try sema.zirValidateStructInitPtr(block, inst); + .validate_struct_init => { + try sema.zirValidateStructInit(block, inst); i += 1; continue; }, - .validate_array_init_ptr => { - try sema.zirValidateArrayInitPtr(block, inst); + .validate_array_init => { + try sema.zirValidateArrayInit(block, inst); i += 1; continue; }, @@ -2106,7 +2107,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com } } -fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { +fn zirValidateStructInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const tracy = trace(@src()); defer tracy.end(); @@ -2117,15 +2118,15 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; const object_ptr = sema.resolveInst(field_ptr_extra.lhs); - const agg_ty = sema.typeOf(object_ptr).elemType(); + const agg_ty = sema.typeOf(object_ptr).childType(); switch (agg_ty.zigTypeTag()) { - .Struct => return sema.validateStructInitPtr( + .Struct => return sema.validateStructInit( block, agg_ty.castTag(.@"struct").?.data, init_src, instrs, ), - .Union => return sema.validateUnionInitPtr( + .Union => return sema.validateUnionInit( block, agg_ty.cast(Type.Payload.Union).?.data, init_src, @@ -2136,7 +2137,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Co } } -fn validateUnionInitPtr( +fn validateUnionInit( sema: *Sema, block: *Block, union_obj: *Module.Union, @@ -2175,7 +2176,7 @@ fn validateUnionInitPtr( _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag); } -fn validateStructInitPtr( +fn validateStructInit( sema: *Sema, block: *Block, struct_obj: *Module.Struct, @@ -2239,10 +2240,22 @@ fn validateStructInitPtr( } } -fn zirValidateArrayInitPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); - return sema.fail(block, src, "TODO implement Sema.zirValidateArrayInitPtr", .{}); +fn zirValidateArrayInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { + const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; + const init_src = validate_inst.src(); + const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); + const instrs = sema.code.extra[validate_extra.end..][0..validate_extra.data.body_len]; + const elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; + const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, elem_ptr_data.payload_index).data; + const array_ptr = sema.resolveInst(elem_ptr_extra.ptr); + const array_ty = sema.typeOf(array_ptr).childType(); + const array_len = array_ty.arrayLen(); + + if (instrs.len != array_len) { + return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{ + array_len, instrs.len, + }); + } } fn failWithBadFieldAccess( @@ -5169,6 +5182,18 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src); } +fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const tracy = trace(@src()); + defer tracy.end(); + + const inst_data = sema.code.instructions.items(.data)[inst].pl_node; + const src = inst_data.src(); + const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; + const array_ptr = sema.resolveInst(extra.ptr); + const elem_index = try sema.addIntUnsigned(Type.usize, extra.index); + return sema.elemPtr(block, src, array_ptr, elem_index, src); +} + fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); diff --git a/src/Zir.zig b/src/Zir.zig index 3f3a0dbafe..cc2c028345 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -344,6 +344,11 @@ pub const Inst = struct { /// Same as `elem_ptr` except also stores a source location node. /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`. elem_ptr_node, + /// Same as `elem_ptr_node` except the index is stored immediately rather than + /// as a reference to another ZIR instruction. + /// Uses the `pl_node` union field. AST node is an element inside array initialization + /// syntax. Payload is `ElemPtrImm`. + elem_ptr_imm, /// Given an array, slice, or pointer, returns the element at the provided index. /// Uses the `bin` union field. Source location is implied to be the same /// as the previous instruction. @@ -675,14 +680,14 @@ pub const Inst = struct { /// This instruction asserts that there is at least one field_ptr instruction, /// because it must use one of them to find out the struct type. /// Uses the `pl_node` field. Payload is `Block`. - validate_struct_init_ptr, - /// Given a set of `elem_ptr_node` instructions, assumes they are all part of an + validate_struct_init, + /// Given a set of `elem_ptr_imm` instructions, assumes they are all part of an /// array initialization expression, and emits a compile error if the number of /// elements does not match the array type. - /// This instruction asserts that there is at least one elem_ptr_node instruction, + /// This instruction asserts that there is at least one `elem_ptr_imm` instruction, /// because it must use one of them to find out the array type. /// Uses the `pl_node` field. Payload is `Block`. - validate_array_init_ptr, + validate_array_init, /// A struct literal with a specified type, with no fields. /// Uses the `un_node` field. struct_init_empty, @@ -1023,6 +1028,7 @@ pub const Inst = struct { .elem_ptr, .elem_val, .elem_ptr_node, + .elem_ptr_imm, .elem_val_node, .ensure_result_used, .ensure_result_non_error, @@ -1114,8 +1120,8 @@ pub const Inst = struct { .switch_block_ref_else_multi, .switch_block_ref_under, .switch_block_ref_under_multi, - .validate_struct_init_ptr, - .validate_array_init_ptr, + .validate_struct_init, + .validate_array_init, .struct_init_empty, .struct_init, .struct_init_ref, @@ -1291,6 +1297,7 @@ pub const Inst = struct { .div = .pl_node, .elem_ptr = .bin, .elem_ptr_node = .pl_node, + .elem_ptr_imm = .pl_node, .elem_val = .bin, .elem_val_node = .pl_node, .ensure_result_used = .un_node, @@ -1377,8 +1384,8 @@ pub const Inst = struct { .switch_capture_multi_ref = .switch_capture, .switch_capture_else = .switch_capture, .switch_capture_else_ref = .switch_capture, - .validate_struct_init_ptr = .pl_node, - .validate_array_init_ptr = .pl_node, + .validate_struct_init = .pl_node, + .validate_array_init = .pl_node, .struct_init_empty = .un_node, .field_type = .pl_node, .field_type_ref = .pl_node, @@ -2459,6 +2466,11 @@ pub const Inst = struct { operand: Ref, }; + pub const ElemPtrImm = struct { + ptr: Ref, + index: u32, + }; + /// This form is supported when there are no ranges, and exactly 1 item per block. /// Depending on zir tag and len fields, extra fields trail /// this one in the extra array. diff --git a/src/print_zir.zig b/src/print_zir.zig index b0805e8f00..14f64aec2d 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -355,6 +355,8 @@ const Writer = struct { .elem_val_node, => try self.writePlNodeBin(stream, inst), + .elem_ptr_imm => try self.writeElemPtrImm(stream, inst), + .@"export" => try self.writePlNodeExport(stream, inst), .export_value => try self.writePlNodeExportValue(stream, inst), @@ -364,8 +366,8 @@ const Writer = struct { .block_inline, .suspend_block, .loop, - .validate_struct_init_ptr, - .validate_array_init_ptr, + .validate_struct_init, + .validate_array_init, .c_import, => try self.writePlNodeBlock(stream, inst), @@ -809,6 +811,15 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } + fn writeElemPtrImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data; + + try self.writeInstRef(stream, extra.ptr); + try stream.print(", {d}) ", .{extra.index}); + try self.writeSrc(stream, inst_data.src()); + } + fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; |
