mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
AstGen: add result location analysis pass
The main motivation for this change is eliminating the `block_ptr` result location and corresponding `store_to_block_ptr` ZIR instruction. This is achieved through a simple pass over the AST before AstGen which determines, for AST nodes which have a choice on whether to provide a result location, which choice to make, based on whether the result pointer is consumed non-trivially. This eliminates so much logic from AstGen that we almost break even on line count! AstGen no longer has to worry about instruction rewriting based on whether or not a result location was consumed: it always knows what to do ahead of time, which simplifies a *lot* of logic. This also incidentally fixes a few random AstGen bugs related to result location handling, leading to the changes in `test/` and `lib/std/`. This opens the door to future RLS improvements by making them much easier to implement correctly, and fixes many bugs. Most ZIR is made more compact after this commit, mainly due to not having redundant `store_to_block_ptr` instructions lying around, but also due to a few bugs in the old system which are implicitly fixed here.
This commit is contained in:
parent
020105d0dd
commit
321961d860
9 changed files with 1347 additions and 1149 deletions
|
|
@ -515,6 +515,7 @@ set(ZIG_STAGE2_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Air.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/AstRlAnnotate.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/Module.zig"
|
||||
|
|
|
|||
|
|
@ -370,10 +370,9 @@ fn render_cmake(
|
|||
}
|
||||
},
|
||||
|
||||
else => {
|
||||
break :blk value;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
break :blk value;
|
||||
};
|
||||
|
||||
if (booldefine) {
|
||||
|
|
|
|||
1348
src/AstGen.zig
1348
src/AstGen.zig
File diff suppressed because it is too large
Load diff
1086
src/AstRlAnnotate.zig
Normal file
1086
src/AstRlAnnotate.zig
Normal file
File diff suppressed because it is too large
Load diff
34
src/Sema.zig
34
src/Sema.zig
|
|
@ -1346,11 +1346,6 @@ fn analyzeBodyInner(
|
|||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store_to_block_ptr => {
|
||||
try sema.zirStoreToBlockPtr(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.store_to_inferred_ptr => {
|
||||
try sema.zirStoreToInferredPtr(block, inst);
|
||||
i += 1;
|
||||
|
|
@ -5269,35 +5264,6 @@ fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !vo
|
|||
try mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category});
|
||||
}
|
||||
|
||||
fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const bin_inst = sema.code.instructions.items(.data)[inst].bin;
|
||||
const ptr = sema.inst_map.get(Zir.refToIndex(bin_inst.lhs).?) orelse {
|
||||
// This is an elided instruction, but AstGen was unable to omit it.
|
||||
return;
|
||||
};
|
||||
const operand = try sema.resolveInst(bin_inst.rhs);
|
||||
const src: LazySrcLoc = sema.src;
|
||||
blk: {
|
||||
const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
|
||||
switch (sema.air_instructions.items(.tag)[ptr_inst]) {
|
||||
.inferred_alloc_comptime => {
|
||||
const iac = &sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime;
|
||||
return sema.storeToInferredAllocComptime(block, src, operand, iac);
|
||||
},
|
||||
.inferred_alloc => {
|
||||
const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
|
||||
return sema.storeToInferredAlloc(block, ptr, operand, ia);
|
||||
},
|
||||
else => break :blk,
|
||||
}
|
||||
}
|
||||
|
||||
return sema.storePtr(block, src, ptr, operand);
|
||||
}
|
||||
|
||||
fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
|
|
|||
16
src/Zir.zig
16
src/Zir.zig
|
|
@ -602,20 +602,9 @@ pub const Inst = struct {
|
|||
/// Same as `store` except provides a source location.
|
||||
/// Uses the `pl_node` union field. Payload is `Bin`.
|
||||
store_node,
|
||||
/// This instruction is not really supposed to be emitted from AstGen; nevertheless it
|
||||
/// is sometimes emitted due to deficiencies in AstGen. When Sema sees this instruction,
|
||||
/// it must clean up after AstGen's mess by looking at various context clues and
|
||||
/// then treating it as one of the following:
|
||||
/// * no-op
|
||||
/// * store_to_inferred_ptr
|
||||
/// * store
|
||||
/// Uses the `bin` union field with LHS as the pointer to store to.
|
||||
store_to_block_ptr,
|
||||
/// Same as `store` but the type of the value being stored will be used to infer
|
||||
/// the pointer type.
|
||||
/// Uses the `bin` union field - Astgen.zig depends on the ability to change
|
||||
/// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr`
|
||||
/// without changing the data.
|
||||
/// Uses the `bin` union field.
|
||||
store_to_inferred_ptr,
|
||||
/// String Literal. Makes an anonymous Decl and then takes a pointer to it.
|
||||
/// Uses the `str` union field.
|
||||
|
|
@ -1109,7 +1098,6 @@ pub const Inst = struct {
|
|||
.shr,
|
||||
.store,
|
||||
.store_node,
|
||||
.store_to_block_ptr,
|
||||
.store_to_inferred_ptr,
|
||||
.str,
|
||||
.sub,
|
||||
|
|
@ -1295,7 +1283,6 @@ pub const Inst = struct {
|
|||
.atomic_store,
|
||||
.store,
|
||||
.store_node,
|
||||
.store_to_block_ptr,
|
||||
.store_to_inferred_ptr,
|
||||
.resolve_inferred_alloc,
|
||||
.validate_array_init_ty,
|
||||
|
|
@ -1667,7 +1654,6 @@ pub const Inst = struct {
|
|||
.slice_length = .pl_node,
|
||||
.store = .bin,
|
||||
.store_node = .pl_node,
|
||||
.store_to_block_ptr = .bin,
|
||||
.store_to_inferred_ptr = .bin,
|
||||
.str = .str,
|
||||
.negate = .un_node,
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ const Writer = struct {
|
|||
switch (tag) {
|
||||
.as,
|
||||
.store,
|
||||
.store_to_block_ptr,
|
||||
.store_to_inferred_ptr,
|
||||
=> try self.writeBin(stream, inst),
|
||||
|
||||
|
|
|
|||
|
|
@ -29,4 +29,4 @@ export fn f4() void {
|
|||
// :2:22: error: expected type 'usize', found 'void'
|
||||
// :7:9: error: expected type 'usize', found 'void'
|
||||
// :14:9: error: expected type 'usize', found 'void'
|
||||
// :19:27: error: expected type 'usize', found 'void'
|
||||
// :20:9: error: expected type 'usize', found 'void'
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ export fn entry() void {
|
|||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:20: error: incompatible types: 'i32' and 'void'
|
||||
// :2:30: note: type 'i32' here
|
||||
// :2:20: error: expected type 'i32', found 'void'
|
||||
// :8:15: error: incompatible types: 'i32' and 'void'
|
||||
// :8:25: note: type 'i32' here
|
||||
// :16:16: error: expected type 'tmp.h.T', found 'void'
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue