Skip to content

Commit

Permalink
CodeGen: Fix address space of global variable
Browse files Browse the repository at this point in the history
Certain targets (e.g. amdgcn) require global variable to stay in global or constant address
space. In C or C++ global variables are emitted in the default (generic) address space.
This patch introduces virtual functions TargetCodeGenInfo::getGlobalVarAddressSpace
and TargetInfo::getConstantAddressSpace to handle this in a general approach.

It only affects IR generated for amdgcn target.

Differential Revision: https://reviews.llvm.org/D33842

llvm-svn: 307470
  • Loading branch information
yxsamliu committed Jul 8, 2017
1 parent affab30 commit cbf647c
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 145 deletions.
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Expand Up @@ -23,6 +23,7 @@
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -954,6 +955,14 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
return *AddrSpaceMap;
}

/// \brief Return an AST address space which can be used opportunistically
/// for constant global memory. It must be possible to convert pointers into
/// this address space to LangAS::Default. If no such address space exists,
/// this may return None, and such optimizations will be disabled.
virtual llvm::Optional<unsigned> getConstantAddressSpace() const {
return LangAS::Default;
}

/// \brief Retrieve the name of the platform as it is used in the
/// availability attribute.
StringRef getPlatformName() const { return PlatformName; }
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets.cpp
Expand Up @@ -2404,6 +2404,10 @@ class AMDGPUTargetInfo final : public TargetInfo {
return LangAS::opencl_constant;
}

llvm::Optional<unsigned> getConstantAddressSpace() const override {
return LangAS::FirstTargetAddressSpace + AS.Constant;
}

/// \returns Target specific vtbl ptr address space.
unsigned getVtblPtrAddressSpace() const override { return AS.Constant; }

Expand Down
17 changes: 8 additions & 9 deletions clang/lib/CodeGen/CGBlocks.cpp
Expand Up @@ -736,9 +736,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
llvm::Constant *isa =
(!CGM.getContext().getLangOpts().OpenCL)
? CGM.getNSConcreteStackBlock()
: CGM.getNullPointer(cast<llvm::PointerType>(
CGM.getNSConcreteStackBlock()->getType()),
QualType(getContext().VoidPtrTy));
: CGM.getNullPointer(VoidPtrPtrTy,
CGM.getContext().getPointerType(
QualType(CGM.getContext().VoidPtrTy)));
isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy);

// Build the block descriptor.
Expand Down Expand Up @@ -1141,12 +1141,11 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
auto fields = builder.beginStruct();

// isa
fields.add(
(!CGM.getContext().getLangOpts().OpenCL)
? CGM.getNSConcreteGlobalBlock()
: CGM.getNullPointer(cast<llvm::PointerType>(
CGM.getNSConcreteGlobalBlock()->getType()),
QualType(CGM.getContext().VoidPtrTy)));
fields.add((!CGM.getContext().getLangOpts().OpenCL)
? CGM.getNSConcreteGlobalBlock()
: CGM.getNullPointer(CGM.VoidPtrPtrTy,
CGM.getContext().getPointerType(QualType(
CGM.getContext().VoidPtrTy))));

// __flags
BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE;
Expand Down
22 changes: 10 additions & 12 deletions clang/lib/CodeGen/CGDecl.cpp
Expand Up @@ -221,8 +221,8 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
Name = getStaticDeclName(*this, D);

llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty);
unsigned AddrSpace =
GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty));
unsigned AS = GetGlobalVarAddressSpace(&D);
unsigned TargetAS = getContext().getTargetAddressSpace(AS);

// Local address space cannot have an initializer.
llvm::Constant *Init = nullptr;
Expand All @@ -231,12 +231,9 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
else
Init = llvm::UndefValue::get(LTy);

llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), LTy,
Ty.isConstant(getContext()), Linkage,
Init, Name, nullptr,
llvm::GlobalVariable::NotThreadLocal,
AddrSpace);
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
setGlobalVisibility(GV, &D);

Expand All @@ -254,11 +251,12 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
}

// Make sure the result is of the correct type.
unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty);
unsigned ExpectedAS = Ty.getAddressSpace();
llvm::Constant *Addr = GV;
if (AddrSpace != ExpectedAddrSpace) {
llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace);
Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy);
if (AS != ExpectedAS) {
Addr = getTargetCodeGenInfo().performAddrSpaceCast(
*this, GV, AS, ExpectedAS,
LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS)));
}

setStaticLocalDeclAddress(&D, Addr);
Expand Down
38 changes: 26 additions & 12 deletions clang/lib/CodeGen/CGExpr.cpp
Expand Up @@ -338,9 +338,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
}
}

static Address
createReferenceTemporary(CodeGenFunction &CGF,
const MaterializeTemporaryExpr *M, const Expr *Inner) {
static Address createReferenceTemporary(CodeGenFunction &CGF,
const MaterializeTemporaryExpr *M,
const Expr *Inner) {
auto &TCG = CGF.getTargetHooks();
switch (M->getStorageDuration()) {
case SD_FullExpression:
case SD_Automatic: {
Expand All @@ -353,13 +354,24 @@ createReferenceTemporary(CodeGenFunction &CGF,
(Ty->isArrayType() || Ty->isRecordType()) &&
CGF.CGM.isTypeConstant(Ty, true))
if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) {
auto *GV = new llvm::GlobalVariable(
CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp");
CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
GV->setAlignment(alignment.getQuantity());
// FIXME: Should we put the new global into a COMDAT?
return Address(GV, alignment);
if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) {
auto AS = AddrSpace.getValue();
auto *GV = new llvm::GlobalVariable(
CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr,
llvm::GlobalValue::NotThreadLocal,
CGF.getContext().getTargetAddressSpace(AS));
CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
GV->setAlignment(alignment.getQuantity());
llvm::Constant *C = GV;
if (AS != LangAS::Default)
C = TCG.performAddrSpaceCast(
CGF.CGM, GV, AS, LangAS::Default,
GV->getValueType()->getPointerTo(
CGF.getContext().getTargetAddressSpace(LangAS::Default)));
// FIXME: Should we put the new global into a COMDAT?
return Address(C, alignment);
}
}
return CGF.CreateMemTemp(Ty, "ref.tmp");
}
Expand Down Expand Up @@ -440,9 +452,11 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {

// Create and initialize the reference temporary.
Address Object = createReferenceTemporary(*this, M, E);
if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) {
if (auto *Var = dyn_cast<llvm::GlobalVariable>(
Object.getPointer()->stripPointerCasts())) {
Object = Address(llvm::ConstantExpr::getBitCast(
Var, ConvertTypeForMem(E->getType())->getPointerTo()),
cast<llvm::Constant>(Object.getPointer()),
ConvertTypeForMem(E->getType())->getPointerTo()),
Object.getAlignment());
// If the temporary is a global and has a constant initializer or is a
// constant temporary that we promoted to a global, we may have already
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/CodeGen/CodeGenFunction.h
Expand Up @@ -1479,6 +1479,9 @@ class CodeGenFunction : public CodeGenTypeCache {

const TargetInfo &getTarget() const { return Target; }
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}

//===--------------------------------------------------------------------===//
// Cleanups
Expand Down Expand Up @@ -3820,10 +3823,6 @@ class CodeGenFunction : public CodeGenTypeCache {
private:
QualType getVarArgType(const Expr *Arg);

const TargetCodeGenInfo &getTargetHooks() const {
return CGM.getTargetCodeGenInfo();
}

void EmitDeclMetadata();

BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType,
Expand Down
66 changes: 44 additions & 22 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -2367,11 +2367,13 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
return llvm::ConstantExpr::getBitCast(Entry, Ty);
}

unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace());
auto AddrSpace = GetGlobalVarAddressSpace(D);
auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace);

auto *GV = new llvm::GlobalVariable(
getModule(), Ty->getElementType(), false,
llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr,
llvm::GlobalVariable::NotThreadLocal, AddrSpace);
llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace);

// If we already created a global with the same mangled name (but different
// type) before, take its name and remove it from its parent.
Expand Down Expand Up @@ -2428,8 +2430,14 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setSection(".cp.rodata");
}

if (AddrSpace != Ty->getAddressSpace())
return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty);
auto ExpectedAS =
D ? D->getType().getAddressSpace()
: (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
auto ExpectedTargetAS = getContext().getTargetAddressSpace(ExpectedAS);
assert(ExpectedTargetAS == Ty->getPointerAddressSpace());
if (AddrSpace != ExpectedAS)
return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace,
ExpectedAS, Ty);

return GV;
}
Expand Down Expand Up @@ -2563,18 +2571,27 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
getDataLayout().getTypeStoreSizeInBits(Ty));
}

unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D,
unsigned AddrSpace) {
if (D && LangOpts.CUDA && LangOpts.CUDAIsDevice) {
if (D->hasAttr<CUDAConstantAttr>())
AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant);
else if (D->hasAttr<CUDASharedAttr>())
AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared);
unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
unsigned AddrSpace;
if (LangOpts.OpenCL) {
AddrSpace = D ? D->getType().getAddressSpace() : LangAS::opencl_global;
assert(AddrSpace == LangAS::opencl_global ||
AddrSpace == LangAS::opencl_constant ||
AddrSpace == LangAS::opencl_local ||
AddrSpace >= LangAS::FirstTargetAddressSpace);
return AddrSpace;
}

if (LangOpts.CUDA && LangOpts.CUDAIsDevice) {
if (D && D->hasAttr<CUDAConstantAttr>())
return LangAS::cuda_constant;
else if (D && D->hasAttr<CUDASharedAttr>())
return LangAS::cuda_shared;
else
AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device);
return LangAS::cuda_device;
}

return AddrSpace;
return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D);
}

template<typename SomeDecl>
Expand Down Expand Up @@ -2727,10 +2744,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
// "extern int x[];") and then a definition of a different type (e.g.
// "int x[10];"). This also happens when an initializer has a different type
// from the type of the global (this happens with unions).
if (!GV ||
GV->getType()->getElementType() != InitType ||
if (!GV || GV->getType()->getElementType() != InitType ||
GV->getType()->getAddressSpace() !=
GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) {
getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) {

// Move the old entry aside so that we'll create a new one.
Entry->setName(StringRef());
Expand Down Expand Up @@ -3739,20 +3755,26 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
Linkage = llvm::GlobalVariable::InternalLinkage;
}
}
unsigned AddrSpace = GetGlobalVarAddressSpace(
VD, getContext().getTargetAddressSpace(MaterializedType));
unsigned AddrSpace =
VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace();
auto TargetAS = getContext().getTargetAddressSpace(AddrSpace);
auto *GV = new llvm::GlobalVariable(
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal,
AddrSpace);
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
setGlobalVisibility(GV, VD);
GV->setAlignment(Align.getQuantity());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
if (VD->getTLSKind())
setTLSMode(GV, *VD);
MaterializedGlobalTemporaryMap[E] = GV;
return ConstantAddress(GV, Align);
llvm::Constant *CV = GV;
if (AddrSpace != LangAS::Default)
CV = getTargetCodeGenInfo().performAddrSpaceCast(
*this, GV, AddrSpace, LangAS::Default,
Type->getPointerTo(
getContext().getTargetAddressSpace(LangAS::Default)));
MaterializedGlobalTemporaryMap[E] = CV;
return ConstantAddress(CV, Align);
}

/// EmitObjCPropertyImplementations - Emit information for synthesized
Expand Down
10 changes: 7 additions & 3 deletions clang/lib/CodeGen/CodeGenModule.h
Expand Up @@ -710,11 +710,15 @@ class CodeGenModule : public CodeGenTypeCache {
SourceLocation Loc = SourceLocation(),
bool TLS = false);

/// Return the address space of the underlying global variable for D, as
/// Return the AST address space of the underlying global variable for D, as
/// determined by its declaration. Normally this is the same as the address
/// space of D's type, but in CUDA, address spaces are associated with
/// declarations, not types.
unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace);
/// declarations, not types. If D is nullptr, return the default address
/// space for global variable.
///
/// For languages without explicit address spaces, if D has default address
/// space, target-specific global or constant address space may be returned.
unsigned GetGlobalVarAddressSpace(const VarDecl *D);

/// Return the llvm::Constant for the address of the given global variable.
/// If Ty is non-null and if the global doesn't exist, then it will be created
Expand Down
46 changes: 46 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Expand Up @@ -416,14 +416,33 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &
return llvm::ConstantPointerNull::get(T);
}

unsigned TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const {
assert(!CGM.getLangOpts().OpenCL &&
!(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
"Address space agnostic languages only");
return D ? D->getType().getAddressSpace() : LangAS::Default;
}

llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
CodeGen::CodeGenFunction &CGF, llvm::Value *Src, unsigned SrcAddr,
unsigned DestAddr, llvm::Type *DestTy, bool isNonNull) const {
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
if (auto *C = dyn_cast<llvm::Constant>(Src))
return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy);
return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy);
}

llvm::Constant *
TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,
unsigned SrcAddr, unsigned DestAddr,
llvm::Type *DestTy) const {
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
return llvm::ConstantExpr::getPointerCast(Src, DestTy);
}

static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);

/// isEmptyField - Return true iff a the field is "empty", that is it
Expand Down Expand Up @@ -7325,6 +7344,8 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {
return LangAS::FirstTargetAddressSpace +
getABIInfo().getDataLayout().getAllocaAddrSpace();
}
unsigned getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const override;
};
}

Expand Down Expand Up @@ -7408,6 +7429,31 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
llvm::ConstantPointerNull::get(NPT), PT);
}

unsigned
AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
const VarDecl *D) const {
assert(!CGM.getLangOpts().OpenCL &&
!(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
"Address space agnostic languages only");
unsigned DefaultGlobalAS =
LangAS::FirstTargetAddressSpace +
CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
if (!D)
return DefaultGlobalAS;

unsigned AddrSpace = D->getType().getAddressSpace();
assert(AddrSpace == LangAS::Default ||
AddrSpace >= LangAS::FirstTargetAddressSpace);
if (AddrSpace != LangAS::Default)
return AddrSpace;

if (CGM.isTypeConstant(D->getType(), false)) {
if (auto ConstAS = CGM.getTarget().getConstantAddressSpace())
return ConstAS.getValue();
}
return DefaultGlobalAS;
}

//===----------------------------------------------------------------------===//
// SPARC v8 ABI Implementation.
// Based on the SPARC Compliance Definition version 2.4.1.
Expand Down

0 comments on commit cbf647c

Please sign in to comment.