diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-06-14 17:46:37 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-06-14 17:46:37 +0000 |
commit | 24cdcadcc5e875b05bbb70eb123ea4f0a018ee83 (patch) | |
tree | d3e38ecc14d1689d1819eecd220d907e35ff48cf /clang/lib/CodeGen/CGExpr.cpp | |
parent | dcdd12b68c2ae7a30221a30d00a4d64f510e1695 (diff) | |
download | bcm5719-llvm-24cdcadcc5e875b05bbb70eb123ea4f0a018ee83.tar.gz bcm5719-llvm-24cdcadcc5e875b05bbb70eb123ea4f0a018ee83.zip |
C++ DR712 and others: handle non-odr-use resulting from an lvalue-to-rvalue conversion applied to a member access or similar not-quite-trivial lvalue expression.
Summary:
When a variable is named in a context where we can't directly emit a
reference to it (because we don't know for sure that it's going to be
defined, or it's from an enclosing function and not captured, or the
reference might not "work" for some reason), we emit a copy of the
variable as a global and use that for the known-to-be-read-only access.
This reinstates r363295, reverted in r363352, with a fix for PR42276:
we now produce a proper name for a non-odr-use reference to a static
constexpr data member. The name <mangled-name>.const is used in that
case; such names are reserved to the implementation for cases such as
this and should demangle nicely.
Reviewers: rjmccall
Subscribers: jdoerfert, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63157
llvm-svn: 363428
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 109 |
1 files changed, 87 insertions, 22 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index d5ce4870f18..f0d8619faa3 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1422,10 +1422,11 @@ static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) { } /// Try to emit a reference to the given value without producing it as -/// an l-value. This is actually more than an optimization: we can't -/// produce an l-value for variables that we never actually captured -/// in a block or lambda, which means const int variables or constexpr -/// literals or similar. +/// an l-value. This is just an optimization, but it avoids us needing +/// to emit global copies of variables if they're named without triggering +/// a formal use in a context where we can't emit a direct reference to them, +/// for instance if a block or lambda or a member of a local class uses a +/// const int variable or constexpr variable from an enclosing function. CodeGenFunction::ConstantEmission CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { ValueDecl *value = refExpr->getDecl(); @@ -2450,33 +2451,97 @@ static LValue EmitGlobalNamedRegister(const VarDecl *VD, CodeGenModule &CGM) { return LValue::MakeGlobalReg(Address(Ptr, Alignment), VD->getType()); } +/// Determine whether we can emit a reference to \p VD from the current +/// context, despite not necessarily having seen an odr-use of the variable in +/// this context. +static bool canEmitSpuriousReferenceToVariable(CodeGenFunction &CGF, + const DeclRefExpr *E, + const VarDecl *VD, + bool IsConstant) { + // For a variable declared in an enclosing scope, do not emit a spurious + // reference even if we have a capture, as that will emit an unwarranted + // reference to our capture state, and will likely generate worse code than + // emitting a local copy. + if (E->refersToEnclosingVariableOrCapture()) + return false; + + // For a local declaration declared in this function, we can always reference + // it even if we don't have an odr-use. + if (VD->hasLocalStorage()) { + return VD->getDeclContext() == + dyn_cast_or_null<DeclContext>(CGF.CurCodeDecl); + } + + // For a global declaration, we can emit a reference to it if we know + // for sure that we are able to emit a definition of it. + VD = VD->getDefinition(CGF.getContext()); + if (!VD) + return false; + + // Don't emit a spurious reference if it might be to a variable that only + // exists on a different device / target. + // FIXME: This is unnecessarily broad. Check whether this would actually be a + // cross-target reference. + if (CGF.getLangOpts().OpenMP || CGF.getLangOpts().CUDA || + CGF.getLangOpts().OpenCL) { + return false; + } + + // We can emit a spurious reference only if the linkage implies that we'll + // be emitting a non-interposable symbol that will be retained until link + // time. + switch (CGF.CGM.getLLVMLinkageVarDefinition(VD, IsConstant)) { + case llvm::GlobalValue::ExternalLinkage: + case llvm::GlobalValue::LinkOnceODRLinkage: + case llvm::GlobalValue::WeakODRLinkage: + case llvm::GlobalValue::InternalLinkage: + case llvm::GlobalValue::PrivateLinkage: + return true; + default: + return false; + } +} + LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { const NamedDecl *ND = E->getDecl(); QualType T = E->getType(); + assert(E->isNonOdrUse() != NOUR_Unevaluated && + "should not emit an unevaluated operand"); + if (const auto *VD = dyn_cast<VarDecl>(ND)) { // Global Named registers access via intrinsics only if (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl()) return EmitGlobalNamedRegister(VD, CGM); - // A DeclRefExpr for a reference initialized by a constant expression can - // appear without being odr-used. Directly emit the constant initializer. - VD->getAnyInitializer(VD); - if (E->isNonOdrUse() == NOUR_Constant && VD->getType()->isReferenceType()) { - llvm::Constant *Val = - ConstantEmitter(*this).emitAbstract(E->getLocation(), - *VD->evaluateValue(), - VD->getType()); - assert(Val && "failed to emit reference constant expression"); - // FIXME: Eventually we will want to emit vector element references. - - // Should we be using the alignment of the constant pointer we emitted? - CharUnits Alignment = getNaturalTypeAlignment(E->getType(), - /* BaseInfo= */ nullptr, - /* TBAAInfo= */ nullptr, - /* forPointeeType= */ true); - return MakeAddrLValue(Address(Val, Alignment), T, AlignmentSource::Decl); + // If this DeclRefExpr does not constitute an odr-use of the variable, + // we're not permitted to emit a reference to it in general, and it might + // not be captured if capture would be necessary for a use. Emit the + // constant value directly instead. + if (E->isNonOdrUse() == NOUR_Constant && + (VD->getType()->isReferenceType() || + !canEmitSpuriousReferenceToVariable(*this, E, VD, true))) { + VD->getAnyInitializer(VD); + llvm::Constant *Val = ConstantEmitter(*this).emitAbstract( + E->getLocation(), *VD->evaluateValue(), VD->getType()); + assert(Val && "failed to emit constant expression"); + + Address Addr = Address::invalid(); + if (!VD->getType()->isReferenceType()) { + // Spill the constant value to a global. + Addr = CGM.createUnnamedGlobalFrom(*VD, Val, + getContext().getDeclAlign(VD)); + } else { + // Should we be using the alignment of the constant pointer we emitted? + CharUnits Alignment = + getNaturalTypeAlignment(E->getType(), + /* BaseInfo= */ nullptr, + /* TBAAInfo= */ nullptr, + /* forPointeeType= */ true); + Addr = Address(Val, Alignment); + } + return MakeAddrLValue(Addr, T, AlignmentSource::Decl); } // FIXME: Handle other kinds of non-odr-use DeclRefExprs. @@ -2512,7 +2577,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // FIXME: We should be able to assert this for FunctionDecls as well! // FIXME: We should be able to assert this for all DeclRefExprs, not just // those with a valid source location. - assert((ND->isUsed(false) || !isa<VarDecl>(ND) || + assert((ND->isUsed(false) || !isa<VarDecl>(ND) || E->isNonOdrUse() || !E->getLocation().isValid()) && "Should not use decl without marking it used!"); |