handle.cpp 9.1 KB

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