mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 16:41:06 +03:00
Add a matching call to llvm.va_end when llvm.va_start was called.
Resolves #1744
This commit is contained in:
parent
9dbd583707
commit
63fba4efdb
2 changed files with 72 additions and 0 deletions
|
@ -1011,6 +1011,17 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
// copy _arguments to a memory location
|
// copy _arguments to a memory location
|
||||||
irFunc->_arguments =
|
irFunc->_arguments =
|
||||||
DtoAllocaDump(irFunc->_arguments, 0, "_arguments_mem");
|
DtoAllocaDump(irFunc->_arguments, 0, "_arguments_mem");
|
||||||
|
|
||||||
|
// Push cleanup block that calls va_end to match the va_start call.
|
||||||
|
{
|
||||||
|
auto *vaendBB =
|
||||||
|
llvm::BasicBlock::Create(gIR->context(), "vaend", gIR->topfunc());
|
||||||
|
IRScope saveScope = gIR->scope();
|
||||||
|
gIR->scope() = IRScope(vaendBB);
|
||||||
|
gIR->ir->CreateCall(GET_INTRINSIC_DECL(vaend), llAp);
|
||||||
|
funcGen.scopes.pushCleanup(vaendBB, gIR->scopebb());
|
||||||
|
gIR->scope() = saveScope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
funcGen.pgo.emitCounterIncrement(fd->fbody);
|
funcGen.pgo.emitCounterIncrement(fd->fbody);
|
||||||
|
@ -1019,6 +1030,17 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
|
||||||
// output function body
|
// output function body
|
||||||
Statement_toIR(fd->fbody, gIR);
|
Statement_toIR(fd->fbody, gIR);
|
||||||
|
|
||||||
|
// D varargs: emit the cleanup block that calls va_end.
|
||||||
|
if (f->linkage == LINKd && f->varargs == 1) {
|
||||||
|
if (!gIR->scopereturned()) {
|
||||||
|
if (!funcGen.retBlock)
|
||||||
|
funcGen.retBlock = gIR->insertBB("return");
|
||||||
|
funcGen.scopes.runCleanups(0, funcGen.retBlock);
|
||||||
|
gIR->scope() = IRScope(funcGen.retBlock);
|
||||||
|
}
|
||||||
|
funcGen.scopes.popCleanups(0);
|
||||||
|
}
|
||||||
|
|
||||||
llvm::BasicBlock *bb = gIR->scopebb();
|
llvm::BasicBlock *bb = gIR->scopebb();
|
||||||
if (pred_begin(bb) == pred_end(bb) &&
|
if (pred_begin(bb) == pred_end(bb) &&
|
||||||
bb != &bb->getParent()->getEntryBlock()) {
|
bb != &bb->getParent()->getEntryBlock()) {
|
||||||
|
|
50
tests/codegen/vastart_vaend_gh1744.d
Normal file
50
tests/codegen/vastart_vaend_gh1744.d
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// Test that va_end is called when returning from a variadic function.
|
||||||
|
|
||||||
|
// Because the IR is kind of ugly, testing at -O0 is very brittle. Instead we
|
||||||
|
// test that at -O3, LLVM was able to analyse the function correctly and
|
||||||
|
// optimize-out the va_start and va_end calls and remove the call to
|
||||||
|
// return_two (Github #1744).
|
||||||
|
// The optimization (removing back-to-back calls to va_start and va_end) only
|
||||||
|
// happens from LLVM >= 3.9.
|
||||||
|
// REQUIRES: atleast_llvm309
|
||||||
|
// RUN: %ldc %s -c -output-ll -O3 -of=%t.O3.ll \
|
||||||
|
// RUN: && FileCheck %s --check-prefix OPT3 < %t.O3.ll
|
||||||
|
|
||||||
|
module mod;
|
||||||
|
|
||||||
|
// OPT3-LABEL: define {{.*}} @{{.*}}void_three_return_paths
|
||||||
|
void void_three_return_paths(int a, ...)
|
||||||
|
{
|
||||||
|
// OPT3: call void @llvm.va_start({{.*}} %[[VA:[0-9]+]])
|
||||||
|
// OPT3-NOT: return_two
|
||||||
|
return_two();
|
||||||
|
|
||||||
|
if (a > 0)
|
||||||
|
{
|
||||||
|
throw new Exception("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are two control paths (normal return, exception resume) that
|
||||||
|
// should call va_end.
|
||||||
|
// OPT3: call void @llvm.va_end({{.*}} %[[VA]])
|
||||||
|
// OPT3: call void @llvm.va_end({{.*}} %[[VA]])
|
||||||
|
}
|
||||||
|
|
||||||
|
// OPT3-LABEL: define {{.*}} @{{.*}}return_two
|
||||||
|
int return_two(...)
|
||||||
|
{
|
||||||
|
// OPT3-NOT: va_start
|
||||||
|
// OPT3-NOT: va_end
|
||||||
|
// OPT3: ret i32 2
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Github #1744:
|
||||||
|
// OPT3-LABEL: define {{.*}} @{{.*}}two_four
|
||||||
|
int two_four()
|
||||||
|
{
|
||||||
|
// OPT3-NOT: return_two
|
||||||
|
// OPT3: ret i32 8
|
||||||
|
return return_two() * 4;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue