Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model return slot as parameter in lowering #4457

Merged
merged 7 commits into from
Nov 1, 2024

Conversation

geoffromer
Copy link
Contributor

No description provided.

Copy link
Contributor

@zygoloid zygoloid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a multiple-ownership issue here: splice_block owns its block, but the decl block is already owned by the function_decl instruction. In practice this is resulting in the decl block being printed twice in SemIR.

Given that different function_decls for the same function will have different decl blocks, I don't think we want to just transfer ownership from the function_decl to the Function entity. I think either of these options could be reasonable:

  • Instead of splice_block, use a different instruction that invokes another block without splicing it. We'd need some way of naming the block owned by the function_decl -- maybe the instruction could name the function_decl instruction itself?
  • Omit the splice_block entirely and instead make lowering first lower the decl block of the definition and then the function body.

I don't think I have a strong preference between these, but the latter option would avoid the need to add a new kind of special-purpose instruction.

Copy link
Contributor Author

@geoffromer geoffromer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Omit the splice_block entirely and instead make lowering first lower the decl block of the definition and then the function body.

I initially tried something like that, but got stuck on how to give the lowered decl block a suitable terminator. I just tried again, and I think I found a way to make it work without too much mess.

toolchain/lower/file_context.cpp Show resolved Hide resolved
toolchain/lower/file_context.cpp Show resolved Hide resolved
toolchain/lower/file_context.cpp Show resolved Hide resolved
toolchain/lower/file_context.cpp Show resolved Hide resolved
toolchain/lower/file_context.cpp Show resolved Hide resolved
Comment on lines 413 to 424
auto* llvm_decl_block = lower_block(decl_block_id);

// If the decl block is empty, reuse it as the first body block. We don't do
// this when the decl block is non-empty so that any branches back to the
// first body block don't also re-execute the decl.
if (llvm_decl_block->empty()) {
CARBON_CHECK(function_lowering.TryToReuseBlock(body_block_ids.front(),
llvm_decl_block));
} else {
function_lowering.builder().SetInsertPoint(llvm_decl_block);
function_lowering.builder().CreateBr(
function_lowering.GetBlock(body_block_ids.front()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

Suggested change
auto* llvm_decl_block = lower_block(decl_block_id);
// If the decl block is empty, reuse it as the first body block. We don't do
// this when the decl block is non-empty so that any branches back to the
// first body block don't also re-execute the decl.
if (llvm_decl_block->empty()) {
CARBON_CHECK(function_lowering.TryToReuseBlock(body_block_ids.front(),
llvm_decl_block));
} else {
function_lowering.builder().SetInsertPoint(llvm_decl_block);
function_lowering.builder().CreateBr(
function_lowering.GetBlock(body_block_ids.front()));
// If the decl block is empty, reuse it as the first body block. We don't do
// this when the decl block is non-empty so that any branches back to the
// first body block don't also re-execute the decl.
llvm::BasicBlock* block = context.builder().GetInsertBlock();
if (block->empty() &&
function_lowering.TryToReuseBlock(body_block_ids.front(),
block))) {
// Reuse this block as the first block of the function body.
} else {
function_lowering.builder().CreateBr(
function_lowering.GetBlock(body_block_ids.front()));

to make this more similar to the other uses of TryToReuseBlock and handle the possibility that we somehow generate multiple LLVM basic blocks while lowering the decl block. (We shouldn't need to SetInsertionPoint because it should still be in the llvm_decl_block.) I wonder if we should actually factor out a function to do this block-reuse or branch process -- we seem to do the same thing three times now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, with some tweaks. I assume removing the first lower_block call was an accident?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, oops, I just meant to remove the variable not the initializer.

@zygoloid zygoloid added this pull request to the merge queue Nov 1, 2024
Merged via the queue into carbon-language:trunk with commit ac5cc33 Nov 1, 2024
8 checks passed
@geoffromer geoffromer deleted the lower branch November 4, 2024 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants