AstGen: finish multi-object for loops
This strategy uses pointer arithmetic to iterate through the loop. This has a problem, however, which is tuples. AstGen does not know whether a given indexable is a tuple or can be iterated based on contiguous memory. Tuples unlike other indexables cannot be represented as a many-item pointer that is incremented as the loop counter. So, after this commit, I will modify AstGen back closer to how @vexu had it before, using a counter and array element access.
This commit is contained in:
135
src/AstGen.zig
135
src/AstGen.zig
@@ -88,6 +88,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
|
||||
Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.FuncFancy.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
Zir.Inst.ElemPtrImm.Bits => @bitCast(u32, @field(extra, field.name)),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
@@ -1565,7 +1566,9 @@ fn arrayInitExprRlPtrInner(
|
||||
for (elements) |elem_init, i| {
|
||||
const elem_ptr = try gz.addPlNode(.elem_ptr_imm, elem_init, Zir.Inst.ElemPtrImm{
|
||||
.ptr = result_ptr,
|
||||
.index = @intCast(u32, i),
|
||||
.bits = .{
|
||||
.index = @intCast(u31, i),
|
||||
},
|
||||
});
|
||||
astgen.extra.items[extra_index] = refToIndex(elem_ptr).?;
|
||||
extra_index += 1;
|
||||
@@ -6308,7 +6311,7 @@ fn forExpr(
|
||||
const lens = try gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len);
|
||||
defer gpa.free(lens);
|
||||
|
||||
const counter_alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc;
|
||||
const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc_mut;
|
||||
|
||||
// Tracks the index of allocs/lens that has a length to be checked and is
|
||||
// used for the end value.
|
||||
@@ -6321,23 +6324,24 @@ fn forExpr(
|
||||
var cond_end_val: Zir.Inst.Ref = .none;
|
||||
|
||||
{
|
||||
var payload = for_full.payload_token;
|
||||
var capture_token = for_full.payload_token;
|
||||
for (for_full.ast.inputs) |input, i_usize| {
|
||||
const i = @intCast(u32, i_usize);
|
||||
const payload_is_ref = token_tags[payload] == .asterisk;
|
||||
const ident_tok = payload + @boolToInt(payload_is_ref);
|
||||
const capture_is_ref = token_tags[capture_token] == .asterisk;
|
||||
const ident_tok = capture_token + @boolToInt(capture_is_ref);
|
||||
|
||||
if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and payload_is_ref) {
|
||||
return astgen.failTok(payload, "pointer modifier invalid on discard", .{});
|
||||
if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and capture_is_ref) {
|
||||
return astgen.failTok(capture_token, "pointer modifier invalid on discard", .{});
|
||||
}
|
||||
payload = ident_tok + @as(u32, 2);
|
||||
// Skip over the comma, and on to the next capture (or the ending pipe character).
|
||||
capture_token = ident_tok + 2;
|
||||
|
||||
try emitDbgNode(parent_gz, input);
|
||||
if (node_tags[input] == .for_range) {
|
||||
if (payload_is_ref) {
|
||||
if (capture_is_ref) {
|
||||
return astgen.failTok(ident_tok, "cannot capture reference to range", .{});
|
||||
}
|
||||
const counter_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node);
|
||||
const counter_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node);
|
||||
const start_node = node_data[input].lhs;
|
||||
const start_val = try expr(parent_gz, scope, .{ .rl = .none }, start_node);
|
||||
_ = try parent_gz.addBin(.store, counter_ptr, start_val);
|
||||
@@ -6364,20 +6368,28 @@ fn forExpr(
|
||||
allocs[i] = counter_ptr;
|
||||
lens[i] = range_len;
|
||||
} else {
|
||||
const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
|
||||
const indexable = try expr(parent_gz, scope, cond_ri, input);
|
||||
const indexable = try expr(parent_gz, scope, .{ .rl = .none }, input);
|
||||
// This instruction has nice compile errors so we put it before the other ones
|
||||
// even though it is not needed until later in the block.
|
||||
const ptr_len = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input);
|
||||
const base_ptr = try parent_gz.addPlNode(.elem_ptr_imm, input, Zir.Inst.ElemPtrImm{
|
||||
.ptr = indexable,
|
||||
.index = 0,
|
||||
.bits = .{
|
||||
.index = 0,
|
||||
.manyptr = true,
|
||||
},
|
||||
});
|
||||
const alloc_ty_inst = try parent_gz.addUnNode(.typeof, base_ptr, node);
|
||||
const alloc = try parent_gz.addUnNode(alloc_tag, alloc_ty_inst, node);
|
||||
_ = try parent_gz.addBin(.store, alloc, base_ptr);
|
||||
|
||||
if (end_input_index == null) {
|
||||
end_input_index = i;
|
||||
assert(cond_end_val == .none);
|
||||
}
|
||||
|
||||
allocs[i] = base_ptr;
|
||||
lens[i] = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input);
|
||||
allocs[i] = alloc;
|
||||
lens[i] = ptr_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6467,62 +6479,47 @@ fn forExpr(
|
||||
var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
|
||||
defer then_scope.unstack();
|
||||
|
||||
const then_sub_scope = &then_scope.base;
|
||||
try then_scope.addDbgBlockBegin();
|
||||
|
||||
// try then_scope.addDbgBlockBegin();
|
||||
// var payload_val_scope: Scope.LocalVal = undefined;
|
||||
// var index_scope: Scope.LocalPtr = undefined;
|
||||
// const then_sub_scope = blk: {
|
||||
// const payload_token = for_full.payload_token.?;
|
||||
// const ident = if (token_tags[payload_token] == .asterisk)
|
||||
// payload_token + 1
|
||||
// else
|
||||
// payload_token;
|
||||
// const is_ptr = ident != payload_token;
|
||||
// const value_name = tree.tokenSlice(ident);
|
||||
// var payload_sub_scope: *Scope = undefined;
|
||||
// if (!mem.eql(u8, value_name, "_")) {
|
||||
// const name_str_index = try astgen.identAsString(ident);
|
||||
// const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
|
||||
// const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{
|
||||
// .lhs = array_ptr,
|
||||
// .rhs = index,
|
||||
// });
|
||||
// try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture);
|
||||
// payload_val_scope = .{
|
||||
// .parent = &then_scope.base,
|
||||
// .gen_zir = &then_scope,
|
||||
// .name = name_str_index,
|
||||
// .inst = payload_inst,
|
||||
// .token_src = ident,
|
||||
// .id_cat = .capture,
|
||||
// };
|
||||
// try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);
|
||||
// payload_sub_scope = &payload_val_scope.base;
|
||||
// } else if (is_ptr) {
|
||||
// } else {
|
||||
// payload_sub_scope = &then_scope.base;
|
||||
// }
|
||||
const capture_scopes = try gpa.alloc(Scope.LocalVal, for_full.ast.inputs.len);
|
||||
defer gpa.free(capture_scopes);
|
||||
|
||||
// const index_token = if (token_tags[ident + 1] == .comma)
|
||||
// ident + 2
|
||||
// else
|
||||
// break :blk payload_sub_scope;
|
||||
// const token_bytes = tree.tokenSlice(index_token);
|
||||
// const index_name = try astgen.identAsString(index_token);
|
||||
// try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");
|
||||
// index_scope = .{
|
||||
// .parent = payload_sub_scope,
|
||||
// .gen_zir = &then_scope,
|
||||
// .name = index_name,
|
||||
// .ptr = index_ptr,
|
||||
// .token_src = index_token,
|
||||
// .maybe_comptime = is_inline,
|
||||
// .id_cat = .@"loop index capture",
|
||||
// };
|
||||
// try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);
|
||||
// break :blk &index_scope.base;
|
||||
// };
|
||||
const then_sub_scope = blk: {
|
||||
var capture_token = for_full.payload_token;
|
||||
var capture_sub_scope: *Scope = &then_scope.base;
|
||||
for (for_full.ast.inputs) |input, i_usize| {
|
||||
const i = @intCast(u32, i_usize);
|
||||
const capture_is_ref = token_tags[capture_token] == .asterisk;
|
||||
const ident_tok = capture_token + @boolToInt(capture_is_ref);
|
||||
const capture_name = tree.tokenSlice(ident_tok);
|
||||
// Skip over the comma, and on to the next capture (or the ending pipe character).
|
||||
capture_token = ident_tok + 2;
|
||||
|
||||
if (mem.eql(u8, capture_name, "_")) continue;
|
||||
|
||||
const name_str_index = try astgen.identAsString(ident_tok);
|
||||
try astgen.detectLocalShadowing(capture_sub_scope, name_str_index, ident_tok, capture_name, .capture);
|
||||
|
||||
const loaded = if (capture_is_ref)
|
||||
loaded_ptrs[i]
|
||||
else
|
||||
try then_scope.addUnNode(.load, loaded_ptrs[i], input);
|
||||
|
||||
capture_scopes[i] = .{
|
||||
.parent = capture_sub_scope,
|
||||
.gen_zir = &then_scope,
|
||||
.name = name_str_index,
|
||||
.inst = loaded,
|
||||
.token_src = ident_tok,
|
||||
.id_cat = .capture,
|
||||
};
|
||||
|
||||
try then_scope.addDbgVar(.dbg_var_val, name_str_index, loaded);
|
||||
capture_sub_scope = &capture_scopes[i].base;
|
||||
}
|
||||
|
||||
break :blk capture_sub_scope;
|
||||
};
|
||||
|
||||
const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr);
|
||||
_ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr);
|
||||
|
||||
37
src/Sema.zig
37
src/Sema.zig
@@ -9649,7 +9649,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
const array_ptr = try sema.resolveInst(extra.lhs);
|
||||
const elem_index = try sema.resolveInst(extra.rhs);
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, src, false);
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, src, false, .One);
|
||||
}
|
||||
|
||||
fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
@@ -9662,7 +9662,7 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
||||
const array_ptr = try sema.resolveInst(extra.lhs);
|
||||
const elem_index = try sema.resolveInst(extra.rhs);
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false);
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, .One);
|
||||
}
|
||||
|
||||
fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
@@ -9673,8 +9673,9 @@ fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
|
||||
const src = inst_data.src();
|
||||
const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
|
||||
const array_ptr = try sema.resolveInst(extra.ptr);
|
||||
const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, src, true);
|
||||
const elem_index = try sema.addIntUnsigned(Type.usize, extra.bits.index);
|
||||
const size: std.builtin.Type.Pointer.Size = if (extra.bits.manyptr) .Many else .One;
|
||||
return sema.elemPtr(block, src, array_ptr, elem_index, src, true, size);
|
||||
}
|
||||
|
||||
fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
@@ -22905,7 +22906,7 @@ fn panicSentinelMismatch(
|
||||
const actual_sentinel = if (ptr_ty.isSlice())
|
||||
try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
|
||||
else blk: {
|
||||
const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
|
||||
const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null, .One);
|
||||
const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
|
||||
break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
|
||||
};
|
||||
@@ -24072,6 +24073,7 @@ fn elemPtr(
|
||||
elem_index: Air.Inst.Ref,
|
||||
elem_index_src: LazySrcLoc,
|
||||
init: bool,
|
||||
size: std.builtin.Type.Pointer.Size,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const indexable_ptr_src = src; // TODO better source location
|
||||
const indexable_ptr_ty = sema.typeOf(indexable_ptr);
|
||||
@@ -24098,13 +24100,12 @@ fn elemPtr(
|
||||
const index_val = maybe_index_val orelse break :rs elem_index_src;
|
||||
const index = @intCast(usize, index_val.toUnsignedInt(target));
|
||||
const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
|
||||
const result_ty = try sema.elemPtrType(indexable_ty, index);
|
||||
return sema.addConstant(result_ty, elem_ptr);
|
||||
const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index, size);
|
||||
return sema.addConstant(elem_ptr_ty, elem_ptr);
|
||||
};
|
||||
const result_ty = try sema.elemPtrType(indexable_ty, null);
|
||||
|
||||
const elem_ptr_ty = try sema.elemPtrType(indexable_ty, null, size);
|
||||
try sema.requireRuntimeBlock(block, src, runtime_src);
|
||||
return block.addPtrElemPtr(indexable, elem_index, result_ty);
|
||||
return block.addPtrElemPtr(indexable, elem_index, elem_ptr_ty);
|
||||
},
|
||||
.One => {
|
||||
assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
|
||||
@@ -24166,7 +24167,7 @@ fn elemVal(
|
||||
},
|
||||
.One => {
|
||||
assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
|
||||
const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false);
|
||||
const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, .One);
|
||||
return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
|
||||
},
|
||||
},
|
||||
@@ -24404,7 +24405,7 @@ fn elemPtrArray(
|
||||
break :o index;
|
||||
} else null;
|
||||
|
||||
const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset);
|
||||
const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset, .One);
|
||||
|
||||
if (maybe_undef_array_ptr_val) |array_ptr_val| {
|
||||
if (array_ptr_val.isUndef()) {
|
||||
@@ -24509,7 +24510,7 @@ fn elemPtrSlice(
|
||||
break :o index;
|
||||
} else null;
|
||||
|
||||
const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
|
||||
const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset, .One);
|
||||
|
||||
if (maybe_undef_slice_val) |slice_val| {
|
||||
if (slice_val.isUndef()) {
|
||||
@@ -26239,7 +26240,7 @@ fn storePtr2(
|
||||
const elem_src = operand_src; // TODO better source location
|
||||
const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
|
||||
const elem_index = try sema.addIntUnsigned(Type.usize, i);
|
||||
const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false);
|
||||
const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, .One);
|
||||
try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
|
||||
}
|
||||
return;
|
||||
@@ -33276,7 +33277,12 @@ fn compareVector(
|
||||
/// For []T, returns *T
|
||||
/// Handles const-ness and address spaces in particular.
|
||||
/// This code is duplicated in `analyzePtrArithmetic`.
|
||||
fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
|
||||
fn elemPtrType(
|
||||
sema: *Sema,
|
||||
ptr_ty: Type,
|
||||
offset: ?usize,
|
||||
size: std.builtin.Type.Pointer.Size,
|
||||
) !Type {
|
||||
const ptr_info = ptr_ty.ptrInfo().data;
|
||||
const elem_ty = ptr_ty.elemType2();
|
||||
const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;
|
||||
@@ -33321,6 +33327,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
|
||||
break :a new_align;
|
||||
};
|
||||
return try Type.ptr(sema.arena, sema.mod, .{
|
||||
.size = size,
|
||||
.pointee_type = elem_ty,
|
||||
.mutable = ptr_info.mutable,
|
||||
.@"addrspace" = ptr_info.@"addrspace",
|
||||
|
||||
11
src/Zir.zig
11
src/Zir.zig
@@ -79,6 +79,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en
|
||||
Inst.BuiltinCall.Flags => @bitCast(Inst.BuiltinCall.Flags, code.extra[i]),
|
||||
Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]),
|
||||
Inst.FuncFancy.Bits => @bitCast(Inst.FuncFancy.Bits, code.extra[i]),
|
||||
Inst.ElemPtrImm.Bits => @bitCast(Inst.ElemPtrImm.Bits, code.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
@@ -388,6 +389,8 @@ pub const Inst = struct {
|
||||
/// 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`.
|
||||
/// This instruction has a way to set the result type to be a
|
||||
/// single-pointer or a many-pointer.
|
||||
elem_ptr_imm,
|
||||
/// Given an array, slice, or pointer, returns the element at the provided index.
|
||||
/// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
|
||||
@@ -2972,7 +2975,13 @@ pub const Inst = struct {
|
||||
|
||||
pub const ElemPtrImm = struct {
|
||||
ptr: Ref,
|
||||
index: u32,
|
||||
bits: Bits,
|
||||
|
||||
pub const Bits = packed struct(u32) {
|
||||
index: u31,
|
||||
/// Controls whether the type returned is `*T` or `[*]T`.
|
||||
manyptr: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
/// 0. multi_cases_len: u32 // If has_multi_cases is set.
|
||||
|
||||
@@ -888,7 +888,9 @@ const Writer = struct {
|
||||
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 stream.print(", {d}", .{extra.bits.index});
|
||||
try self.writeFlag(stream, ", manyptr", extra.bits.manyptr);
|
||||
try stream.writeAll(") ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user