aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Sema.zig67
1 files changed, 61 insertions, 6 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index d4c49973a1..42b43d656f 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -2711,17 +2711,72 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const ptr = try sema.resolveInst(inst_data.operand);
- const ptr_ty = sema.typeOf(ptr);
- var ptr_info = ptr_ty.ptrInfo().data;
+ const src = inst_data.src();
+ const alloc = try sema.resolveInst(inst_data.operand);
+ const alloc_ty = sema.typeOf(alloc);
+
+ var ptr_info = alloc_ty.ptrInfo().data;
+ const elem_ty = ptr_info.pointee_type;
+
+ // Detect if all stores to an `.alloc` were comptime known.
+ ct: {
+ var search_index: usize = block.instructions.items.len;
+ const air_tags = sema.air_instructions.items(.tag);
+ const air_datas = sema.air_instructions.items(.data);
+
+ const store_inst = while (true) {
+ if (search_index == 0) break :ct;
+ search_index -= 1;
+
+ const candidate = block.instructions.items[search_index];
+ switch (air_tags[candidate]) {
+ .dbg_stmt => continue,
+ .store => break candidate,
+ else => break :ct,
+ }
+ } else unreachable; // TODO shouldn't need this
+
+ while (true) {
+ if (search_index == 0) break :ct;
+ search_index -= 1;
+
+ const candidate = block.instructions.items[search_index];
+ switch (air_tags[candidate]) {
+ .dbg_stmt => continue,
+ .alloc => {
+ if (Air.indexToRef(candidate) != alloc) break :ct;
+ break;
+ },
+ else => break :ct,
+ }
+ }
+
+ const store_op = air_datas[store_inst].bin_op;
+ const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct;
+ if (store_op.lhs != alloc) break :ct;
+
+ // Remove all the unnecessary runtime instructions.
+ block.instructions.shrinkRetainingCapacity(search_index);
+
+ var anon_decl = try block.startAnonDecl(src);
+ defer anon_decl.deinit();
+ return sema.analyzeDeclRef(try anon_decl.finish(
+ try elem_ty.copy(anon_decl.arena()),
+ try store_val.copy(anon_decl.arena()),
+ ptr_info.@"align",
+ ));
+ }
+
ptr_info.mutable = false;
const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
- if (try sema.resolveMaybeUndefVal(block, inst_data.src(), ptr)) |val| {
+ // Detect if a comptime value simply needs to have its type changed.
+ if (try sema.resolveMaybeUndefVal(block, inst_data.src(), alloc)) |val| {
return sema.addConstant(const_ptr_ty, val);
}
- try sema.requireRuntimeBlock(block, inst_data.src());
- return block.addBitCast(const_ptr_ty, ptr);
+
+ try sema.requireRuntimeBlock(block, src);
+ return block.addBitCast(const_ptr_ty, alloc);
}
fn zirAllocInferredComptime(