Skip to content

Commit

Permalink
CodeGen: Cast alloca to expected address space
Browse files Browse the repository at this point in the history
Alloca always returns a pointer in alloca address space, which may
be different from the type defined by the language. For example,
in C++ the auto variables are in the default address space. Therefore
cast alloca to the expected address space when necessary.

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

llvm-svn: 303370
  • Loading branch information
yxsamliu committed May 18, 2017
1 parent b00ffd8 commit 6d96f16
Show file tree
Hide file tree
Showing 28 changed files with 286 additions and 85 deletions.
3 changes: 1 addition & 2 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -2324,8 +2324,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
uint64_t getTargetNullPointerValue(QualType QT) const;

bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling ||
AS >= LangAS::Count;
return AddrSpaceMapMangling || AS >= LangAS::FirstTargetAddressSpace;
}

private:
Expand Down
7 changes: 5 additions & 2 deletions clang/include/clang/AST/Type.h
Expand Up @@ -333,15 +333,18 @@ class Qualifiers {

bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; }
bool hasTargetSpecificAddressSpace() const {
return getAddressSpace() >= LangAS::FirstTargetAddressSpace;
}
/// Get the address space attribute value to be printed by diagnostics.
unsigned getAddressSpaceAttributePrintValue() const {
auto Addr = getAddressSpace();
// This function is not supposed to be used with language specific
// address spaces. If that happens, the diagnostic message should consider
// printing the QualType instead of the address space value.
assert(Addr == 0 || Addr >= LangAS::Count);
assert(Addr == 0 || hasTargetSpecificAddressSpace());
if (Addr)
return Addr - LangAS::Count;
return Addr - LangAS::FirstTargetAddressSpace;
// TODO: The diagnostic messages where Addr may be 0 should be fixed
// since it cannot differentiate the situation where 0 denotes the default
// address space or user specified __attribute__((address_space(0))).
Expand Down
5 changes: 2 additions & 3 deletions clang/include/clang/Basic/AddressSpaces.h
Expand Up @@ -45,13 +45,12 @@ enum ID {
// This denotes the count of language-specific address spaces and also
// the offset added to the target-specific address spaces, which are usually
// specified by address space attributes __attribute__(address_space(n))).
Count
FirstTargetAddressSpace
};

/// The type of a lookup table which maps from language-specific address spaces
/// to target-specific ones.
typedef unsigned Map[Count];

typedef unsigned Map[FirstTargetAddressSpace];
}

}
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -2490,7 +2490,7 @@ def err_attribute_address_multiple_qualifiers : Error<
def err_attribute_address_function_type : Error<
"function type may not be qualified with an address space">;
def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an address space">;
"automatic variable qualified with an%select{| invalid}0 address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
def err_field_with_address_space : Error<
Expand Down
13 changes: 4 additions & 9 deletions clang/lib/AST/ASTContext.cpp
Expand Up @@ -8730,8 +8730,8 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
char *End;
unsigned AddrSpace = strtoul(Str, &End, 10);
if (End != Str && AddrSpace != 0) {
Type = Context.getAddrSpaceQualType(Type, AddrSpace +
LangAS::Count);
Type = Context.getAddrSpaceQualType(
Type, AddrSpace + LangAS::FirstTargetAddressSpace);
Str = End;
}
if (c == '*')
Expand Down Expand Up @@ -9546,13 +9546,8 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
}

unsigned ASTContext::getTargetAddressSpace(unsigned AS) const {
// For OpenCL, only function local variables are not explicitly marked with
// an address space in the AST, and these need to be the address space of
// alloca.
if (!AS && LangOpts.OpenCL)
return getTargetInfo().getDataLayout().getAllocaAddrSpace();
if (AS >= LangAS::Count)
return AS - LangAS::Count;
if (AS >= LangAS::FirstTargetAddressSpace)
return AS - LangAS::FirstTargetAddressSpace;
else
return (*AddrSpaceMap)[AS];
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/TypePrinter.cpp
Expand Up @@ -1668,9 +1668,9 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy,
OS << "__shared";
break;
default:
assert(addrspace >= LangAS::Count);
assert(addrspace >= LangAS::FirstTargetAddressSpace);
OS << "__attribute__((address_space(";
OS << addrspace - LangAS::Count;
OS << addrspace - LangAS::FirstTargetAddressSpace;
OS << ")))";
}
}
Expand Down
64 changes: 44 additions & 20 deletions clang/lib/Basic/Targets.cpp
Expand Up @@ -2034,25 +2034,45 @@ ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const {
return llvm::makeArrayRef(GCCRegNames);
}

static const LangAS::Map AMDGPUPrivateIsZeroMap = {
4, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
4, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
static const LangAS::Map AMDGPUNonOpenCLPrivateIsZeroMap = {
4, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
4, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
};
static const LangAS::Map AMDGPUNonOpenCLGenericIsZeroMap = {
0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
0, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
};
static const LangAS::Map AMDGPUGenericIsZeroMap = {
0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
0, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
static const LangAS::Map AMDGPUOpenCLPrivateIsZeroMap = {
0, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
4, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
};
static const LangAS::Map AMDGPUOpenCLGenericIsZeroMap = {
5, // Default
1, // opencl_global
3, // opencl_local
2, // opencl_constant
0, // opencl_generic
1, // cuda_device
2, // cuda_constant
3 // cuda_shared
};

// If you edit the description strings, make sure you update
Expand Down Expand Up @@ -2149,8 +2169,12 @@ class AMDGPUTargetInfo final : public TargetInfo {
: DataLayoutStringR600);
assert(DataLayout->getAllocaAddrSpace() == AS.Private);

AddrSpaceMap = IsGenericZero ? &AMDGPUGenericIsZeroMap :
&AMDGPUPrivateIsZeroMap;
AddrSpaceMap =
llvm::StringSwitch<const LangAS::Map *>(Triple.getEnvironmentName())
.Case("opencl", &AMDGPUOpenCLPrivateIsZeroMap)
.Case("amdgiz", &AMDGPUNonOpenCLGenericIsZeroMap)
.Case("amdgizcl", &AMDGPUOpenCLGenericIsZeroMap)
.Default(&AMDGPUNonOpenCLPrivateIsZeroMap);
UseAddrSpaceMapMangling = true;
}

Expand Down
18 changes: 17 additions & 1 deletion clang/lib/CodeGen/CGDecl.cpp
Expand Up @@ -11,14 +11,15 @@
//
//===----------------------------------------------------------------------===//

#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGDebugInfo.h"
#include "CGOpenCLRuntime.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
Expand Down Expand Up @@ -1105,6 +1106,21 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
address = Address(vla, alignment);
}

// Alloca always returns a pointer in alloca address space, which may
// be different from the type defined by the language. For example,
// in C++ the auto variables are in the default address space. Therefore
// cast alloca to the expected address space when necessary.
auto T = D.getType();
assert(T.getAddressSpace() == LangAS::Default);
if (getASTAllocaAddressSpace() != LangAS::Default) {
auto *Addr = getTargetHooks().performAddrSpaceCast(
*this, address.getPointer(), getASTAllocaAddressSpace(),
T.getAddressSpace(),
address.getElementType()->getPointerTo(
getContext().getTargetAddressSpace(T.getAddressSpace())),
/*non-null*/ true);
address = Address(Addr, address.getAlignment());
}
setAddrOfLocalVar(&D, address);
emission.Addr = address;

Expand Down
7 changes: 3 additions & 4 deletions clang/lib/CodeGen/CGExprScalar.cpp
Expand Up @@ -1579,10 +1579,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
// Since target may map different address spaces in AST to the same address
// space, an address space conversion may end up as a bitcast.
auto *Src = Visit(E);
return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGF, Src,
E->getType(),
DestTy);
return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(
CGF, Visit(E), E->getType()->getPointeeType().getAddressSpace(),
DestTy->getPointeeType().getAddressSpace(), ConvertType(DestTy));
}
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Expand Up @@ -113,6 +113,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
AllocaInt8PtrTy = Int8Ty->getPointerTo(
M.getDataLayout().getAllocaAddrSpace());
ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();

RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
BuiltinCC = getTargetCodeGenInfo().getABIInfo().getBuiltinCC();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenTypeCache.h
Expand Up @@ -94,6 +94,8 @@ struct CodeGenTypeCache {
unsigned char SizeAlignInBytes;
};

unsigned ASTAllocaAddressSpace;

CharUnits getSizeSize() const {
return CharUnits::fromQuantity(SizeSizeInBytes);
}
Expand All @@ -111,6 +113,8 @@ struct CodeGenTypeCache {
llvm::CallingConv::ID getRuntimeCC() const { return RuntimeCC; }
llvm::CallingConv::ID BuiltinCC;
llvm::CallingConv::ID getBuiltinCC() const { return BuiltinCC; }

unsigned getASTAllocaAddressSpace() const { return ASTAllocaAddressSpace; }
};

} // end namespace CodeGen
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/CodeGen/TargetInfo.cpp
Expand Up @@ -407,12 +407,11 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &
}

llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
CodeGen::CodeGenFunction &CGF, llvm::Value *Src, QualType SrcTy,
QualType DestTy) const {
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.
return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src,
CGF.ConvertType(DestTy));
return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy);
}

static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
Expand Down Expand Up @@ -7292,6 +7291,11 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo {

llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const override;

unsigned getASTAllocaAddressSpace() const override {
return LangAS::FirstTargetAddressSpace +
getABIInfo().getDataLayout().getAllocaAddrSpace();
}
};
}

Expand Down
15 changes: 11 additions & 4 deletions clang/lib/CodeGen/TargetInfo.h
Expand Up @@ -229,13 +229,20 @@ class TargetCodeGenInfo {
virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T, QualType QT) const;

/// Get the AST address space for alloca.
virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; }

/// Perform address space cast of an expression of pointer type.
/// \param V is the LLVM value to be casted to another address space.
/// \param SrcTy is the QualType of \p V.
/// \param DestTy is the destination QualType.
/// \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.
/// \param IsNonNull is the flag indicating \p V is known to be non null.
virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction &CGF,
llvm::Value *V, QualType SrcTy, QualType DestTy) const;

llvm::Value *V, unsigned SrcAddr,
unsigned DestAddr,
llvm::Type *DestTy,
bool IsNonNull = false) const;
};

} // namespace CodeGen
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -7191,7 +7191,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
// ISO/IEC TR 18037 S5.1.2
if (!getLangOpts().OpenCL
&& NewVD->hasLocalStorage() && T.getAddressSpace() != 0) {
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl);
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 0;
NewVD->setInvalidDecl();
return;
}
Expand Down Expand Up @@ -7271,6 +7271,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
} else if (T.getAddressSpace() != LangAS::Default) {
// Do not allow other address spaces on automatic variable.
Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1;
NewVD->setInvalidDecl();
return;
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaType.cpp
Expand Up @@ -5531,14 +5531,15 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
addrSpace.setIsSigned(false);
}
llvm::APSInt max(addrSpace.getBitWidth());
max = Qualifiers::MaxAddressSpace - LangAS::Count;
max = Qualifiers::MaxAddressSpace - LangAS::FirstTargetAddressSpace;
if (addrSpace > max) {
S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high)
<< (unsigned)max.getZExtValue() << ASArgExpr->getSourceRange();
Attr.setInvalid();
return;
}
ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()) + LangAS::Count;
ASIdx = static_cast<unsigned>(addrSpace.getZExtValue()) +
LangAS::FirstTargetAddressSpace;
} else {
// The keyword-based type attributes imply which address space to use.
switch (Attr.getKind()) {
Expand Down
8 changes: 5 additions & 3 deletions clang/test/CodeGen/address-space.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm < %s | FileCheck -check-prefixes=CHECK,GIZ %s
// RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=CHECK,PIZ %s
// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHeCK,GIZ %s
// RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,GIZ %s

// CHECK: @foo = common addrspace(1) global
int foo __attribute__((address_space(1)));
Expand Down Expand Up @@ -40,8 +40,10 @@ typedef struct {
} MyStruct;

// CHECK-LABEL: define void @test4(
// CHECK: call void @llvm.memcpy.p0i8.p2i8
// CHECK: call void @llvm.memcpy.p2i8.p0i8
// GIZ: call void @llvm.memcpy.p0i8.p2i8
// GIZ: call void @llvm.memcpy.p2i8.p0i8
// PIZ: call void @llvm.memcpy.p4i8.p2i8
// PIZ: call void @llvm.memcpy.p2i8.p4i8
void test4(MyStruct __attribute__((address_space(2))) *pPtr) {
MyStruct s = pPtr[0];
pPtr[0] = s;
Expand Down

0 comments on commit 6d96f16

Please sign in to comment.