handle.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #include "llvm/ADT/APFloat.h"
  5. #include "llvm/ADT/APInt.h"
  6. #include "llvm/ADT/ArrayRef.h"
  7. #include "llvm/IR/BasicBlock.h"
  8. #include "llvm/IR/Constants.h"
  9. #include "llvm/IR/IRBuilder.h"
  10. #include "llvm/IR/Type.h"
  11. #include "llvm/IR/Value.h"
  12. #include "llvm/Support/Casting.h"
  13. #include "toolchain/lower/function_context.h"
  14. #include "toolchain/sem_ir/builtin_function_kind.h"
  15. #include "toolchain/sem_ir/function.h"
  16. #include "toolchain/sem_ir/inst.h"
  17. #include "toolchain/sem_ir/typed_insts.h"
  18. namespace Carbon::Lower {
  19. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  20. SemIR::AddrOf inst) -> void {
  21. context.SetLocal(inst_id, context.GetValue(inst.lvalue_id));
  22. }
  23. auto HandleInst(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
  24. SemIR::AddrPattern /*inst*/) -> void {
  25. CARBON_FATAL() << "`addr` should be lowered by `BuildFunctionDefinition`";
  26. }
  27. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  28. SemIR::ArrayIndex inst) -> void {
  29. auto* array_value = context.GetValue(inst.array_id);
  30. auto* llvm_type =
  31. context.GetType(context.sem_ir().insts().Get(inst.array_id).type_id());
  32. llvm::Value* indexes[2] = {
  33. llvm::ConstantInt::get(llvm::Type::getInt32Ty(context.llvm_context()), 0),
  34. context.GetValue(inst.index_id)};
  35. context.SetLocal(inst_id,
  36. context.builder().CreateInBoundsGEP(llvm_type, array_value,
  37. indexes, "array.index"));
  38. }
  39. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  40. SemIR::ArrayInit inst) -> void {
  41. // The result of initialization is the return slot of the initializer.
  42. context.SetLocal(inst_id, context.GetValue(inst.dest_id));
  43. }
  44. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  45. SemIR::AsCompatible inst) -> void {
  46. context.SetLocal(inst_id, context.GetValue(inst.source_id));
  47. }
  48. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  49. SemIR::Assign inst) -> void {
  50. auto storage_type_id = context.sem_ir().insts().Get(inst.lhs_id).type_id();
  51. context.FinishInit(storage_type_id, inst.lhs_id, inst.rhs_id);
  52. }
  53. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  54. SemIR::BindAlias inst) -> void {
  55. auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id);
  56. if (type_inst_id == SemIR::InstId::BuiltinNamespaceType) {
  57. return;
  58. }
  59. context.SetLocal(inst_id, context.GetValue(inst.value_id));
  60. }
  61. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  62. SemIR::ExportDecl inst) -> void {
  63. auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id);
  64. if (type_inst_id == SemIR::InstId::BuiltinNamespaceType) {
  65. return;
  66. }
  67. context.SetLocal(inst_id, context.GetValue(inst.value_id));
  68. }
  69. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  70. SemIR::BindName inst) -> void {
  71. context.SetLocal(inst_id, context.GetValue(inst.value_id));
  72. }
  73. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  74. SemIR::BindSymbolicName inst) -> void {
  75. context.SetLocal(inst_id, context.GetValue(inst.value_id));
  76. }
  77. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  78. SemIR::BlockArg inst) -> void {
  79. context.SetLocal(inst_id, context.GetBlockArg(inst.block_id, inst.type_id));
  80. }
  81. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  82. SemIR::BoundMethod inst) -> void {
  83. // Propagate just the function; the object is separately provided to the
  84. // enclosing call as an implicit argument.
  85. context.SetLocal(inst_id, context.GetValue(inst.function_id));
  86. }
  87. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  88. SemIR::Branch inst) -> void {
  89. // Opportunistically avoid creating a BasicBlock that contains just a branch.
  90. // TODO: Don't do this if it would remove a loop preheader block.
  91. llvm::BasicBlock* block = context.builder().GetInsertBlock();
  92. if (block->empty() && context.TryToReuseBlock(inst.target_id, block)) {
  93. // Reuse this block as the branch target.
  94. } else {
  95. context.builder().CreateBr(context.GetBlock(inst.target_id));
  96. }
  97. context.builder().ClearInsertionPoint();
  98. }
  99. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  100. SemIR::BranchIf inst) -> void {
  101. llvm::Value* cond = context.GetValue(inst.cond_id);
  102. llvm::BasicBlock* then_block = context.GetBlock(inst.target_id);
  103. llvm::BasicBlock* else_block = context.MakeSyntheticBlock();
  104. context.builder().CreateCondBr(cond, then_block, else_block);
  105. context.builder().SetInsertPoint(else_block);
  106. }
  107. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  108. SemIR::BranchWithArg inst) -> void {
  109. llvm::Value* arg = context.GetValue(inst.arg_id);
  110. SemIR::TypeId arg_type_id =
  111. context.sem_ir().insts().Get(inst.arg_id).type_id();
  112. // Opportunistically avoid creating a BasicBlock that contains just a branch.
  113. // We only do this for a block that we know will only have a single
  114. // predecessor, so that we can correctly populate the predecessors of the
  115. // PHINode.
  116. llvm::BasicBlock* block = context.builder().GetInsertBlock();
  117. llvm::BasicBlock* phi_predecessor = block;
  118. if (block->empty() && context.IsCurrentSyntheticBlock(block) &&
  119. context.TryToReuseBlock(inst.target_id, block)) {
  120. // Reuse this block as the branch target.
  121. phi_predecessor = block->getSinglePredecessor();
  122. CARBON_CHECK(phi_predecessor)
  123. << "Synthetic block did not have a single predecessor";
  124. } else {
  125. context.builder().CreateBr(context.GetBlock(inst.target_id));
  126. }
  127. context.GetBlockArg(inst.target_id, arg_type_id)
  128. ->addIncoming(arg, phi_predecessor);
  129. context.builder().ClearInsertionPoint();
  130. }
  131. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  132. SemIR::Converted inst) -> void {
  133. context.SetLocal(inst_id, context.GetValue(inst.result_id));
  134. }
  135. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  136. SemIR::Deref inst) -> void {
  137. context.SetLocal(inst_id, context.GetValue(inst.pointer_id));
  138. }
  139. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  140. SemIR::FacetTypeAccess /*inst*/) -> void {
  141. context.SetLocal(inst_id, context.GetTypeAsValue());
  142. }
  143. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  144. SemIR::InitializeFrom inst) -> void {
  145. auto storage_type_id = context.sem_ir().insts().Get(inst.dest_id).type_id();
  146. context.FinishInit(storage_type_id, inst.dest_id, inst.src_id);
  147. }
  148. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  149. SemIR::NameRef inst) -> void {
  150. auto type_inst_id = context.sem_ir().types().GetInstId(inst.type_id);
  151. if (type_inst_id == SemIR::InstId::BuiltinNamespaceType) {
  152. return;
  153. }
  154. context.SetLocal(inst_id, context.GetValue(inst.value_id));
  155. }
  156. auto HandleInst(FunctionContext& /*context*/, SemIR::InstId /*inst_id*/,
  157. SemIR::Param /*inst*/) -> void {
  158. CARBON_FATAL() << "Parameters should be lowered by `BuildFunctionDefinition`";
  159. }
  160. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  161. SemIR::Return /*inst*/) -> void {
  162. context.builder().CreateRetVoid();
  163. }
  164. auto HandleInst(FunctionContext& context, SemIR::InstId /*inst_id*/,
  165. SemIR::ReturnExpr inst) -> void {
  166. auto result_type_id = context.sem_ir().insts().Get(inst.expr_id).type_id();
  167. switch (SemIR::InitRepr::ForType(context.sem_ir(), result_type_id).kind) {
  168. case SemIR::InitRepr::None:
  169. // Nothing to return.
  170. context.builder().CreateRetVoid();
  171. return;
  172. case SemIR::InitRepr::InPlace:
  173. context.FinishInit(result_type_id, inst.dest_id, inst.expr_id);
  174. context.builder().CreateRetVoid();
  175. return;
  176. case SemIR::InitRepr::ByCopy:
  177. // The expression produces the value representation for the type.
  178. context.builder().CreateRet(context.GetValue(inst.expr_id));
  179. return;
  180. case SemIR::InitRepr::Incomplete:
  181. CARBON_FATAL() << "Lowering return of incomplete type "
  182. << context.sem_ir().types().GetAsInst(result_type_id);
  183. }
  184. }
  185. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  186. SemIR::SpliceBlock inst) -> void {
  187. context.LowerBlock(inst.block_id);
  188. context.SetLocal(inst_id, context.GetValue(inst.result_id));
  189. }
  190. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  191. SemIR::UnaryOperatorNot inst) -> void {
  192. context.SetLocal(
  193. inst_id, context.builder().CreateNot(context.GetValue(inst.operand_id)));
  194. }
  195. auto HandleInst(FunctionContext& context, SemIR::InstId inst_id,
  196. SemIR::VarStorage inst) -> void {
  197. context.SetLocal(inst_id,
  198. context.builder().CreateAlloca(context.GetType(inst.type_id),
  199. /*ArraySize=*/nullptr));
  200. }
  201. } // namespace Carbon::Lower