Commit b9c5a1fdf5
Changed files (5)
src/astgen.zig
@@ -443,7 +443,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
.deref => {
const lhs = try expr(mod, scope, .none, node_datas[node].lhs);
- const result = try gz.addUnNode(.deref_node, lhs, node);
+ const result = try gz.addUnNode(.load, lhs, node);
return rvalue(mod, scope, rl, result, node);
},
.address_of => {
@@ -1042,7 +1042,7 @@ fn blockExprStmts(
.coerce_result_ptr,
.decl_ref,
.decl_val,
- .deref_node,
+ .load,
.div,
.elem_ptr,
.elem_val,
@@ -1396,7 +1396,7 @@ fn assignOp(
const gz = scope.getGenZir();
const lhs_ptr = try lvalExpr(mod, scope, node_datas[infix_node].lhs);
- const lhs = try gz.addUnNode(.deref_node, lhs_ptr, infix_node);
+ const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
const lhs_type = try gz.addUnTok(.typeof, lhs, infix_node);
const rhs = try expr(mod, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs);
@@ -2105,7 +2105,7 @@ fn whileExpr(
try checkLabelRedefinition(mod, scope, label_token);
}
const parent_gz = scope.getGenZir();
- const is_inline = while_full.inline_token != null;
+ const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop;
const loop_block = try parent_gz.addBlock(loop_tag, node);
try parent_gz.instructions.append(mod.gpa, loop_block);
@@ -2149,7 +2149,6 @@ fn whileExpr(
// TODO avoid emitting the continue expr when there
// are no jumps to it. This happens when the last statement of a while body is noreturn
// and there are no `continue` statements.
- // The "repeat" at the end of a loop body is implied.
if (while_full.ast.cont_expr != 0) {
_ = try expr(mod, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr);
}
@@ -2236,44 +2235,32 @@ fn forExpr(
node: ast.Node.Index,
for_full: ast.full.While,
) InnerError!zir.Inst.Ref {
- if (true) @panic("TODO update for zir-memory-layout");
if (for_full.label_token) |label_token| {
try checkLabelRedefinition(mod, scope, label_token);
}
-
- if (for_full.inline_token) |inline_token| {
- return mod.failTok(scope, inline_token, "TODO inline for", .{});
- }
-
// Set up variables and constants.
const parent_gz = scope.getGenZir();
+ const is_inline = parent_gz.force_comptime or for_full.inline_token != null;
const tree = parent_gz.tree();
- const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
- const for_src = token_starts[for_full.ast.while_token];
+ const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr);
+ const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
+
const index_ptr = blk: {
- const usize_type = try addZIRInstConst(mod, scope, for_src, .{
- .ty = Type.initTag(.type),
- .val = Value.initTag(.usize_type),
- });
- const index_ptr = try addZIRUnOp(mod, scope, for_src, .alloc, usize_type);
+ const index_ptr = try parent_gz.addUnNode(.alloc, .usize_type, node);
// initialize to zero
- const zero = try addZIRInstConst(mod, scope, for_src, .{
- .ty = Type.initTag(.usize),
- .val = Value.initTag(.zero),
- });
- _ = try addZIRBinOp(mod, scope, for_src, .store, index_ptr, zero);
+ _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);
break :blk index_ptr;
};
- const array_ptr = try expr(mod, scope, .ref, for_full.ast.cond_expr);
- const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
- const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
+
+ const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop;
+ const loop_block = try parent_gz.addBlock(loop_tag, node);
+ try parent_gz.instructions.append(mod.gpa, loop_block);
var loop_scope: Scope.GenZir = .{
.parent = scope,
- .decl = scope.ownerDecl().?,
- .arena = scope.arena(),
+ .zir_code = parent_gz.zir_code,
.force_comptime = parent_gz.force_comptime,
.instructions = .{},
};
@@ -2282,66 +2269,49 @@ fn forExpr(
var cond_scope: Scope.GenZir = .{
.parent = &loop_scope.base,
- .decl = loop_scope.decl,
- .arena = loop_scope.arena,
+ .zir_code = parent_gz.zir_code,
.force_comptime = loop_scope.force_comptime,
.instructions = .{},
};
defer cond_scope.instructions.deinit(mod.gpa);
// check condition i < array_expr.len
- const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr);
- const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len);
-
- const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{
- .condition = cond,
- .then_body = undefined, // populated below
- .else_body = undefined, // populated below
- }, .{});
- const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .block, .{
- .instructions = try loop_scope.arena.dupe(zir.Inst.Ref, cond_scope.instructions.items),
+ const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
+ const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, zir.Inst.Bin{
+ .lhs = index,
+ .rhs = len,
});
- // increment index variable
- const one = try addZIRInstConst(mod, &loop_scope.base, for_src, .{
- .ty = Type.initTag(.usize),
- .val = Value.initTag(.one),
- });
- const index_2 = try addZIRUnOp(mod, &loop_scope.base, cond_src, .deref, index_ptr);
- const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one);
- _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one);
-
- const loop = try scope.arena().create(zir.Inst.Loop);
- loop.* = .{
- .base = .{
- .tag = .loop,
- .src = for_src,
- },
- .positionals = .{
- .body = .{
- .instructions = try scope.arena().dupe(zir.Inst.Ref, loop_scope.instructions.items),
- },
- },
- .kw_args = .{},
- };
- const for_block = try addZIRInstBlock(mod, scope, for_src, .block, .{
- .instructions = try scope.arena().dupe(zir.Inst.Ref, &[1]zir.Inst.Ref{&loop.base}),
+ const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
+ const condbr = try cond_scope.addCondBr(condbr_tag, node);
+ const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block;
+ const cond_block = try loop_scope.addBlock(block_tag, node);
+ try loop_scope.instructions.append(mod.gpa, cond_block);
+ try cond_scope.setBlockBody(cond_block);
+
+ // Increment the index variable.
+ const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
+ const index_plus_one = try loop_scope.addPlNode(.add, node, zir.Inst.Bin{
+ .lhs = index_2,
+ .rhs = .one_usize,
});
- loop_scope.break_block = for_block;
+ _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
+ const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
+ _ = try loop_scope.addNode(repeat_tag, node);
+
+ try loop_scope.setBlockBody(loop_block);
+ loop_scope.break_block = loop_block;
loop_scope.continue_block = cond_block;
if (for_full.label_token) |label_token| {
loop_scope.label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{
.token = label_token,
- .block_inst = for_block,
+ .block_inst = loop_block,
});
}
- // while body
- const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];
var then_scope: Scope.GenZir = .{
.parent = &cond_scope.base,
- .decl = cond_scope.decl,
- .arena = cond_scope.arena,
+ .zir_code = parent_gz.zir_code,
.force_comptime = cond_scope.force_comptime,
.instructions = .{},
};
@@ -2375,6 +2345,7 @@ fn forExpr(
.gen_zir = &then_scope,
.name = index_name,
.ptr = index_ptr,
+ .src = parent_gz.tokSrcLoc(index_token),
};
break :blk &index_scope.base;
};
@@ -2382,34 +2353,36 @@ fn forExpr(
loop_scope.break_count += 1;
const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
- // else branch
var else_scope: Scope.GenZir = .{
.parent = &cond_scope.base,
- .decl = cond_scope.decl,
- .arena = cond_scope.arena,
+ .zir_code = parent_gz.zir_code,
.force_comptime = cond_scope.force_comptime,
.instructions = .{},
};
defer else_scope.instructions.deinit(mod.gpa);
const else_node = for_full.ast.else_expr;
- const else_info: struct { src: usize, result: ?*zir.Inst } = if (else_node != 0) blk: {
+ const else_info: struct {
+ src: ast.Node.Index,
+ result: zir.Inst.Ref,
+ } = if (else_node != 0) blk: {
loop_scope.break_count += 1;
const sub_scope = &else_scope.base;
break :blk .{
- .src = token_starts[tree.lastToken(else_node)],
+ .src = else_node,
.result = try expr(mod, sub_scope, loop_scope.break_result_loc, else_node),
};
} else .{
- .src = token_starts[tree.lastToken(for_full.ast.then_expr)],
- .result = null,
+ .src = for_full.ast.then_expr,
+ .result = .none,
};
if (loop_scope.label) |some| {
if (!some.used) {
- return mod.fail(scope, token_starts[some.token], "unused for loop label", .{});
+ return mod.failTok(scope, some.token, "unused for loop label", .{});
}
}
+ const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
return finishThenElseBlock(
mod,
scope,
@@ -2420,13 +2393,13 @@ fn forExpr(
&else_scope,
condbr,
cond,
- then_src,
+ for_full.ast.then_expr,
else_info.src,
then_result,
else_info.result,
- for_block,
+ loop_block,
cond_block,
- .@"break",
+ break_tag,
);
}
@@ -2862,7 +2835,7 @@ fn identifier(
const local_ptr = s.cast(Scope.LocalPtr).?;
if (mem.eql(u8, local_ptr.name, ident_name)) {
if (rl == .ref) return local_ptr.ptr;
- const loaded = try gz.addUnNode(.deref_node, local_ptr.ptr, ident);
+ const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
return rvalue(mod, scope, rl, loaded, ident);
}
s = local_ptr.parent;
src/Sema.zig
@@ -160,7 +160,7 @@ pub fn analyzeBody(
.@"const" => try sema.zirConst(block, inst),
.decl_ref => try sema.zirDeclRef(block, inst),
.decl_val => try sema.zirDeclVal(block, inst),
- .deref_node => try sema.zirDerefNode(block, inst),
+ .load => try sema.zirLoad(block, inst),
.div => try sema.zirArithmetic(block, inst),
.elem_ptr => try sema.zirElemPtr(block, inst),
.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
@@ -576,7 +576,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
}
const result_ptr = try sema.namedFieldPtr(block, src, array_ptr, "len", src);
- return sema.analyzeDeref(block, src, result_ptr, result_ptr.src);
+ return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
}
fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -1911,7 +1911,7 @@ fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro
const object = try sema.resolveInst(extra.lhs);
const object_ptr = try sema.analyzeRef(block, src, object);
const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
- return sema.analyzeDeref(block, src, result_ptr, result_ptr.src);
+ return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
}
fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -1939,7 +1939,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inne
const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
const object_ptr = try sema.analyzeRef(block, src, object);
const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
- return sema.analyzeDeref(block, src, result_ptr, src);
+ return sema.analyzeLoad(block, src, result_ptr, src);
}
fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -2060,7 +2060,7 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
const array_ptr = try sema.analyzeRef(block, sema.src, array);
const elem_index = try sema.resolveInst(bin_inst.rhs);
const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
- return sema.analyzeDeref(block, sema.src, result_ptr, sema.src);
+ return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);
}
fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -2075,7 +2075,7 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
const array_ptr = try sema.analyzeRef(block, src, array);
const elem_index = try sema.resolveInst(extra.rhs);
const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
- return sema.analyzeDeref(block, src, result_ptr, src);
+ return sema.analyzeLoad(block, src, result_ptr, src);
}
fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -2183,7 +2183,7 @@ fn zirSwitchBr(
const target_ptr = try sema.resolveInst(inst.positionals.target);
const target = if (ref)
- try sema.analyzeDeref(parent_block, inst.base.src, target_ptr, inst.positionals.target.src)
+ try sema.analyzeLoad(parent_block, inst.base.src, target_ptr, inst.positionals.target.src)
else
target_ptr;
try sema.validateSwitch(parent_block, target, inst);
@@ -2639,7 +2639,7 @@ fn analyzeArithmetic(
return block.addBinOp(src, scalar_type, ir_tag, casted_lhs, casted_rhs);
}
-fn zirDerefNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
+fn zirLoad(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -2647,7 +2647,7 @@ fn zirDerefNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErr
const src = inst_data.src();
const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
const ptr = try sema.resolveInst(inst_data.operand);
- return sema.analyzeDeref(block, src, ptr, ptr_src);
+ return sema.analyzeLoad(block, src, ptr, ptr_src);
}
fn zirAsm(
@@ -2958,7 +2958,7 @@ fn zirIsNullPtr(
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
- const loaded = try sema.analyzeDeref(block, src, ptr, src);
+ const loaded = try sema.analyzeLoad(block, src, ptr, src);
return sema.analyzeIsNull(block, src, loaded, invert_logic);
}
@@ -2978,7 +2978,7 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
- const loaded = try sema.analyzeDeref(block, src, ptr, src);
+ const loaded = try sema.analyzeLoad(block, src, ptr, src);
return sema.analyzeIsErr(block, src, loaded);
}
@@ -3343,7 +3343,7 @@ fn namedFieldPtr(
},
.Type => {
_ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
- const result = try sema.analyzeDeref(block, src, object_ptr, object_ptr.src);
+ const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
const val = result.value().?;
const child_type = try val.toType(sema.arena);
switch (child_type.zigTypeTag()) {
@@ -3409,7 +3409,7 @@ fn elemPtr(
if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
// we have to deref the ptr operand to get the actual array pointer
- const array_ptr_deref = try sema.analyzeDeref(block, src, array_ptr, array_ptr.src);
+ const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
if (array_ptr_deref.value()) |array_ptr_val| {
if (elem_index.value()) |index_val| {
// Both array pointer and index are compile-time known.
@@ -3669,7 +3669,7 @@ fn coerceArrayPtrToMany(sema: *Sema, block: *Scope.Block, dest_type: Type, inst:
fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
const decl_ref = try sema.analyzeDeclRef(block, src, decl);
- return sema.analyzeDeref(block, src, decl_ref, src);
+ return sema.analyzeLoad(block, src, decl_ref, src);
}
fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
@@ -3737,7 +3737,7 @@ fn analyzeRef(
return block.addUnOp(src, ptr_type, .ref, operand);
}
-fn analyzeDeref(
+fn analyzeLoad(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
src/zir.zig
@@ -281,7 +281,7 @@ pub const Inst = struct {
decl_val,
/// Load the value from a pointer. Assumes `x.*` syntax.
/// Uses `un_node` field. AST node is the `x.*` syntax.
- deref_node,
+ load,
/// Arithmetic division. Asserts no integer overflow.
/// Uses the `pl_node` union field. Payload is `Bin`.
div,
@@ -661,7 +661,7 @@ pub const Inst = struct {
.dbg_stmt_node,
.decl_ref,
.decl_val,
- .deref_node,
+ .load,
.div,
.elem_ptr,
.elem_val,
@@ -841,6 +841,10 @@ pub const Inst = struct {
bool_true,
/// `false`
bool_false,
+ /// `0` (usize)
+ zero_usize,
+ /// `1` (usize)
+ one_usize,
_,
@@ -1016,10 +1020,18 @@ pub const Inst = struct {
.ty = Type.initTag(.comptime_int),
.val = Value.initTag(.zero),
},
+ .zero_usize = .{
+ .ty = Type.initTag(.usize),
+ .val = Value.initTag(.zero),
+ },
.one = .{
.ty = Type.initTag(.comptime_int),
.val = Value.initTag(.one),
},
+ .one_usize = .{
+ .ty = Type.initTag(.usize),
+ .val = Value.initTag(.one),
+ },
.void_value = .{
.ty = Type.initTag(.void),
.val = Value.initTag(.void_value),
@@ -1377,7 +1389,7 @@ const Writer = struct {
.call_none,
.call_none_chkused,
.compile_error,
- .deref_node,
+ .load,
.ensure_result_used,
.ensure_result_non_error,
.import,
test/stage2/test.zig
@@ -968,37 +968,37 @@ pub fn addCases(ctx: *TestContext) !void {
);
// Basic for loop
- //case.addCompareOutput(
- // \\export fn _start() noreturn {
- // \\ for ("hello") |_| print();
- // \\
- // \\ exit();
- // \\}
- // \\
- // \\fn print() void {
- // \\ asm volatile ("syscall"
- // \\ :
- // \\ : [number] "{rax}" (1),
- // \\ [arg1] "{rdi}" (1),
- // \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
- // \\ [arg3] "{rdx}" (6)
- // \\ : "rcx", "r11", "memory"
- // \\ );
- // \\ return;
- // \\}
- // \\
- // \\fn exit() noreturn {
- // \\ asm volatile ("syscall"
- // \\ :
- // \\ : [number] "{rax}" (231),
- // \\ [arg1] "{rdi}" (0)
- // \\ : "rcx", "r11", "memory"
- // \\ );
- // \\ unreachable;
- // \\}
- //,
- // "hello\nhello\nhello\nhello\nhello\n",
- //);
+ case.addCompareOutput(
+ \\export fn _start() noreturn {
+ \\ for ("hello") |_| print();
+ \\
+ \\ exit();
+ \\}
+ \\
+ \\fn print() void {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (1),
+ \\ [arg1] "{rdi}" (1),
+ \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
+ \\ [arg3] "{rdx}" (6)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ return;
+ \\}
+ \\
+ \\fn exit() noreturn {
+ \\ asm volatile ("syscall"
+ \\ :
+ \\ : [number] "{rax}" (231),
+ \\ [arg1] "{rdi}" (0)
+ \\ : "rcx", "r11", "memory"
+ \\ );
+ \\ unreachable;
+ \\}
+ ,
+ "hello\nhello\nhello\nhello\nhello\n",
+ );
}
//{
BRANCH_TODO
@@ -35,3 +35,6 @@ Performance optimizations to look into:
* enum literals can use small strings
* string literals can use small strings
* don't need the Sema coercion on condbr condition, it's done with result locations
+ * astgen for loops using pointer arithmetic because it's faster and if the programmer
+ wants an index capture, that will just be a convenience variable that zig sets up
+ independently.