diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGDecl.cpp | 80 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 109 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.h | 7 |
3 files changed, 144 insertions, 52 deletions
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index db18ac49c6e..233212c76be 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1077,17 +1077,16 @@ static llvm::Constant *constWithPadding(CodeGenModule &CGM, IsPattern isPattern, return constant; } -static Address createUnnamedGlobalFrom(CodeGenModule &CGM, const VarDecl &D, - CGBuilderTy &Builder, - llvm::Constant *Constant, - CharUnits Align) { +Address CodeGenModule::createUnnamedGlobalFrom(const VarDecl &D, + llvm::Constant *Constant, + CharUnits Align) { auto FunctionName = [&](const DeclContext *DC) -> std::string { if (const auto *FD = dyn_cast<FunctionDecl>(DC)) { if (const auto *CC = dyn_cast<CXXConstructorDecl>(FD)) return CC->getNameAsString(); if (const auto *CD = dyn_cast<CXXDestructorDecl>(FD)) return CD->getNameAsString(); - return CGM.getMangledName(FD); + return getMangledName(FD); } else if (const auto *OM = dyn_cast<ObjCMethodDecl>(DC)) { return OM->getNameAsString(); } else if (isa<BlockDecl>(DC)) { @@ -1095,26 +1094,47 @@ static Address createUnnamedGlobalFrom(CodeGenModule &CGM, const VarDecl &D, } else if (isa<CapturedDecl>(DC)) { return "<captured>"; } else { - llvm::llvm_unreachable_internal("expected a function or method"); + llvm_unreachable("expected a function or method"); } }; - auto *Ty = Constant->getType(); - bool isConstant = true; - llvm::GlobalVariable *InsertBefore = nullptr; - unsigned AS = CGM.getContext().getTargetAddressSpace( - CGM.getStringLiteralAddressSpace()); - llvm::GlobalVariable *GV = new llvm::GlobalVariable( - CGM.getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage, - Constant, - "__const." + FunctionName(D.getParentFunctionOrMethod()) + "." + - D.getName(), - InsertBefore, llvm::GlobalValue::NotThreadLocal, AS); - GV->setAlignment(Align.getQuantity()); - GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - - Address SrcPtr = Address(GV, Align); - llvm::Type *BP = llvm::PointerType::getInt8PtrTy(CGM.getLLVMContext(), AS); + // Form a simple per-variable cache of these values in case we find we + // want to reuse them. + llvm::GlobalVariable *&CacheEntry = InitializerConstants[&D]; + if (!CacheEntry || CacheEntry->getInitializer() != Constant) { + auto *Ty = Constant->getType(); + bool isConstant = true; + llvm::GlobalVariable *InsertBefore = nullptr; + unsigned AS = + getContext().getTargetAddressSpace(getStringLiteralAddressSpace()); + std::string Name; + if (D.hasGlobalStorage()) + Name = getMangledName(&D).str() + ".const"; + else if (const DeclContext *DC = D.getParentFunctionOrMethod()) + Name = ("__const." + FunctionName(DC) + "." + D.getName()).str(); + else + llvm_unreachable("local variable has no parent function or method"); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage, + Constant, Name, InsertBefore, llvm::GlobalValue::NotThreadLocal, AS); + GV->setAlignment(Align.getQuantity()); + GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + CacheEntry = GV; + } else if (CacheEntry->getAlignment() < Align.getQuantity()) { + CacheEntry->setAlignment(Align.getQuantity()); + } + + return Address(CacheEntry, Align); +} + +static Address createUnnamedGlobalForMemcpyFrom(CodeGenModule &CGM, + const VarDecl &D, + CGBuilderTy &Builder, + llvm::Constant *Constant, + CharUnits Align) { + Address SrcPtr = CGM.createUnnamedGlobalFrom(D, Constant, Align); + llvm::Type *BP = llvm::PointerType::getInt8PtrTy(CGM.getLLVMContext(), + SrcPtr.getAddressSpace()); if (SrcPtr.getType() != BP) SrcPtr = Builder.CreateBitCast(SrcPtr, BP); return SrcPtr; @@ -1197,10 +1217,10 @@ static void emitStoresForConstant(CodeGenModule &CGM, const VarDecl &D, } // Copy from a global. - Builder.CreateMemCpy( - Loc, - createUnnamedGlobalFrom(CGM, D, Builder, constant, Loc.getAlignment()), - SizeVal, isVolatile); + Builder.CreateMemCpy(Loc, + createUnnamedGlobalForMemcpyFrom( + CGM, D, Builder, constant, Loc.getAlignment()), + SizeVal, isVolatile); } static void emitStoresForZeroInit(CodeGenModule &CGM, const VarDecl &D, @@ -1763,10 +1783,10 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::PHINode *Cur = Builder.CreatePHI(Begin.getType(), 2, "vla.cur"); Cur->addIncoming(Begin.getPointer(), OriginBB); CharUnits CurAlign = Loc.getAlignment().alignmentOfArrayElement(EltSize); - Builder.CreateMemCpy( - Address(Cur, CurAlign), - createUnnamedGlobalFrom(CGM, D, Builder, Constant, ConstantAlign), - BaseSizeInChars, isVolatile); + Builder.CreateMemCpy(Address(Cur, CurAlign), + createUnnamedGlobalForMemcpyFrom( + CGM, D, Builder, Constant, ConstantAlign), + BaseSizeInChars, isVolatile); llvm::Value *Next = Builder.CreateInBoundsGEP(Int8Ty, Cur, BaseSizeInChars, "vla.next"); llvm::Value *Done = Builder.CreateICmpEQ(Next, End, "vla-init.isdone"); 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!"); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 8c1bc0777de..95964afed4e 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -362,6 +362,10 @@ private: llvm::SmallVector<std::pair<llvm::GlobalValue *, llvm::Constant *>, 8> GlobalValReplacements; + /// Variables for which we've emitted globals containing their constant + /// values along with the corresponding globals, for opportunistic reuse. + llvm::DenseMap<const VarDecl*, llvm::GlobalVariable*> InitializerConstants; + /// Set of global decls for which we already diagnosed mangled name conflict. /// Required to not issue a warning (on a mangling conflict) multiple times /// for the same decl. @@ -623,6 +627,9 @@ public: StaticLocalDeclGuardMap[D] = C; } + Address createUnnamedGlobalFrom(const VarDecl &D, llvm::Constant *Constant, + CharUnits Align); + bool lookupRepresentativeDecl(StringRef MangledName, GlobalDecl &Result) const; |