Add an EvalOrAddInst function. (#5258)

Use that instead of `AddInstInNoBlock` to get the value of an
instruction when evaluation might depend on the `InstId` but only the
`ConstantId` of the instruction is desired by the consumer.
This commit is contained in:
Richard Smith
2025-04-08 21:04:30 +00:00
committed by GitHub
parent d07f70cfb3
commit bfef32b482
17 changed files with 164 additions and 83 deletions
+80 -8
View File
@@ -10,6 +10,7 @@
#include "toolchain/check/generic_region_stack.h"
#include "toolchain/sem_ir/constant.h"
#include "toolchain/sem_ir/ids.h"
#include "toolchain/sem_ir/inst_kind.h"
namespace Carbon::Check {
@@ -100,20 +101,91 @@ auto AddPatternInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
auto GetOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
-> SemIR::InstId {
if (loc_id_and_inst.loc_id.is_implicit() &&
!loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
auto const_id =
TryEvalInstUnsafe(context, SemIR::InstId::None, loc_id_and_inst.inst);
if (const_id.has_value()) {
CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
loc_id_and_inst.inst);
return context.constant_values().GetInstId(const_id);
CARBON_CHECK(!loc_id_and_inst.inst.kind().has_cleanup());
auto handle_constant_id = [&](SemIR::ConstantId const_id) -> SemIR::InstId {
CARBON_CHECK(const_id.has_value());
// If we didn't produce a constant value for the instruction, we have to add
// the instruction.
if (!const_id.is_constant()) {
return SemIR::InstId::None;
}
CARBON_VLOG_TO(context.vlog_stream(), "GetOrAddInst: constant: {0}\n",
loc_id_and_inst.inst);
return context.constant_values().GetInstId(const_id);
};
// If the instruction is implicit, produce its constant value instead if
// possible.
if (loc_id_and_inst.loc_id.is_implicit()) {
switch (loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
case SemIR::InstConstantNeedsInstIdKind::No: {
// Evaluation doesn't need an InstId. Just do it.
auto const_id = TryEvalInstUnsafe(context, SemIR::InstId::None,
loc_id_and_inst.inst);
if (auto result_inst_id = handle_constant_id(const_id);
result_inst_id.has_value()) {
return result_inst_id;
}
break;
}
case SemIR::InstConstantNeedsInstIdKind::DuringEvaluation: {
// Evaluation temporarily needs an InstId. Add one for now.
auto inst_id = AddInstInNoBlock(context, loc_id_and_inst);
auto const_id = context.constant_values().Get(inst_id);
if (auto result_inst_id = handle_constant_id(const_id);
result_inst_id.has_value()) {
// TODO: We didn't end up needing the `inst_id` instruction. Consider
// removing it from `insts` if it's still the most recently added
// instruction.
CARBON_CHECK(result_inst_id != inst_id);
return result_inst_id;
}
context.inst_block_stack().AddInstId(inst_id);
return inst_id;
}
case SemIR::InstConstantNeedsInstIdKind::Permanent: {
// Evaluation needs a permanent InstId. Add the instruction.
break;
}
}
}
// TODO: For an implicit instruction, this reattempts evaluation.
return AddInst(context, loc_id_and_inst);
}
auto EvalOrAddInst(Context& context, SemIR::LocIdAndInst loc_id_and_inst)
-> SemIR::ConstantId {
CARBON_CHECK(!loc_id_and_inst.inst.kind().has_cleanup());
switch (loc_id_and_inst.inst.kind().constant_needs_inst_id()) {
case SemIR::InstConstantNeedsInstIdKind::No: {
// Evaluation doesn't need an InstId. Just do it.
return TryEvalInstUnsafe(context, SemIR::InstId::None,
loc_id_and_inst.inst);
}
case SemIR::InstConstantNeedsInstIdKind::DuringEvaluation: {
// Evaluation temporarily needs an InstId. Add one for now.
auto inst_id = AddInstInNoBlock(context, loc_id_and_inst);
// TODO: Consider removing `inst_id` from `insts` if it's still the most
// recently added instruction.
return context.constant_values().Get(inst_id);
}
case SemIR::InstConstantNeedsInstIdKind::Permanent: {
// Evaluation needs a permanent InstId. Add the instruction.
auto inst_id = AddInst(context, loc_id_and_inst);
return context.constant_values().Get(inst_id);
}
}
}
auto AddPlaceholderInstInNoBlock(Context& context,
SemIR::LocIdAndInst loc_id_and_inst)
-> SemIR::InstId {