mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-04 22:02:52 +01:00
Use static allocas for temporaries. (#5734)
Previously we created allocas for temporaries at whatever point in the output LLVM function we'd reached. This would result in these being dynamic allocas (performing a dynamic stack allocation), which is inefficent and can lead to a stack overflow if it happens in a loop. Switch to putting the allocas in the entry block instead, and instead generate a lifetime start marker when we reach the point where the temporary is introduced. We already did this for local variables; this is just factoring out and reusing that code.
This commit is contained in:
@@ -198,6 +198,50 @@ auto FunctionContext::MakeSyntheticBlock() -> llvm::BasicBlock* {
|
||||
return synthetic_block_;
|
||||
}
|
||||
|
||||
auto FunctionContext::CreateAlloca(llvm::Type* type, const llvm::Twine& name)
|
||||
-> llvm::AllocaInst* {
|
||||
// Position the first alloca right before the start of the executable code in
|
||||
// the function.
|
||||
llvm::AllocaInst* alloca;
|
||||
{
|
||||
llvm::IRBuilderBase::InsertPointGuard guard(builder());
|
||||
|
||||
auto debug_loc = builder().getCurrentDebugLocation();
|
||||
if (after_allocas_) {
|
||||
builder().SetInsertPoint(after_allocas_);
|
||||
} else {
|
||||
builder().SetInsertPointPastAllocas(&llvm_function());
|
||||
}
|
||||
|
||||
// IRBuilder tramples over our debug location when setting the insert point,
|
||||
// so undo that.
|
||||
builder().SetCurrentDebugLocation(debug_loc);
|
||||
|
||||
// Create an alloca for this variable in the entry block.
|
||||
alloca = builder().CreateAlloca(type, /*ArraySize=*/nullptr, name);
|
||||
}
|
||||
|
||||
// Create a lifetime start intrinsic here to indicate where its scope really
|
||||
// begins.
|
||||
auto size = llvm_module().getDataLayout().getTypeAllocSize(type);
|
||||
builder().CreateLifetimeStart(
|
||||
alloca, llvm::ConstantInt::get(llvm_context(), llvm::APInt(64, size)));
|
||||
|
||||
// If we just created the first alloca, there is now definitely at least one
|
||||
// instruction after it -- there is a lifetime start instruction if nothing
|
||||
// else. Use that instruction as our insert point for all future allocas.
|
||||
if (!after_allocas_) {
|
||||
auto loc = alloca->getIterator();
|
||||
++loc;
|
||||
after_allocas_ = &*loc;
|
||||
}
|
||||
|
||||
// TODO: Create a matching `@llvm.lifetime.end` intrinsic call when the
|
||||
// variable goes out of scope.
|
||||
|
||||
return alloca;
|
||||
}
|
||||
|
||||
auto FunctionContext::GetDebugLoc(SemIR::InstId inst_id) -> llvm::DebugLoc {
|
||||
if (!di_subprogram_) {
|
||||
return llvm::DebugLoc();
|
||||
|
||||
Reference in New Issue
Block a user