aboutsummaryrefslogtreecommitdiff
path: root/src/AstGen.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-02 19:11:51 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-02 19:11:51 -0700
commit97d7fddfb78d17132749cae59fea36fe661bf642 (patch)
tree5b01a32f9ee35e6cef838cffb5058e5f0f777229 /src/AstGen.zig
parent43d364afef7f0609f9d897c7ff129ba6b9b3cab0 (diff)
downloadzig-97d7fddfb78d17132749cae59fea36fe661bf642.tar.gz
zig-97d7fddfb78d17132749cae59fea36fe661bf642.zip
stage2: progress towards basic structs
Introduce `ResultLoc.none_or_ref` which is used by field access expressions to avoid unnecessary loads when the field access itself will do the load. This turns: ```zig p.y - p.x - p.x ``` from ```zir %14 = load(%4) node_offset:8:12 %15 = field_val(%14, "y") node_offset:8:13 %16 = load(%4) node_offset:8:18 %17 = field_val(%16, "x") node_offset:8:19 %18 = sub(%15, %17) node_offset:8:16 %19 = load(%4) node_offset:8:24 %20 = field_val(%19, "x") node_offset:8:25 ``` to ```zir %14 = field_val(%4, "y") node_offset:8:13 %15 = field_val(%4, "x") node_offset:8:19 %16 = sub(%14, %15) node_offset:8:16 %17 = field_val(%4, "x") node_offset:8:25 ``` Much more compact. This requires `Sema.zirFieldVal` to support both pointers and non-pointers. C backend: Implement typedefs for struct types, as well as the following TZIR instructions: * mul * mulwrap * addwrap * subwrap * ref * struct_field_ptr Note that add, addwrap, sub, subwrap, mul, mulwrap instructions are all incorrect currently and need to be updated to properly handle wrapping and non wrapping for signed and unsigned. C backend: change indentation delta to 1, to make the output smaller and to process fewer bytes. I promise I will add a test case as soon as I fix those warnings that are being printed for my test case.
Diffstat (limited to 'src/AstGen.zig')
-rw-r--r--src/AstGen.zig38
1 files changed, 25 insertions, 13 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 9b4e6c7c1a..6c3ce1251c 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -124,6 +124,9 @@ pub const ResultLoc = union(enum) {
/// The expression must generate a pointer rather than a value. For example, the left hand side
/// of an assignment uses this kind of result location.
ref,
+ /// The callee will accept a ref, but it is not necessary, and the `ResultLoc`
+ /// may be treated as `none` instead.
+ none_or_ref,
/// The expression will be coerced into this type, but it will be evaluated as an rvalue.
ty: zir.Inst.Ref,
/// The expression must store its result into this typed pointer. The result instruction
@@ -157,7 +160,7 @@ pub const ResultLoc = union(enum) {
var elide_store_to_block_ptr_instructions = false;
switch (rl) {
// In this branch there will not be any store_to_block_ptr instructions.
- .discard, .none, .ty, .ref => return .{
+ .discard, .none, .none_or_ref, .ty, .ref => return .{
.tag = .break_operand,
.elide_store_to_block_ptr_instructions = false,
},
@@ -606,8 +609,13 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
.deref => {
const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
- const result = try gz.addUnNode(.load, lhs, node);
- return rvalue(gz, scope, rl, result, node);
+ switch (rl) {
+ .ref, .none_or_ref => return lhs,
+ else => {
+ const result = try gz.addUnNode(.load, lhs, node);
+ return rvalue(gz, scope, rl, result, node);
+ },
+ }
},
.address_of => {
const result = try expr(gz, scope, .ref, node_datas[node].lhs);
@@ -816,7 +824,7 @@ pub fn structInitExpr(
}
switch (rl) {
.discard => return mod.failNode(scope, node, "TODO implement structInitExpr discard", .{}),
- .none => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
+ .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
.ref => unreachable, // struct literal not valid as l-value
.ty => |ty_inst| {
return mod.failNode(scope, node, "TODO implement structInitExpr ty", .{});
@@ -1980,7 +1988,7 @@ fn orelseCatchExpr(
// TODO handle catch
const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
.ref => .ref,
- .discard, .none, .block_ptr, .inferred_ptr => .none,
+ .discard, .none, .none_or_ref, .block_ptr, .inferred_ptr => .none,
.ty => |elem_ty| blk: {
const wrapped_ty = try block_scope.addUnNode(.optional_type, elem_ty, node);
break :blk .{ .ty = wrapped_ty };
@@ -2156,7 +2164,7 @@ pub fn fieldAccess(
.field_name_start = str_index,
}),
else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, zir.Inst.Field{
- .lhs = try expr(gz, scope, .none, object_node),
+ .lhs = try expr(gz, scope, .none_or_ref, object_node),
.field_name_start = str_index,
}), node),
}
@@ -3474,9 +3482,13 @@ fn identifier(
.local_ptr => {
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(.load, local_ptr.ptr, ident);
- return rvalue(gz, scope, rl, loaded, ident);
+ switch (rl) {
+ .ref, .none_or_ref => return local_ptr.ptr,
+ else => {
+ const loaded = try gz.addUnNode(.load, local_ptr.ptr, ident);
+ return rvalue(gz, scope, rl, loaded, ident);
+ },
+ }
}
s = local_ptr.parent;
},
@@ -3493,7 +3505,7 @@ fn identifier(
}
const decl_index = @intCast(u32, gop.index);
switch (rl) {
- .ref => return gz.addDecl(.decl_ref, decl_index, ident),
+ .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),
else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
}
}
@@ -3697,7 +3709,7 @@ fn as(
) InnerError!zir.Inst.Ref {
const dest_type = try typeExpr(gz, scope, lhs);
switch (rl) {
- .none, .discard, .ref, .ty => {
+ .none, .none_or_ref, .discard, .ref, .ty => {
const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
return rvalue(gz, scope, rl, result, node);
},
@@ -3781,7 +3793,7 @@ fn bitCast(
});
return rvalue(gz, scope, rl, result, node);
},
- .ref => unreachable, // `@bitCast` is not allowed as an r-value.
+ .ref, .none_or_ref => unreachable, // `@bitCast` is not allowed as an r-value.
.ptr => |result_ptr| {
const casted_result_ptr = try gz.addUnNode(.bitcast_result_ptr, result_ptr, node);
return expr(gz, scope, .{ .ptr = casted_result_ptr }, rhs);
@@ -4354,7 +4366,7 @@ fn rvalue(
src_node: ast.Node.Index,
) InnerError!zir.Inst.Ref {
switch (rl) {
- .none => return result,
+ .none, .none_or_ref => return result,
.discard => {
// Emit a compile error for discarding error values.
_ = try gz.addUnNode(.ensure_result_non_error, result, src_node);