AstGen: use RLS to infer the first argument of @fieldParentPtr

This commit is contained in:
Jacob Young
2024-03-19 11:55:15 +01:00
parent e409afb79b
commit 17673dcd6e
9 changed files with 126 additions and 83 deletions

View File

@@ -316,8 +316,7 @@ const ResultInfo = struct {
};
/// Find the result type for a cast builtin given the result location.
/// If the location does not have a known result type, emits an error on
/// the given node.
/// If the location does not have a known result type, returns `null`.
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
return switch (rl) {
.discard, .none, .ref, .inferred_ptr, .destructure => null,
@@ -330,6 +329,9 @@ const ResultInfo = struct {
};
}
/// Find the result type for a cast builtin given the result location.
/// If the location does not have a known result type, emits an error on
/// the given node.
fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
const astgen = gz.astgen;
if (try rl.resultType(gz, node)) |ty| return ty;
@@ -2786,7 +2788,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.atomic_load,
.atomic_rmw,
.mul_add,
.field_parent_ptr,
.max,
.min,
.c_import,
@@ -8853,6 +8854,7 @@ fn ptrCast(
const node_datas = tree.nodes.items(.data);
const node_tags = tree.nodes.items(.tag);
const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).Struct.backing_integer.?;
var flags: Zir.Inst.FullPtrCastFlags = .{};
// Note that all pointer cast builtins have one parameter, so we only need
@@ -8870,36 +8872,62 @@ fn ptrCast(
}
if (node_datas[node].lhs == 0) break; // 0 args
if (node_datas[node].rhs != 0) break; // 2 args
const builtin_token = main_tokens[node];
const builtin_name = tree.tokenSlice(builtin_token);
const info = BuiltinFn.list.get(builtin_name) orelse break;
if (info.param_count != 1) break;
if (node_datas[node].rhs == 0) {
// 1 arg
if (info.param_count != 1) break;
switch (info.tag) {
else => break,
inline .ptr_cast,
.align_cast,
.addrspace_cast,
.const_cast,
.volatile_cast,
=> |tag| {
if (@field(flags, @tagName(tag))) {
return astgen.failNode(node, "redundant {s}", .{builtin_name});
}
@field(flags, @tagName(tag)) = true;
},
switch (info.tag) {
else => break,
inline .ptr_cast,
.align_cast,
.addrspace_cast,
.const_cast,
.volatile_cast,
=> |tag| {
if (@field(flags, @tagName(tag))) {
return astgen.failNode(node, "redundant {s}", .{builtin_name});
}
@field(flags, @tagName(tag)) = true;
},
}
node = node_datas[node].lhs;
} else {
// 2 args
if (info.param_count != 2) break;
switch (info.tag) {
else => break,
.field_parent_ptr => {
if (flags.ptr_cast) break;
const flags_int: FlagsInt = @bitCast(flags);
const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
const parent_ptr_type = try ri.rl.resultTypeForCast(gz, root_node, "@alignCast");
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, node_datas[node].lhs);
const field_ptr = try expr(gz, scope, .{ .rl = .none }, node_datas[node].rhs);
try emitDbgStmt(gz, cursor);
const result = try gz.addExtendedPayloadSmall(.field_parent_ptr, flags_int, Zir.Inst.FieldParentPtr{
.src_node = gz.nodeIndexToRelative(node),
.parent_ptr_type = parent_ptr_type,
.field_name = field_name,
.field_ptr = field_ptr,
});
return rvalue(gz, ri, result, root_node);
},
}
}
node = node_datas[node].lhs;
}
const flags_i: u5 = @bitCast(flags);
assert(flags_i != 0);
const flags_int: FlagsInt = @bitCast(flags);
assert(flags_int != 0);
const ptr_only: Zir.Inst.FullPtrCastFlags = .{ .ptr_cast = true };
if (flags_i == @as(u5, @bitCast(ptr_only))) {
if (flags_int == @as(FlagsInt, @bitCast(ptr_only))) {
// Special case: simpler representation
return typeCast(gz, scope, ri, root_node, node, .ptr_cast, "@ptrCast");
}
@@ -8908,12 +8936,12 @@ fn ptrCast(
.const_cast = true,
.volatile_cast = true,
};
if ((flags_i & ~@as(u5, @bitCast(no_result_ty_flags))) == 0) {
if ((flags_int & ~@as(FlagsInt, @bitCast(no_result_ty_flags))) == 0) {
// Result type not needed
const cursor = maybeAdvanceSourceCursorToMainToken(gz, root_node);
const operand = try expr(gz, scope, .{ .rl = .none }, node);
try emitDbgStmt(gz, cursor);
const result = try gz.addExtendedPayloadSmall(.ptr_cast_no_dest, flags_i, Zir.Inst.UnNode{
const result = try gz.addExtendedPayloadSmall(.ptr_cast_no_dest, flags_int, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(root_node),
.operand = operand,
});
@@ -8926,7 +8954,7 @@ fn ptrCast(
const result_type = try ri.rl.resultTypeForCast(gz, root_node, flags.needResultTypeBuiltinName());
const operand = try expr(gz, scope, .{ .rl = .none }, node);
try emitDbgStmt(gz, cursor);
const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_i, Zir.Inst.BinNode{
const result = try gz.addExtendedPayloadSmall(.ptr_cast_full, flags_int, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(root_node),
.lhs = result_type,
.rhs = operand,
@@ -9379,7 +9407,7 @@ fn builtinCall(
try emitDbgNode(gz, node);
const result = try gz.addExtendedPayload(.error_cast, Zir.Inst.BinNode{
.lhs = try ri.rl.resultTypeForCast(gz, node, "@errorCast"),
.lhs = try ri.rl.resultTypeForCast(gz, node, builtin_name),
.rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.node = gz.nodeIndexToRelative(node),
});
@@ -9452,7 +9480,7 @@ fn builtinCall(
},
.splat => {
const result_type = try ri.rl.resultTypeForCast(gz, node, "@splat");
const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
@@ -9537,12 +9565,13 @@ fn builtinCall(
return rvalue(gz, ri, result, node);
},
.field_parent_ptr => {
const parent_type = try typeExpr(gz, scope, params[0]);
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1]);
const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{
.parent_type = parent_type,
const parent_ptr_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0]);
const result = try gz.addExtendedPayloadSmall(.field_parent_ptr, 0, Zir.Inst.FieldParentPtr{
.src_node = gz.nodeIndexToRelative(node),
.parent_ptr_type = parent_ptr_type,
.field_name = field_name,
.field_ptr = try expr(gz, scope, .{ .rl = .none }, params[2]),
.field_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
});
return rvalue(gz, ri, result, node);
},

View File

@@ -911,6 +911,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.work_item_id,
.work_group_size,
.work_group_id,
.field_parent_ptr,
=> {
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
return false;
@@ -976,7 +977,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
},
.bit_offset_of,
.offset_of,
.field_parent_ptr,
.has_decl,
.has_field,
.field,

View File

@@ -504,7 +504,7 @@ pub const list = list: {
"@fieldParentPtr",
.{
.tag = .field_parent_ptr,
.param_count = 3,
.param_count = 2,
},
},
.{

View File

@@ -940,9 +940,6 @@ pub const Inst = struct {
/// The addend communicates the type of the builtin.
/// The mulends need to be coerced to the same type.
mul_add,
/// Implements the `@fieldParentPtr` builtin.
/// Uses the `pl_node` union field with payload `FieldParentPtr`.
field_parent_ptr,
/// Implements the `@memcpy` builtin.
/// Uses the `pl_node` union field with payload `Bin`.
memcpy,
@@ -1230,7 +1227,6 @@ pub const Inst = struct {
.atomic_store,
.mul_add,
.builtin_call,
.field_parent_ptr,
.max,
.memcpy,
.memset,
@@ -1522,7 +1518,6 @@ pub const Inst = struct {
.atomic_rmw,
.mul_add,
.builtin_call,
.field_parent_ptr,
.max,
.min,
.c_import,
@@ -1794,7 +1789,6 @@ pub const Inst = struct {
.atomic_store = .pl_node,
.mul_add = .pl_node,
.builtin_call = .pl_node,
.field_parent_ptr = .pl_node,
.max = .pl_node,
.memcpy = .pl_node,
.memset = .pl_node,
@@ -2064,6 +2058,12 @@ pub const Inst = struct {
/// with a specific value. For instance, this is used for the capture of an `errdefer`.
/// This should never appear in a body.
value_placeholder,
/// Implements the `@fieldParentPtr` builtin.
/// `operand` is payload index to `FieldParentPtr`.
/// `small` contains `FullPtrCastFlags`.
/// Guaranteed to not have the `ptr_cast` flag.
/// Uses the `pl_node` union field with payload `FieldParentPtr`.
field_parent_ptr,
pub const InstData = struct {
opcode: Extended,
@@ -3363,9 +3363,14 @@ pub const Inst = struct {
};
pub const FieldParentPtr = struct {
parent_type: Ref,
src_node: i32,
parent_ptr_type: Ref,
field_name: Ref,
field_ptr: Ref,
pub fn src(self: FieldParentPtr) LazySrcLoc {
return LazySrcLoc.nodeOffset(self.src_node);
}
};
pub const Shuffle = struct {