diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 50e9d40001..75794ca3a3 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -858,6 +858,64 @@ void DtoResolveVariable(VarDeclaration *vd) { } } +namespace { +bool eval(VarDeclaration *vd, Expression *e) { + + auto ve = e->isVarExp(); + if (!ve) { + return false; + } + VarDeclaration *v = nullptr; + if (ve) + v = ve->var->isVarDeclaration(); + return vd == v; +} +bool walk(VarDeclaration *vd, CommaExp *ce) { + IF_LOG Logger::println("ce = %s", ce->toChars()); + if (auto ce2 = ce->e2->isCommaExp()) { + if (walk(vd, ce2)) + return true; + } + if (auto ce1 = ce->e1->isCommaExp()) { + if (walk(vd, ce1)) + return true; + } + if (eval(vd, ce->e2)) + return true; + if (eval(vd, ce->e1)) + return true; + return false; +} +bool varIsSret(VarDeclaration *vd, IrFunction *f) { + if (!f->sretArg) + return false; + auto fd = f->decl; + auto rets = fd->returns; + if (!rets) + return false; +#if LDC_LLVM_VER >= 1800 + #define startswith starts_with +#endif + llvm::StringRef name = vd->ident->toChars(); + if (name.startswith("__tmpfordtor") ||name.startswith("__sl")) { + return true; + } +#if LDC_LLVM_VER >= 1800 + #undef startswith +#endif + for (d_size_t i = 0; i < rets->length; i++) { + auto rs = (*rets)[i]; + Expression *e = rs->exp; + CommaExp *ce = e->isCommaExp(); + if (ce) { + if (walk(vd, ce)) return true; + } + if (eval(vd, e)) + return true; + } + return false; +} +} /****************************************************************************** * DECLARATION EXP HELPER ******************************************************************************/ @@ -906,29 +964,22 @@ void DtoVarDeclaration(VarDeclaration *vd) { // We also allocate a variable for zero-sized variables, because they are technically not `null` when loaded. // The x86_64 ABI "loads" zero-sized function arguments, and without an allocation ASan will report an error (Github #4816). - llvm::Value *allocainst; - bool isRealAlloca = false; LLType *lltype = DtoType(type); // void for noreturn if (lltype->isVoidTy()) { - allocainst = getNullPtr(); - } else if (type != vd->type) { - allocainst = DtoAlloca(type, vd->toChars()); - isRealAlloca = true; - } else { - allocainst = DtoAlloca(vd, vd->toChars()); - isRealAlloca = true; + irLocal->value = getNullPtr(); } - - irLocal->value = allocainst; - - if (!lltype->isVoidTy()) + else { + auto allocainst = type != vd->type ? DtoAlloca(type, vd->toChars()) + : DtoAlloca(vd, vd->toChars()); + irLocal->value = allocainst; + gIR->DBuilder.EmitLocalVariable(allocainst, vd); - - // Lifetime annotation is only valid on alloca. - if (isRealAlloca) { + // The lifetime of a stack variable starts from the point it is declared - gIR->funcGen().localVariableLifetimeAnnotator.addLocalVariable( - allocainst, DtoConstUlong(size(type))); + if (!vd->isParameter() && !varIsSret(vd, gIR->func())) { + gIR->funcGen().localVariableLifetimeAnnotator.addLocalVariable( + allocainst, DtoConstUlong(size(type))); + } } } diff --git a/gen/variable_lifetime.cpp b/gen/variable_lifetime.cpp index cf21104de2..a6659f6ec3 100644 --- a/gen/variable_lifetime.cpp +++ b/gen/variable_lifetime.cpp @@ -37,7 +37,7 @@ LocalVariableLifetimeAnnotator::LocalVariableLifetimeAnnotator(IRState &irs) void LocalVariableLifetimeAnnotator::pushScope() { scopes.emplace_back(); } -void LocalVariableLifetimeAnnotator::addLocalVariable(llvm::Value *address, +void LocalVariableLifetimeAnnotator::addLocalVariable(llvm::AllocaInst *address, llvm::Value *size) { assert(address); assert(size); @@ -52,8 +52,13 @@ void LocalVariableLifetimeAnnotator::addLocalVariable(llvm::Value *address, scopes.back().variables.emplace_back(size, address); // Emit lifetime start - irs.CreateCallOrInvoke(getLLVMLifetimeStartFn(), {size, address}, "", - true /*nothrow*/); + irs.CreateCallOrInvoke(getLLVMLifetimeStartFn(), +#if LDC_LLVM_VER >= 2100 + {address}, +#else + {size, address}, +#endif + "", true /*nothrow*/); } // Emits end-of-lifetime annotation for all variables in current scope. @@ -67,8 +72,14 @@ void LocalVariableLifetimeAnnotator::popScope() { assert(address); - irs.CreateCallOrInvoke(getLLVMLifetimeEndFn(), {size, address}, "", - true /*nothrow*/); + irs.CreateCallOrInvoke(getLLVMLifetimeEndFn(), +#if LDC_LLVM_VER >= 2100 + {address}, +#else + {size, address}, +#endif + "", true /*nothrow*/); + } scopes.pop_back(); } diff --git a/gen/variable_lifetime.h b/gen/variable_lifetime.h index f482030c9a..2dcf02090f 100644 --- a/gen/variable_lifetime.h +++ b/gen/variable_lifetime.h @@ -21,12 +21,13 @@ namespace llvm { class Function; class Type; class Value; +class AllocaInst; } struct IRState; struct LocalVariableLifetimeAnnotator { struct LocalVariableScope { - std::vector> variables; + std::vector> variables; }; /// Stack of scopes, each scope can have multiple variables. std::vector scopes; @@ -52,5 +53,5 @@ struct LocalVariableLifetimeAnnotator { void popScope(); /// Register a new local variable for lifetime annotation. - void addLocalVariable(llvm::Value *address, llvm::Value *size); + void addLocalVariable(llvm::AllocaInst *address, llvm::Value *size); };