lowering_handle.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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/STLExtras.h"
  5. #include "llvm/ADT/Sequence.h"
  6. #include "toolchain/lowering/lowering_function_context.h"
  7. #include "toolchain/semantics/semantics_node_kind.h"
  8. namespace Carbon {
  9. auto LoweringHandleInvalid(LoweringFunctionContext& /*context*/,
  10. SemIR::NodeId /*node_id*/, SemIR::Node /*node*/)
  11. -> void {
  12. llvm_unreachable("never in actual IR");
  13. }
  14. auto LoweringHandleCrossReference(LoweringFunctionContext& /*context*/,
  15. SemIR::NodeId /*node_id*/, SemIR::Node node)
  16. -> void {
  17. CARBON_FATAL() << "TODO: Add support: " << node;
  18. }
  19. auto LoweringHandleAddressOf(LoweringFunctionContext& context,
  20. SemIR::NodeId node_id, SemIR::Node node) -> void {
  21. context.SetLocal(node_id, context.GetLocal(node.GetAsAddressOf()));
  22. }
  23. auto LoweringHandleArrayIndex(LoweringFunctionContext& context,
  24. SemIR::NodeId node_id, SemIR::Node node) -> void {
  25. auto [array_node_id, index_node_id] = node.GetAsArrayIndex();
  26. auto* array_value = context.GetLocal(array_node_id);
  27. auto* llvm_type =
  28. context.GetType(context.semantics_ir().GetNode(array_node_id).type_id());
  29. auto index_node = context.semantics_ir().GetNode(index_node_id);
  30. llvm::Value* array_element_value;
  31. if (index_node.kind() == SemIR::NodeKind::IntegerLiteral) {
  32. const auto index = context.semantics_ir()
  33. .GetIntegerLiteral(index_node.GetAsIntegerLiteral())
  34. .getZExtValue();
  35. array_element_value = context.GetIndexFromStructOrArray(
  36. llvm_type, array_value, index, "array.index");
  37. } else {
  38. auto* index = context.builder().CreateLoad(llvm_type->getArrayElementType(),
  39. context.GetLocal(index_node_id));
  40. // TODO: Handle return value or call such as `F()[a]`.
  41. array_element_value = context.builder().CreateInBoundsGEP(
  42. llvm_type, array_value, index, "array.index");
  43. }
  44. context.SetLocal(node_id, array_element_value);
  45. }
  46. auto LoweringHandleArrayValue(LoweringFunctionContext& context,
  47. SemIR::NodeId node_id, SemIR::Node node) -> void {
  48. auto* llvm_type = context.GetType(node.type_id());
  49. auto* alloca =
  50. context.builder().CreateAlloca(llvm_type, /*ArraySize=*/nullptr, "array");
  51. context.SetLocal(node_id, alloca);
  52. auto tuple_node_id = node.GetAsArrayValue();
  53. auto* tuple_value = context.GetLocal(tuple_node_id);
  54. auto* tuple_type =
  55. context.GetType(context.semantics_ir().GetNode(tuple_node_id).type_id());
  56. for (auto i : llvm::seq(llvm_type->getArrayNumElements())) {
  57. llvm::Value* array_element_value = context.GetIndexFromStructOrArray(
  58. tuple_type, tuple_value, i, "array.element");
  59. if (tuple_value->getType()->isPointerTy()) {
  60. array_element_value = context.builder().CreateLoad(
  61. llvm_type->getArrayElementType(), array_element_value);
  62. }
  63. // Initializing the array with values.
  64. context.builder().CreateStore(
  65. array_element_value,
  66. context.builder().CreateStructGEP(llvm_type, alloca, i));
  67. }
  68. }
  69. auto LoweringHandleAssign(LoweringFunctionContext& context,
  70. SemIR::NodeId /*node_id*/, SemIR::Node node) -> void {
  71. auto [storage_id, value_id] = node.GetAsAssign();
  72. context.builder().CreateStore(context.GetLocalLoaded(value_id),
  73. context.GetLocal(storage_id));
  74. }
  75. auto LoweringHandleBinaryOperatorAdd(LoweringFunctionContext& /*context*/,
  76. SemIR::NodeId /*node_id*/,
  77. SemIR::Node node) -> void {
  78. CARBON_FATAL() << "TODO: Add support: " << node;
  79. }
  80. auto LoweringHandleBindName(LoweringFunctionContext& /*context*/,
  81. SemIR::NodeId /*node_id*/, SemIR::Node /*node*/)
  82. -> void {
  83. // Probably need to do something here, but not necessary for now.
  84. }
  85. auto LoweringHandleBlockArg(LoweringFunctionContext& context,
  86. SemIR::NodeId node_id, SemIR::Node node) -> void {
  87. SemIR::NodeBlockId block_id = node.GetAsBlockArg();
  88. context.SetLocal(node_id, context.GetBlockArg(block_id, node.type_id()));
  89. }
  90. auto LoweringHandleBoolLiteral(LoweringFunctionContext& context,
  91. SemIR::NodeId node_id, SemIR::Node node)
  92. -> void {
  93. llvm::Value* v = llvm::ConstantInt::get(context.builder().getInt1Ty(),
  94. node.GetAsBoolLiteral().index);
  95. context.SetLocal(node_id, v);
  96. }
  97. auto LoweringHandleBranch(LoweringFunctionContext& context,
  98. SemIR::NodeId /*node_id*/, SemIR::Node node) -> void {
  99. SemIR::NodeBlockId target_block_id = node.GetAsBranch();
  100. // Opportunistically avoid creating a BasicBlock that contains just a branch.
  101. llvm::BasicBlock* block = context.builder().GetInsertBlock();
  102. if (block->empty() && context.TryToReuseBlock(target_block_id, block)) {
  103. // Reuse this block as the branch target.
  104. } else {
  105. context.builder().CreateBr(context.GetBlock(target_block_id));
  106. }
  107. context.builder().ClearInsertionPoint();
  108. }
  109. auto LoweringHandleBranchIf(LoweringFunctionContext& context,
  110. SemIR::NodeId /*node_id*/, SemIR::Node node)
  111. -> void {
  112. auto [target_block_id, cond_id] = node.GetAsBranchIf();
  113. llvm::Value* cond = context.GetLocalLoaded(cond_id);
  114. llvm::BasicBlock* then_block = context.GetBlock(target_block_id);
  115. llvm::BasicBlock* else_block = context.CreateSyntheticBlock();
  116. context.builder().CreateCondBr(cond, then_block, else_block);
  117. context.builder().SetInsertPoint(else_block);
  118. }
  119. auto LoweringHandleBranchWithArg(LoweringFunctionContext& context,
  120. SemIR::NodeId /*node_id*/, SemIR::Node node)
  121. -> void {
  122. auto [target_block_id, arg_id] = node.GetAsBranchWithArg();
  123. llvm::Value* arg = context.GetLocalLoaded(arg_id);
  124. SemIR::TypeId arg_type_id = context.semantics_ir().GetNode(arg_id).type_id();
  125. // Opportunistically avoid creating a BasicBlock that contains just a branch.
  126. // We only do this for a block that we know will only have a single
  127. // predecessor, so that we can correctly populate the predecessors of the
  128. // PHINode.
  129. llvm::BasicBlock* block = context.builder().GetInsertBlock();
  130. llvm::BasicBlock* phi_predecessor = block;
  131. if (block->empty() && context.IsCurrentSyntheticBlock(block) &&
  132. context.TryToReuseBlock(target_block_id, block)) {
  133. // Reuse this block as the branch target.
  134. phi_predecessor = block->getSinglePredecessor();
  135. CARBON_CHECK(phi_predecessor)
  136. << "Synthetic block did not have a single predecessor";
  137. } else {
  138. context.builder().CreateBr(context.GetBlock(target_block_id));
  139. }
  140. context.GetBlockArg(target_block_id, arg_type_id)
  141. ->addIncoming(arg, phi_predecessor);
  142. context.builder().ClearInsertionPoint();
  143. }
  144. auto LoweringHandleBuiltin(LoweringFunctionContext& /*context*/,
  145. SemIR::NodeId /*node_id*/, SemIR::Node node)
  146. -> void {
  147. CARBON_FATAL() << "TODO: Add support: " << node;
  148. }
  149. auto LoweringHandleCall(LoweringFunctionContext& context, SemIR::NodeId node_id,
  150. SemIR::Node node) -> void {
  151. auto [refs_id, function_id] = node.GetAsCall();
  152. auto* function = context.GetFunction(function_id);
  153. std::vector<llvm::Value*> args;
  154. for (auto ref_id : context.semantics_ir().GetNodeBlock(refs_id)) {
  155. args.push_back(context.GetLocalLoaded(ref_id));
  156. }
  157. if (function->getReturnType()->isVoidTy()) {
  158. context.builder().CreateCall(function, args);
  159. // TODO: use empty tuple type.
  160. // TODO: don't create the empty tuple if the call does not get assigned.
  161. context.SetLocal(node_id, context.builder().CreateAlloca(
  162. llvm::StructType::get(context.llvm_context()),
  163. /*ArraySize=*/nullptr, "call.result"));
  164. } else {
  165. context.SetLocal(node_id, context.builder().CreateCall(
  166. function, args, function->getName()));
  167. }
  168. }
  169. auto LoweringHandleDereference(LoweringFunctionContext& context,
  170. SemIR::NodeId node_id, SemIR::Node node)
  171. -> void {
  172. context.SetLocal(node_id, context.GetLocal(node.GetAsDereference()));
  173. }
  174. auto LoweringHandleFunctionDeclaration(LoweringFunctionContext& /*context*/,
  175. SemIR::NodeId /*node_id*/,
  176. SemIR::Node node) -> void {
  177. CARBON_FATAL()
  178. << "Should not be encountered. If that changes, we may want to change "
  179. "higher-level logic to skip them rather than calling this. "
  180. << node;
  181. }
  182. auto LoweringHandleIntegerLiteral(LoweringFunctionContext& context,
  183. SemIR::NodeId node_id, SemIR::Node node)
  184. -> void {
  185. llvm::APInt i =
  186. context.semantics_ir().GetIntegerLiteral(node.GetAsIntegerLiteral());
  187. // TODO: This won't offer correct semantics, but seems close enough for now.
  188. llvm::Value* v =
  189. llvm::ConstantInt::get(context.builder().getInt32Ty(), i.getSExtValue());
  190. context.SetLocal(node_id, v);
  191. }
  192. auto LoweringHandleNamespace(LoweringFunctionContext& /*context*/,
  193. SemIR::NodeId /*node_id*/, SemIR::Node /*node*/)
  194. -> void {
  195. // No action to take.
  196. }
  197. auto LoweringHandleParameter(LoweringFunctionContext& /*context*/,
  198. SemIR::NodeId /*node_id*/, SemIR::Node /*node*/)
  199. -> void {
  200. CARBON_FATAL() << "Parameters should be lowered by `BuildFunctionDefinition`";
  201. }
  202. auto LoweringHandleRealLiteral(LoweringFunctionContext& context,
  203. SemIR::NodeId node_id, SemIR::Node node)
  204. -> void {
  205. SemIR::RealLiteral real =
  206. context.semantics_ir().GetRealLiteral(node.GetAsRealLiteral());
  207. // TODO: This will probably have overflow issues, and should be fixed.
  208. double val =
  209. real.mantissa.getSExtValue() *
  210. std::pow((real.is_decimal ? 10 : 2), real.exponent.getSExtValue());
  211. llvm::APFloat llvm_val(val);
  212. context.SetLocal(node_id, llvm::ConstantFP::get(
  213. context.builder().getDoubleTy(), llvm_val));
  214. }
  215. auto LoweringHandleReturn(LoweringFunctionContext& context,
  216. SemIR::NodeId /*node_id*/, SemIR::Node /*node*/)
  217. -> void {
  218. context.builder().CreateRetVoid();
  219. }
  220. auto LoweringHandleReturnExpression(LoweringFunctionContext& context,
  221. SemIR::NodeId /*node_id*/, SemIR::Node node)
  222. -> void {
  223. SemIR::NodeId expr_id = node.GetAsReturnExpression();
  224. context.builder().CreateRet(context.GetLocalLoaded(expr_id));
  225. }
  226. auto LoweringHandleStringLiteral(LoweringFunctionContext& /*context*/,
  227. SemIR::NodeId /*node_id*/, SemIR::Node node)
  228. -> void {
  229. CARBON_FATAL() << "TODO: Add support: " << node;
  230. }
  231. auto LoweringHandleStructAccess(LoweringFunctionContext& context,
  232. SemIR::NodeId node_id, SemIR::Node node)
  233. -> void {
  234. auto [struct_id, member_index] = node.GetAsStructAccess();
  235. auto struct_type_id = context.semantics_ir().GetNode(struct_id).type_id();
  236. auto* llvm_type = context.GetType(struct_type_id);
  237. // Get type information for member names.
  238. auto type_refs = context.semantics_ir().GetNodeBlock(
  239. context.semantics_ir()
  240. .GetNode(context.semantics_ir().GetType(struct_type_id))
  241. .GetAsStructType());
  242. auto [field_name_id, field_type_id] =
  243. context.semantics_ir()
  244. .GetNode(type_refs[member_index.index])
  245. .GetAsStructTypeField();
  246. auto member_name = context.semantics_ir().GetString(field_name_id);
  247. auto* gep = context.builder().CreateStructGEP(
  248. llvm_type, context.GetLocal(struct_id), member_index.index, member_name);
  249. context.SetLocal(node_id, gep);
  250. }
  251. auto LoweringHandleTupleIndex(LoweringFunctionContext& context,
  252. SemIR::NodeId node_id, SemIR::Node node) -> void {
  253. auto [tuple_node_id, index_node_id] = node.GetAsTupleIndex();
  254. auto* tuple_value = context.GetLocal(tuple_node_id);
  255. auto index_node = context.semantics_ir().GetNode(index_node_id);
  256. const auto index = context.semantics_ir()
  257. .GetIntegerLiteral(index_node.GetAsIntegerLiteral())
  258. .getZExtValue();
  259. auto* llvm_type =
  260. context.GetType(context.semantics_ir().GetNode(tuple_node_id).type_id());
  261. context.SetLocal(node_id, context.GetIndexFromStructOrArray(
  262. llvm_type, tuple_value, index, "tuple.index"));
  263. }
  264. auto LoweringHandleTupleValue(LoweringFunctionContext& context,
  265. SemIR::NodeId node_id, SemIR::Node node) -> void {
  266. auto* llvm_type = context.GetType(node.type_id());
  267. auto* alloca =
  268. context.builder().CreateAlloca(llvm_type, /*ArraySize=*/nullptr, "tuple");
  269. context.SetLocal(node_id, alloca);
  270. auto refs = context.semantics_ir().GetNodeBlock(node.GetAsTupleValue());
  271. for (auto [i, ref] : llvm::enumerate(refs)) {
  272. auto* gep = context.builder().CreateStructGEP(llvm_type, alloca, i);
  273. context.builder().CreateStore(context.GetLocal(ref), gep);
  274. }
  275. }
  276. auto LoweringHandleStructTypeField(LoweringFunctionContext& /*context*/,
  277. SemIR::NodeId /*node_id*/,
  278. SemIR::Node /*node*/) -> void {
  279. // No action to take.
  280. }
  281. auto LoweringHandleStructValue(LoweringFunctionContext& context,
  282. SemIR::NodeId node_id, SemIR::Node node)
  283. -> void {
  284. auto* llvm_type = context.GetType(node.type_id());
  285. auto* alloca = context.builder().CreateAlloca(
  286. llvm_type, /*ArraySize=*/nullptr, "struct");
  287. context.SetLocal(node_id, alloca);
  288. auto refs = context.semantics_ir().GetNodeBlock(node.GetAsStructValue());
  289. // Get type information for member names.
  290. auto type_refs = context.semantics_ir().GetNodeBlock(
  291. context.semantics_ir()
  292. .GetNode(context.semantics_ir().GetType(node.type_id()))
  293. .GetAsStructType());
  294. for (auto [i, ref, type_ref] : llvm::enumerate(refs, type_refs)) {
  295. auto [field_name_id, field_type_id] =
  296. context.semantics_ir().GetNode(type_ref).GetAsStructTypeField();
  297. auto member_name = context.semantics_ir().GetString(field_name_id);
  298. auto* gep =
  299. context.builder().CreateStructGEP(llvm_type, alloca, i, member_name);
  300. context.builder().CreateStore(context.GetLocal(ref), gep);
  301. }
  302. }
  303. auto LoweringHandleStubReference(LoweringFunctionContext& context,
  304. SemIR::NodeId node_id, SemIR::Node node)
  305. -> void {
  306. context.SetLocal(node_id, context.GetLocal(node.GetAsStubReference()));
  307. }
  308. auto LoweringHandleUnaryOperatorNot(LoweringFunctionContext& context,
  309. SemIR::NodeId node_id, SemIR::Node node)
  310. -> void {
  311. context.SetLocal(node_id, context.builder().CreateNot(context.GetLocal(
  312. node.GetAsUnaryOperatorNot())));
  313. }
  314. auto LoweringHandleVarStorage(LoweringFunctionContext& context,
  315. SemIR::NodeId node_id, SemIR::Node node) -> void {
  316. // TODO: Eventually this name will be optional, and we'll want to provide
  317. // something like `var` as a default. However, that's not possible right now
  318. // so cannot be tested.
  319. auto name = context.semantics_ir().GetString(node.GetAsVarStorage());
  320. auto* alloca = context.builder().CreateAlloca(context.GetType(node.type_id()),
  321. /*ArraySize=*/nullptr, name);
  322. context.SetLocal(node_id, alloca);
  323. }
  324. } // namespace Carbon