mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:10:12 +01:00
When making a direct call to a thunk, inline the call in SemIR. (#5642)
This preserves the constant values of the arguments to the thunk, which is important if the thunk requires conversion of an `IntLiteral` to some other type. This should become unnecessary once we have form support, but avoiding the indirection through a thunk function seems valuable even once that support is in place. To support this, track whether a function is a thunk on the Function object, and if so, what the callee of the thunk is. This information is also included in formatted SemIR when dumping the thunk.
This commit is contained in:
+61
-48
@@ -191,26 +191,25 @@ static auto CloneFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
// Create the `Function` object.
|
||||
auto& callee = context.functions().Get(callee_id);
|
||||
function_decl.function_id = context.functions().Add(SemIR::Function{
|
||||
{.name_id = signature.name_id,
|
||||
.parent_scope_id = callee.parent_scope_id,
|
||||
.generic_id = generic_id,
|
||||
.first_param_node_id = signature.first_param_node_id,
|
||||
.last_param_node_id = signature.last_param_node_id,
|
||||
.pattern_block_id = pattern_block_id,
|
||||
.implicit_param_patterns_id = implicit_param_patterns_id,
|
||||
.param_patterns_id = param_patterns_id,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = decl_id,
|
||||
.definition_id = decl_id},
|
||||
{.call_params_id = call_params_id,
|
||||
.return_slot_pattern_id = return_slot_pattern_id,
|
||||
.special_function_kind = SemIR::Function::SpecialFunctionKind::Thunk,
|
||||
.virtual_modifier = callee.virtual_modifier,
|
||||
.virtual_index = callee.virtual_index,
|
||||
.self_param_id = self_param_id}});
|
||||
function_decl.function_id = context.functions().Add(
|
||||
SemIR::Function{{.name_id = signature.name_id,
|
||||
.parent_scope_id = callee.parent_scope_id,
|
||||
.generic_id = generic_id,
|
||||
.first_param_node_id = signature.first_param_node_id,
|
||||
.last_param_node_id = signature.last_param_node_id,
|
||||
.pattern_block_id = pattern_block_id,
|
||||
.implicit_param_patterns_id = implicit_param_patterns_id,
|
||||
.param_patterns_id = param_patterns_id,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = decl_id,
|
||||
.definition_id = decl_id},
|
||||
{.call_params_id = call_params_id,
|
||||
.return_slot_pattern_id = return_slot_pattern_id,
|
||||
.virtual_modifier = callee.virtual_modifier,
|
||||
.virtual_index = callee.virtual_index,
|
||||
.self_param_id = self_param_id}});
|
||||
function_decl.type_id =
|
||||
GetFunctionType(context, function_decl.function_id,
|
||||
context.scope_stack().PeekSpecificId());
|
||||
@@ -269,6 +268,9 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
CloneFunctionDecl(context, SemIR::LocId(callee_id), signature_id,
|
||||
signature_specific_id, callee.function_id);
|
||||
|
||||
// Track that this function is a thunk.
|
||||
context.functions().Get(function_id).SetThunk(callee_id);
|
||||
|
||||
// Register the thunk to be defined when we reach the end of the enclosing
|
||||
// deferred definition scope, for example an `impl` or `class` definition, as
|
||||
// if the thunk's body were written inline in this location.
|
||||
@@ -284,7 +286,8 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id,
|
||||
}
|
||||
|
||||
// Build an expression that names the value matched by a pattern.
|
||||
static auto BuildPatternRef(Context& context, SemIR::FunctionId function_id,
|
||||
static auto BuildPatternRef(Context& context,
|
||||
llvm::ArrayRef<SemIR::InstId> arg_ids,
|
||||
SemIR::InstId pattern_id) -> SemIR::InstId {
|
||||
auto pattern = context.insts().Get(pattern_id);
|
||||
|
||||
@@ -294,20 +297,7 @@ static auto BuildPatternRef(Context& context, SemIR::FunctionId function_id,
|
||||
|
||||
auto pattern_ref_id = SemIR::InstId::None;
|
||||
if (auto value_param = pattern.TryAs<SemIR::ValueParamPattern>()) {
|
||||
// Build a reference to this parameter.
|
||||
auto call_param_id = context.inst_blocks().Get(
|
||||
context.functions()
|
||||
.Get(function_id)
|
||||
.call_params_id)[value_param->index.index];
|
||||
// Use a pretty name for the `name_ref`. While it's suspicious to use a
|
||||
// pretty name in the IR like this, the only reason we include a name at
|
||||
// all here is to make the formatted SemIR more readable.
|
||||
pattern_ref_id = AddInst<SemIR::NameRef>(
|
||||
context, SemIR::LocId(pattern_id),
|
||||
{.type_id = context.insts().Get(call_param_id).type_id(),
|
||||
.name_id = SemIR::GetPrettyNameFromPatternId(
|
||||
context.sem_ir(), value_param->subpattern_id),
|
||||
.value_id = call_param_id});
|
||||
pattern_ref_id = arg_ids[value_param->index.index];
|
||||
} else {
|
||||
if (pattern_id != SemIR::ErrorInst::InstId) {
|
||||
context.TODO(
|
||||
@@ -327,24 +317,17 @@ static auto BuildPatternRef(Context& context, SemIR::FunctionId function_id,
|
||||
return pattern_ref_id;
|
||||
}
|
||||
|
||||
// Build a call to a function that forwards the arguments of the enclosing
|
||||
// function, for use when constructing a thunk.
|
||||
static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
|
||||
SemIR::InstId callee_id) -> SemIR::InstId {
|
||||
auto loc_id = SemIR::LocId(callee_id);
|
||||
auto PerformThunkCall(Context& context, SemIR::LocId loc_id,
|
||||
SemIR::FunctionId function_id,
|
||||
llvm::ArrayRef<SemIR::InstId> call_arg_ids,
|
||||
SemIR::InstId callee_id) -> SemIR::InstId {
|
||||
auto& function = context.functions().Get(function_id);
|
||||
|
||||
// Build a `NameRef` naming the callee, and a `SpecificConstant` if needed.
|
||||
auto callee_type = context.types().GetAs<SemIR::FunctionType>(
|
||||
context.insts().Get(callee_id).type_id());
|
||||
callee_id = BuildNameRef(context, loc_id, function.name_id, callee_id,
|
||||
callee_type.specific_id);
|
||||
|
||||
// If we have a self parameter, form `self.<callee_id>`.
|
||||
if (function.self_param_id.has_value()) {
|
||||
callee_id = PerformCompoundMemberAccess(
|
||||
context, loc_id,
|
||||
BuildPatternRef(context, function_id, function.self_param_id),
|
||||
BuildPatternRef(context, call_arg_ids, function.self_param_id),
|
||||
callee_id);
|
||||
}
|
||||
|
||||
@@ -352,12 +335,42 @@ static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
|
||||
llvm::SmallVector<SemIR::InstId> args;
|
||||
for (auto pattern_id :
|
||||
context.inst_blocks().Get(function.param_patterns_id)) {
|
||||
args.push_back(BuildPatternRef(context, function_id, pattern_id));
|
||||
args.push_back(BuildPatternRef(context, call_arg_ids, pattern_id));
|
||||
}
|
||||
|
||||
return PerformCall(context, loc_id, callee_id, args);
|
||||
}
|
||||
|
||||
// Build a call to a function that forwards the arguments of the enclosing
|
||||
// function, for use when constructing a thunk.
|
||||
static auto BuildThunkCall(Context& context, SemIR::FunctionId function_id,
|
||||
SemIR::InstId callee_id) -> SemIR::InstId {
|
||||
auto& function = context.functions().Get(function_id);
|
||||
|
||||
// Build a `NameRef` naming the callee, and a `SpecificConstant` if needed.
|
||||
auto loc_id = SemIR::LocId(callee_id);
|
||||
auto callee_type = context.types().GetAs<SemIR::FunctionType>(
|
||||
context.insts().Get(callee_id).type_id());
|
||||
callee_id = BuildNameRef(context, loc_id, function.name_id, callee_id,
|
||||
callee_type.specific_id);
|
||||
|
||||
// Build a reference to each parameter for use as call arguments.
|
||||
llvm::SmallVector<SemIR::InstId> call_args;
|
||||
auto call_params = context.inst_blocks().Get(function.call_params_id);
|
||||
call_args.reserve(call_params.size());
|
||||
for (auto call_param_id : call_params) {
|
||||
// Use a pretty name for the `name_ref`. While it's suspicious to use a
|
||||
// pretty name in the IR like this, the only reason we include a name at all
|
||||
// here is to make the formatted SemIR more readable.
|
||||
auto call_param = context.insts().GetAs<SemIR::AnyParam>(call_param_id);
|
||||
call_args.push_back(BuildNameRef(context, SemIR::LocId(call_param_id),
|
||||
call_param.pretty_name_id, call_param_id,
|
||||
SemIR::SpecificId::None));
|
||||
}
|
||||
|
||||
return PerformThunkCall(context, loc_id, function_id, call_args, callee_id);
|
||||
}
|
||||
|
||||
// Given a declaration of a thunk and the function that it should call, build
|
||||
// the thunk body.
|
||||
static auto BuildThunkDefinition(Context& context,
|
||||
|
||||
Reference in New Issue
Block a user