eval_inst.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_
  5. #define CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_
  6. #include "toolchain/check/eval.h"
  7. namespace Carbon::Check {
  8. // The result of constant evaluation of an instruction.
  9. class ConstantEvalResult {
  10. public:
  11. // Produce a new constant as the result of an evaluation. The phase of the
  12. // produced constant must be the same as the greatest phase of the operands in
  13. // the evaluation. This will typically be the case if the evaluation uses all
  14. // of its operands.
  15. static auto NewSamePhase(SemIR::Inst inst) -> ConstantEvalResult {
  16. return ConstantEvalResult(inst, /*same_phase_as_inst=*/true);
  17. }
  18. // Produce a new constant as the result of an evaluation. The constant may
  19. // have any phase. Use `NewSamePhase` instead where possible, as it avoids a
  20. // phase recomputation.
  21. static auto NewAnyPhase(SemIR::Inst inst) -> ConstantEvalResult {
  22. return ConstantEvalResult(inst, /*same_phase_as_inst=*/false);
  23. }
  24. // Produce an existing constant as the result of an evaluation.
  25. static constexpr auto Existing(SemIR::ConstantId existing_id)
  26. -> ConstantEvalResult {
  27. CARBON_CHECK(existing_id.is_constant());
  28. return ConstantEvalResult(existing_id);
  29. }
  30. // Indicates that an error was produced by evaluation.
  31. static const ConstantEvalResult Error;
  32. // Indicates that we encountered an instruction whose evaluation is
  33. // non-constant despite having constant operands. This should be rare;
  34. // usually we want to produce an error in this case.
  35. static const ConstantEvalResult NotConstant;
  36. // Indicates that we encountered an instruction for which we've not
  37. // implemented constant evaluation yet. Instruction is treated as not
  38. // constant.
  39. static const ConstantEvalResult TODO;
  40. // Returns whether the result of evaluation is that we should produce a new
  41. // constant described by `new_inst()` rather than an existing `ConstantId`
  42. // described by `existing()`.
  43. auto is_new() const -> bool { return !result_id_.has_value(); }
  44. // Returns the existing constant that this the instruction evaluates to, or
  45. // `None` if this is evaluation produces a new constant.
  46. auto existing() const -> SemIR::ConstantId { return result_id_; }
  47. // Returns the new constant instruction that is the result of evaluation.
  48. auto new_inst() const -> SemIR::Inst {
  49. CARBON_CHECK(is_new());
  50. return new_inst_;
  51. }
  52. // Whether the new constant instruction is known to have the same phase as the
  53. // evaluated instruction. Requires `is_new()`.
  54. auto same_phase_as_inst() const -> bool {
  55. CARBON_CHECK(is_new());
  56. return same_phase_as_inst_;
  57. }
  58. private:
  59. constexpr explicit ConstantEvalResult(SemIR::ConstantId raw_id)
  60. : result_id_(raw_id), same_phase_as_inst_(false) {}
  61. explicit ConstantEvalResult(SemIR::Inst inst, bool same_phase_as_inst)
  62. : result_id_(SemIR::ConstantId::None),
  63. new_inst_(inst),
  64. same_phase_as_inst_(same_phase_as_inst) {}
  65. SemIR::ConstantId result_id_;
  66. union {
  67. SemIR::Inst new_inst_;
  68. };
  69. bool same_phase_as_inst_;
  70. };
  71. constexpr ConstantEvalResult ConstantEvalResult::Error =
  72. Existing(SemIR::ErrorInst::SingletonConstantId);
  73. constexpr ConstantEvalResult ConstantEvalResult::NotConstant =
  74. ConstantEvalResult(SemIR::ConstantId::NotConstant);
  75. constexpr ConstantEvalResult ConstantEvalResult::TODO = NotConstant;
  76. // `EvalConstantInst` evaluates an instruction whose operands are all constant,
  77. // in a context unrelated to the enclosing evaluation. The function is given the
  78. // instruction after its operands, including its type, are replaced by their
  79. // evaluated value, and returns a `ConstantEvalResult` describing the result of
  80. // evaluating the instruction.
  81. //
  82. // An overload is defined for each type whose constant kind is one of the
  83. // following:
  84. //
  85. // - InstConstantKind::Indirect
  86. // - InstConstantKind::SymbolicOnly
  87. // - InstConstantKind::Conditional
  88. //
  89. // ... except for cases where the result of evaluation depends on the evaluation
  90. // context itself. Those cases are handled by explicit specialization of
  91. // `TryEvalTypedInst` in `eval.cpp` instead.
  92. //
  93. // Overloads are *declared* for all types, because there isn't a good way to
  94. // declare only the overloads we want here without duplicating the list of
  95. // types. Missing overloads will be diagnosed when linking.
  96. #define CARBON_SEM_IR_INST_KIND(Kind) \
  97. auto EvalConstantInst(Context& context, SemIRLoc loc, SemIR::Kind inst) \
  98. -> ConstantEvalResult;
  99. #include "toolchain/sem_ir/inst_kind.def"
  100. } // namespace Carbon::Check
  101. #endif // CARBON_TOOLCHAIN_CHECK_EVAL_INST_H_