lowering_function_context.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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 "toolchain/lowering/lowering_function_context.h"
  5. #include "toolchain/semantics/semantics_ir.h"
  6. namespace Carbon::Lower {
  7. FunctionContext::FunctionContext(FileContext& file_context,
  8. llvm::Function* function)
  9. : file_context_(&file_context),
  10. function_(function),
  11. builder_(file_context.llvm_context()) {}
  12. auto FunctionContext::GetBlock(SemIR::NodeBlockId block_id)
  13. -> llvm::BasicBlock* {
  14. llvm::BasicBlock*& entry = blocks_[block_id];
  15. if (!entry) {
  16. entry = llvm::BasicBlock::Create(llvm_context(), "", function_);
  17. }
  18. return entry;
  19. }
  20. auto FunctionContext::TryToReuseBlock(SemIR::NodeBlockId block_id,
  21. llvm::BasicBlock* block) -> bool {
  22. if (!blocks_.insert({block_id, block}).second) {
  23. return false;
  24. }
  25. if (block == synthetic_block_) {
  26. synthetic_block_ = nullptr;
  27. }
  28. return true;
  29. }
  30. auto FunctionContext::GetBlockArg(SemIR::NodeBlockId block_id,
  31. SemIR::TypeId type_id) -> llvm::PHINode* {
  32. llvm::BasicBlock* block = GetBlock(block_id);
  33. // Find the existing phi, if any.
  34. auto phis = block->phis();
  35. if (!phis.empty()) {
  36. CARBON_CHECK(std::next(phis.begin()) == phis.end())
  37. << "Expected at most one phi, found "
  38. << std::distance(phis.begin(), phis.end());
  39. return &*phis.begin();
  40. }
  41. // The number of predecessor slots to reserve.
  42. static constexpr unsigned NumReservedPredecessors = 2;
  43. auto* phi = llvm::PHINode::Create(GetType(type_id), NumReservedPredecessors);
  44. phi->insertInto(block, block->begin());
  45. return phi;
  46. }
  47. auto FunctionContext::CreateSyntheticBlock() -> llvm::BasicBlock* {
  48. synthetic_block_ = llvm::BasicBlock::Create(llvm_context(), "", function_);
  49. return synthetic_block_;
  50. }
  51. auto FunctionContext::FinishInitialization(SemIR::TypeId type_id,
  52. SemIR::NodeId dest_id,
  53. SemIR::NodeId source_id) -> void {
  54. switch (SemIR::GetInitializingRepresentation(semantics_ir(), type_id).kind) {
  55. case SemIR::InitializingRepresentation::None:
  56. case SemIR::InitializingRepresentation::InPlace:
  57. break;
  58. case SemIR::InitializingRepresentation::ByCopy:
  59. CopyValue(type_id, source_id, dest_id);
  60. break;
  61. }
  62. }
  63. auto FunctionContext::CopyValue(SemIR::TypeId type_id, SemIR::NodeId source_id,
  64. SemIR::NodeId dest_id) -> void {
  65. switch (auto rep = SemIR::GetValueRepresentation(semantics_ir(), type_id);
  66. rep.kind) {
  67. case SemIR::ValueRepresentation::None:
  68. break;
  69. case SemIR::ValueRepresentation::Copy:
  70. builder().CreateStore(GetLocalLoaded(source_id), GetLocal(dest_id));
  71. break;
  72. case SemIR::ValueRepresentation::Pointer: {
  73. const auto& layout = llvm_module().getDataLayout();
  74. auto* type = GetType(type_id);
  75. // TODO: Compute known alignment of the source and destination, which may
  76. // be greater than the alignment computed by LLVM.
  77. auto align = layout.getABITypeAlign(type);
  78. // TODO: Attach !tbaa.struct metadata indicating which portions of the
  79. // type we actually need to copy and which are padding.
  80. builder().CreateMemCpy(GetLocal(dest_id), align, GetLocal(source_id),
  81. align, layout.getTypeAllocSize(type));
  82. break;
  83. }
  84. case SemIR::ValueRepresentation::Custom:
  85. CARBON_FATAL() << "TODO: Add support for CopyValue with custom value rep";
  86. }
  87. }
  88. auto FunctionContext::GetLocalLoaded(SemIR::NodeId node_id) -> llvm::Value* {
  89. auto* value = GetLocal(node_id);
  90. if (llvm::isa<llvm::AllocaInst, llvm::GetElementPtrInst>(value)) {
  91. auto* load_type = GetType(semantics_ir().GetNode(node_id).type_id());
  92. return builder().CreateLoad(load_type, value);
  93. } else {
  94. // No load is needed.
  95. return value;
  96. }
  97. }
  98. } // namespace Carbon::Lower