mirror of
https://github.com/intel/llvm.git
synced 2026-01-28 01:04:49 +08:00
CodeGen: Fix address space of global variable
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
This commit is contained in:
@@ -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"
|
||||
@@ -954,6 +955,14 @@ public:
|
||||
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; }
|
||||
|
||||
@@ -2404,6 +2404,10 @@ public:
|
||||
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; }
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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: {
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -1479,6 +1479,9 @@ public:
|
||||
|
||||
const TargetInfo &getTarget() const { return Target; }
|
||||
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
|
||||
const TargetCodeGenInfo &getTargetHooks() const {
|
||||
return CGM.getTargetCodeGenInfo();
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Cleanups
|
||||
@@ -3820,10 +3823,6 @@ public:
|
||||
private:
|
||||
QualType getVarArgType(const Expr *Arg);
|
||||
|
||||
const TargetCodeGenInfo &getTargetHooks() const {
|
||||
return CGM.getTargetCodeGenInfo();
|
||||
}
|
||||
|
||||
void EmitDeclMetadata();
|
||||
|
||||
BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType,
|
||||
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
else
|
||||
AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
return LangAS::cuda_device;
|
||||
}
|
||||
|
||||
return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D);
|
||||
}
|
||||
|
||||
template<typename SomeDecl>
|
||||
@@ -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());
|
||||
@@ -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
|
||||
|
||||
@@ -710,11 +710,15 @@ public:
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -7325,6 +7344,8 @@ public:
|
||||
return LangAS::FirstTargetAddressSpace +
|
||||
getABIInfo().getDataLayout().getAllocaAddrSpace();
|
||||
}
|
||||
unsigned getGlobalVarAddressSpace(CodeGenModule &CGM,
|
||||
const VarDecl *D) const override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -229,6 +229,13 @@ public:
|
||||
virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
|
||||
llvm::PointerType *T, QualType QT) const;
|
||||
|
||||
/// Get target favored AST address space of a global variable for languages
|
||||
/// other than OpenCL and CUDA.
|
||||
/// If \p D is nullptr, returns the default target favored address space
|
||||
/// for global variable.
|
||||
virtual unsigned getGlobalVarAddressSpace(CodeGenModule &CGM,
|
||||
const VarDecl *D) const;
|
||||
|
||||
/// Get the AST address space for alloca.
|
||||
virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; }
|
||||
|
||||
@@ -243,6 +250,15 @@ public:
|
||||
unsigned DestAddr,
|
||||
llvm::Type *DestTy,
|
||||
bool IsNonNull = false) const;
|
||||
|
||||
/// Perform address space cast of a constant expression of pointer type.
|
||||
/// \param V is the LLVM constant to be casted to another address space.
|
||||
/// \param SrcAddr is the language address space of \p V.
|
||||
/// \param DestAddr is the targeted language address space.
|
||||
/// \param DestTy is the destination LLVM pointer type.
|
||||
virtual llvm::Constant *
|
||||
performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *V, unsigned SrcAddr,
|
||||
unsigned DestAddr, llvm::Type *DestTy) const;
|
||||
};
|
||||
|
||||
} // namespace CodeGen
|
||||
|
||||
@@ -24,11 +24,13 @@ int test2(int i) { return ban[i]; }
|
||||
__attribute__((address_space(2))) int *A, *B;
|
||||
|
||||
// CHECK-LABEL: define void @test3()
|
||||
// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @B
|
||||
// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @B
|
||||
// X86: load i32 addrspace(2)*, i32 addrspace(2)** @B
|
||||
// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)**)
|
||||
// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)* addrspace(4)*)
|
||||
// CHECK: load i32, i32 addrspace(2)*
|
||||
// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @A
|
||||
// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @A
|
||||
// X86: load i32 addrspace(2)*, i32 addrspace(2)** @A
|
||||
// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)**)
|
||||
// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)* addrspace(4)*)
|
||||
// CHECK: store i32 {{.*}}, i32 addrspace(2)*
|
||||
void test3() {
|
||||
*A = *B;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
// RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=PIZ,COM %s
|
||||
// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,COM %s
|
||||
|
||||
// PIZ-DAG: @foo = common addrspace(4) global i32 0
|
||||
// CHECK-DAG: @foo = common global i32 0
|
||||
// PIZ-DAG: @foo = common addrspace(1) global i32 0
|
||||
// CHECK-DAG: @foo = common addrspace(1) global i32 0
|
||||
int foo;
|
||||
|
||||
// PIZ-DAG: @ban = common addrspace(4) global [10 x i32] zeroinitializer
|
||||
// CHECK-DAG: @ban = common global [10 x i32] zeroinitializer
|
||||
// PIZ-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer
|
||||
// CHECK-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer
|
||||
int ban[10];
|
||||
|
||||
// PIZ-DAG: @A = common addrspace(4) global i32 addrspace(4)* null
|
||||
// PIZ-DAG: @B = common addrspace(4) global i32 addrspace(4)* null
|
||||
// CHECK-DAG: @A = common global i32* null
|
||||
// CHECK-DAG: @B = common global i32* null
|
||||
// PIZ-DAG: @A = common addrspace(1) global i32 addrspace(4)* null
|
||||
// PIZ-DAG: @B = common addrspace(1) global i32 addrspace(4)* null
|
||||
// CHECK-DAG: @A = common addrspace(1) global i32* null
|
||||
// CHECK-DAG: @B = common addrspace(1) global i32* null
|
||||
int *A;
|
||||
int *B;
|
||||
|
||||
// COM-LABEL: define i32 @test1()
|
||||
// PIZ: load i32, i32 addrspace(4)* @foo
|
||||
// CHECK: load i32, i32* @foo
|
||||
// PIZ: load i32, i32 addrspace(4)* addrspacecast{{[^@]+}} @foo
|
||||
// CHECK: load i32, i32* addrspacecast{{[^@]+}} @foo
|
||||
int test1() { return foo; }
|
||||
|
||||
// COM-LABEL: define i32 @test2(i32 %i)
|
||||
@@ -30,13 +30,13 @@ int test1() { return foo; }
|
||||
int test2(int i) { return ban[i]; }
|
||||
|
||||
// COM-LABEL: define void @test3()
|
||||
// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @B
|
||||
// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* addrspacecast{{[^@]+}} @B
|
||||
// PIZ: load i32, i32 addrspace(4)*
|
||||
// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @A
|
||||
// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* addrspacecast{{[^@]+}} @A
|
||||
// PIZ: store i32 {{.*}}, i32 addrspace(4)*
|
||||
// CHECK: load i32*, i32** @B
|
||||
// CHECK: load i32*, i32** addrspacecast{{.*}} @B
|
||||
// CHECK: load i32, i32*
|
||||
// CHECK: load i32*, i32** @A
|
||||
// CHECK: load i32*, i32** addrspacecast{{.*}} @A
|
||||
// CHECK: store i32 {{.*}}, i32*
|
||||
void test3() {
|
||||
*A = *B;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefixes=X86,CHECK %s
|
||||
// RUN: %clang_cc1 -std=c++11 -triple amdgcn-amd-amdhsa-amdgiz -DNO_TLS -emit-llvm -o - %s | FileCheck -check-prefixes=AMD,CHECK %s
|
||||
|
||||
namespace std {
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
@@ -46,54 +47,72 @@ struct wantslist1 {
|
||||
wantslist1(std::initializer_list<destroyme1>);
|
||||
~wantslist1();
|
||||
};
|
||||
|
||||
// CHECK: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3]
|
||||
// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 }
|
||||
// X86: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3]
|
||||
// X86: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 }
|
||||
// AMD: @_ZGR15globalInitList1_ = internal addrspace(1) constant [3 x i32] [i32 1, i32 2, i32 3]
|
||||
// AMD: @globalInitList1 = addrspace(1) global %{{[^ ]+}} { i32* addrspacecast (i32 addrspace(1)* getelementptr inbounds ([3 x i32], [3 x i32] addrspace(1)* @_ZGR15globalInitList1_, i32 0, i32 0) to i32*), i{{32|64}} 3 }
|
||||
std::initializer_list<int> globalInitList1 = {1, 2, 3};
|
||||
|
||||
#ifndef NO_TLS
|
||||
namespace thread_local_global_array {
|
||||
// FIXME: We should be able to constant-evaluate this even though the
|
||||
// initializer is not a constant expression (pointers to thread_local
|
||||
// objects aren't really a problem).
|
||||
//
|
||||
// CHECK: @_ZN25thread_local_global_array1xE = thread_local global
|
||||
// CHECK: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
|
||||
std::initializer_list<int> thread_local x = { 1, 2, 3, 4 };
|
||||
// FIXME: We should be able to constant-evaluate this even though the
|
||||
// initializer is not a constant expression (pointers to thread_local
|
||||
// objects aren't really a problem).
|
||||
//
|
||||
// X86: @_ZN25thread_local_global_array1xE = thread_local global
|
||||
// X86: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4]
|
||||
std::initializer_list<int> thread_local x = {1, 2, 3, 4};
|
||||
}
|
||||
#endif
|
||||
|
||||
// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
|
||||
// CHECK: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
|
||||
// X86: @globalInitList2 = global %{{[^ ]+}} zeroinitializer
|
||||
// X86: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
|
||||
// AMD: @globalInitList2 = addrspace(1) global %{{[^ ]+}} zeroinitializer
|
||||
// AMD: @_ZGR15globalInitList2_ = internal addrspace(1) global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer
|
||||
|
||||
// CHECK: @_ZN15partly_constant1kE = global i32 0, align 4
|
||||
// CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8
|
||||
// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4
|
||||
// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4
|
||||
// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
|
||||
// X86: @_ZN15partly_constant1kE = global i32 0, align 4
|
||||
// X86: @_ZN15partly_constant2ilE = global {{.*}} null, align 8
|
||||
// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8
|
||||
// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8
|
||||
// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4
|
||||
// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4
|
||||
// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
|
||||
// AMD: @_ZN15partly_constant1kE = addrspace(1) global i32 0, align 4
|
||||
// AMD: @_ZN15partly_constant2ilE = addrspace(2) global {{.*}} null, align 8
|
||||
// AMD: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global {{.*}} zeroinitializer, align 8
|
||||
// AMD: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [3 x {{.*}}] zeroinitializer, align 8
|
||||
// AMD: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3], align 4
|
||||
// AMD: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [2 x i32] zeroinitializer, align 4
|
||||
// AMD: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4
|
||||
|
||||
// CHECK: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4
|
||||
// CHECK: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
|
||||
// X86: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4
|
||||
// X86: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
|
||||
// AMD: @[[REFTMP1:.*]] = private addrspace(2) constant [2 x i32] [i32 42, i32 43], align 4
|
||||
// AMD: @[[REFTMP2:.*]] = private addrspace(2) constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4
|
||||
|
||||
// CHECK: appending global
|
||||
|
||||
|
||||
// thread_local initializer:
|
||||
// CHECK-LABEL: define internal void
|
||||
// CHECK: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
|
||||
// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
|
||||
// X86-LABEL: define internal void @__cxx_global_var_init
|
||||
// X86: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0),
|
||||
// X86: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8
|
||||
// X86: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8
|
||||
|
||||
|
||||
// CHECK-LABEL: define internal void
|
||||
// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0
|
||||
// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1
|
||||
// CHECK: __cxa_atexit
|
||||
// CHECK: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0),
|
||||
// CHECK: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8
|
||||
// CHECK: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8
|
||||
// CHECK: call void @_ZN10destroyme1D1Ev
|
||||
// CHECK-LABEL: define internal void @__cxx_global_var_init
|
||||
// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0
|
||||
// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1
|
||||
// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 0
|
||||
// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 1
|
||||
// CHECK: call i32 @__cxa_atexit
|
||||
// X86: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0),
|
||||
// X86: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8
|
||||
// X86: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8
|
||||
// AMD: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i64 0, i64 0),
|
||||
// AMD: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 0), align 8
|
||||
// AMD: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 1), align 8
|
||||
// CHECK: call void @_ZN10destroyme1D1Ev
|
||||
// CHECK-NEXT: call void @_ZN10destroyme1D1Ev
|
||||
// CHECK-NEXT: ret void
|
||||
std::initializer_list<witharg1> globalInitList2 = {
|
||||
witharg1(destroyme1()), witharg1(destroyme1())
|
||||
};
|
||||
@@ -101,7 +120,9 @@ std::initializer_list<witharg1> globalInitList2 = {
|
||||
void fn1(int i) {
|
||||
// CHECK-LABEL: define void @_Z3fn1i
|
||||
// temporary array
|
||||
// CHECK: [[array:%[^ ]+]] = alloca [3 x i32]
|
||||
// X86: [[array:%[^ ]+]] = alloca [3 x i32]
|
||||
// AMD: [[alloca:%[^ ]+]] = alloca [3 x i32], align 4, addrspace(5)
|
||||
// AMD: [[array:%[^ ]+]] = addrspacecast [3 x i32] addrspace(5)* [[alloca]] to [3 x i32]*
|
||||
// CHECK: getelementptr inbounds [3 x i32], [3 x i32]* [[array]], i{{32|64}} 0
|
||||
// CHECK-NEXT: store i32 1, i32*
|
||||
// CHECK-NEXT: getelementptr
|
||||
@@ -175,7 +196,6 @@ void fn6() {
|
||||
destroyme2 dm2;
|
||||
// CHECK: call void @_ZN10destroyme2D1Ev
|
||||
}
|
||||
|
||||
void fn7() {
|
||||
// CHECK-LABEL: define void @_Z3fn7v
|
||||
// temps should be destroyed before dm2
|
||||
@@ -366,37 +386,36 @@ namespace partly_constant {
|
||||
std::initializer_list<std::initializer_list<int>> &&il = { { 1, 2, 3 }, { 4, k }, { 5, 6, 7, 8 } };
|
||||
// First init list.
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_FIRST]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 1)
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_FIRST]]{{.*}}, i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 1)
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]],
|
||||
//
|
||||
// Second init list array (non-constant).
|
||||
// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0)
|
||||
// CHECK: load i32, i32* @_ZN15partly_constant1kE
|
||||
// CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 1)
|
||||
// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0)
|
||||
// CHECK: load i32, i32* {{.*}}@_ZN15partly_constant1kE
|
||||
// CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 1)
|
||||
//
|
||||
// Second init list.
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 0)
|
||||
// CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 1)
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 0)
|
||||
// CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 1)
|
||||
//
|
||||
// Third init list.
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_THIRD]], i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 2, i32 0)
|
||||
// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZGRN15partly_constant2ilE4_, i64 0, i64 2, i32 1)
|
||||
// CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_THIRD]]{{.*}}, i64 0, i64 0),
|
||||
// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 0)
|
||||
// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@_ZGRN15partly_constant2ilE4_{{.*}}, i64 0, i64 2, i32 1)
|
||||
// CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]],
|
||||
//
|
||||
// Outer init list.
|
||||
// CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0),
|
||||
// CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 1)
|
||||
// CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0),
|
||||
// CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 0)
|
||||
// CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 1)
|
||||
//
|
||||
// 'il' reference.
|
||||
// CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8
|
||||
// CHECK: store {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, {{.*}}** {{.*}}@_ZN15partly_constant2ilE{{.*}}, align 8
|
||||
}
|
||||
|
||||
namespace nested {
|
||||
struct A { A(); ~A(); };
|
||||
struct B { const A &a; ~B(); };
|
||||
@@ -463,7 +482,7 @@ namespace PR20445 {
|
||||
template<int x> void f() { new MyClass({42, 43}); }
|
||||
template void f<0>();
|
||||
// CHECK-LABEL: define {{.*}} @_ZN7PR204451fILi0EEEvv(
|
||||
// CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* @[[REFTMP1]], i64 0, i64 0)
|
||||
// CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* {{.*}}@[[REFTMP1]]{{.*}}, i64 0, i64 0)
|
||||
// CHECK: call void @_ZN7PR204456vectorC1ESt16initializer_listIiE(
|
||||
// CHECK: call void @_ZN7PR204457MyClassC1ERKNS_6vectorE(
|
||||
}
|
||||
@@ -476,9 +495,9 @@ namespace ConstExpr {
|
||||
};
|
||||
void f(std::initializer_list<C>);
|
||||
void g() {
|
||||
// CHECK-LABEL: _ZN9ConstExpr1gEv
|
||||
// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* @[[REFTMP2]], i64 0, i64 0)
|
||||
// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
|
||||
// CHECK-LABEL: _ZN9ConstExpr1gEv
|
||||
// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* {{.*}}@[[REFTMP2]]{{.*}}, i64 0, i64 0)
|
||||
// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE
|
||||
f({C(1), C(2), C(3)});
|
||||
}
|
||||
}
|
||||
@@ -498,11 +517,13 @@ namespace B19773010 {
|
||||
void f1() {
|
||||
// CHECK-LABEL: @_ZN9B197730102f1Ev
|
||||
testcase a{{"", ENUM_CONSTANT}};
|
||||
// CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
|
||||
// X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
|
||||
// AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(2)* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"] addrspace(2)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8
|
||||
}
|
||||
void f2() {
|
||||
// CHECK-LABEL: @_ZN9B197730102f2Ev
|
||||
// CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16
|
||||
// X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16
|
||||
// AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(1)* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"] addrspace(1)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* addrspacecast{{.*}}@_ZZN9B197730102f2EvE1p{{.*}}, i64 0, i64 1, i32 0), align 8
|
||||
static std::initializer_list<pair<const char *, E>> a, p[2] =
|
||||
{a, {{"", ENUM_CONSTANT}}};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user