diff options
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 109 |
1 files changed, 22 insertions, 87 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index f0d8619faa3..d5ce4870f18 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1422,11 +1422,10 @@ static ConstantEmissionKind checkVarTypeForConstantEmission(QualType type) { } /// Try to emit a reference to the given value without producing it as -/// 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. +/// 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. CodeGenFunction::ConstantEmission CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) { ValueDecl *value = refExpr->getDecl(); @@ -2451,97 +2450,33 @@ 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); - // 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); + // 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); } // FIXME: Handle other kinds of non-odr-use DeclRefExprs. @@ -2577,7 +2512,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) || E->isNonOdrUse() || + assert((ND->isUsed(false) || !isa<VarDecl>(ND) || !E->getLocation().isValid()) && "Should not use decl without marking it used!"); |