mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 10:42:05 +00:00
Add support for the MS qualifiers __ptr32, __ptr64, __sptr, __uptr.
Summary: This adds parsing of the qualifiers __ptr32, __ptr64, __sptr, and __uptr and lowers them to the corresponding address space pointer for 32-bit and 64-bit pointers. (32/64-bit pointers added in https://reviews.llvm.org/D69639) A large part of this patch is making these pointers ignore the address space when doing things like overloading and casting. https://bugs.llvm.org/show_bug.cgi?id=42359 Reviewers: rnk, rsmith Subscribers: jholewinski, jvesely, nhaehnle, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D71039
This commit is contained in:
parent
eb1857ce0d
commit
a85f5efd95
@ -1155,6 +1155,10 @@ public:
|
||||
/// attribute.
|
||||
QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr) const;
|
||||
|
||||
/// Remove the existing address space on the type if it is a pointer size
|
||||
/// address space and return the type with qualifiers intact.
|
||||
QualType removePtrSizeAddrSpace(QualType T) const;
|
||||
|
||||
/// Return the uniqued reference to the type for a \c restrict
|
||||
/// qualified type.
|
||||
///
|
||||
@ -1209,6 +1213,15 @@ public:
|
||||
const FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||
bool AsWritten = false);
|
||||
|
||||
/// Get a function type and produce the equivalent function type where
|
||||
/// pointer size address spaces in the return type and parameter tyeps are
|
||||
/// replaced with the default address space.
|
||||
QualType getFunctionTypeWithoutPtrSizes(QualType T);
|
||||
|
||||
/// Determine whether two function types are the same, ignoring pointer sizes
|
||||
/// in the return type and parameter types.
|
||||
bool hasSameFunctionTypeIgnoringPtrSizes(QualType T, QualType U);
|
||||
|
||||
/// Return the uniqued reference to the type for a complex
|
||||
/// number with the specified element type.
|
||||
QualType getComplexType(QualType T) const;
|
||||
|
@ -477,7 +477,10 @@ public:
|
||||
return A == B ||
|
||||
// Otherwise in OpenCLC v2.0 s6.5.5: every address space except
|
||||
// for __constant can be used as __generic.
|
||||
(A == LangAS::opencl_generic && B != LangAS::opencl_constant);
|
||||
(A == LangAS::opencl_generic && B != LangAS::opencl_constant) ||
|
||||
// Consider pointer size address spaces to be equivalent to default.
|
||||
((isPtrSizeAddressSpace(A) || A == LangAS::Default) &&
|
||||
(isPtrSizeAddressSpace(B) || B == LangAS::Default));
|
||||
}
|
||||
|
||||
/// Returns true if the address space in these qualifiers is equal to or
|
||||
|
@ -42,6 +42,11 @@ enum class LangAS : unsigned {
|
||||
cuda_constant,
|
||||
cuda_shared,
|
||||
|
||||
// Pointer size and extension address spaces.
|
||||
ptr32_sptr,
|
||||
ptr32_uptr,
|
||||
ptr64,
|
||||
|
||||
// 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))).
|
||||
@ -68,6 +73,11 @@ inline LangAS getLangASFromTargetAS(unsigned TargetAS) {
|
||||
(unsigned)LangAS::FirstTargetAddressSpace);
|
||||
}
|
||||
|
||||
inline bool isPtrSizeAddressSpace(LangAS AS) {
|
||||
return (AS == LangAS::ptr32_sptr || AS == LangAS::ptr32_uptr ||
|
||||
AS == LangAS::ptr64);
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_ADDRESSSPACES_H
|
||||
|
@ -2975,22 +2975,22 @@ def Win64 : IgnoredAttr {
|
||||
|
||||
def Ptr32 : TypeAttr {
|
||||
let Spellings = [Keyword<"__ptr32">];
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [Ptr32Docs];
|
||||
}
|
||||
|
||||
def Ptr64 : TypeAttr {
|
||||
let Spellings = [Keyword<"__ptr64">];
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [Ptr64Docs];
|
||||
}
|
||||
|
||||
def SPtr : TypeAttr {
|
||||
let Spellings = [Keyword<"__sptr">];
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [SPtrDocs];
|
||||
}
|
||||
|
||||
def UPtr : TypeAttr {
|
||||
let Spellings = [Keyword<"__uptr">];
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [UPtrDocs];
|
||||
}
|
||||
|
||||
def MSInheritance : InheritableAttr {
|
||||
|
@ -3139,6 +3139,44 @@ Since it is not widely used and has been removed from OpenCL 2.1, it is ignored
|
||||
by Clang.
|
||||
}];
|
||||
}
|
||||
|
||||
def Ptr32Docs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
The ``__ptr32`` qualifier represents a native pointer on a 32-bit system. On a
|
||||
64-bit system, a pointer with ``__ptr32`` is extended to a 64-bit pointer. The
|
||||
``__sptr`` and ``__uptr`` qualifiers can be used to specify whether the pointer
|
||||
is sign extended or zero extended. This qualifier is enabled under
|
||||
``-fms-extensions``.
|
||||
}];
|
||||
}
|
||||
|
||||
def Ptr64Docs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
The ``__ptr64`` qualifier represents a native pointer on a 64-bit system. On a
|
||||
32-bit system, a ``__ptr64`` pointer is truncated to a 32-bit pointer. This
|
||||
qualifier is enabled under ``-fms-extensions``.
|
||||
}];
|
||||
}
|
||||
|
||||
def SPtrDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
The ``__sptr`` qualifier specifies that a 32-bit pointer should be sign
|
||||
extended when converted to a 64-bit pointer.
|
||||
}];
|
||||
}
|
||||
|
||||
def UPtrDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
The ``__uptr`` qualifier specifies that a 32-bit pointer should be zero
|
||||
extended when converted to a 64-bit pointer.
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
def NullabilityDocs : DocumentationCategory<"Nullability Attributes"> {
|
||||
let Content = [{
|
||||
Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``).
|
||||
|
@ -825,15 +825,18 @@ static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
|
||||
// The fake address space map must have a distinct entry for each
|
||||
// language-specific address space.
|
||||
static const unsigned FakeAddrSpaceMap[] = {
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // cuda_device
|
||||
6, // cuda_constant
|
||||
7 // cuda_shared
|
||||
0, // Default
|
||||
1, // opencl_global
|
||||
3, // opencl_local
|
||||
2, // opencl_constant
|
||||
0, // opencl_private
|
||||
4, // opencl_generic
|
||||
5, // cuda_device
|
||||
6, // cuda_constant
|
||||
7, // cuda_shared
|
||||
8, // ptr32_sptr
|
||||
9, // ptr32_uptr
|
||||
10 // ptr64
|
||||
};
|
||||
return &FakeAddrSpaceMap;
|
||||
} else {
|
||||
@ -2832,6 +2835,16 @@ QualType ASTContext::getObjCGCQualType(QualType T,
|
||||
return getExtQualType(TypeNode, Quals);
|
||||
}
|
||||
|
||||
QualType ASTContext::removePtrSizeAddrSpace(QualType T) const {
|
||||
if (const PointerType *Ptr = T->getAs<PointerType>()) {
|
||||
QualType Pointee = Ptr->getPointeeType();
|
||||
if (isPtrSizeAddressSpace(Pointee.getAddressSpace())) {
|
||||
return getPointerType(removeAddrSpaceQualType(Pointee));
|
||||
}
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
|
||||
FunctionType::ExtInfo Info) {
|
||||
if (T->getExtInfo() == Info)
|
||||
@ -2906,6 +2919,29 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
|
||||
getFunctionTypeWithExceptionSpec(U, EST_None)));
|
||||
}
|
||||
|
||||
QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
|
||||
if (const auto *Proto = T->getAs<FunctionProtoType>()) {
|
||||
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
|
||||
SmallVector<QualType, 16> Args(Proto->param_types());
|
||||
for (unsigned i = 0, n = Args.size(); i != n; ++i)
|
||||
Args[i] = removePtrSizeAddrSpace(Args[i]);
|
||||
return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
|
||||
}
|
||||
|
||||
if (const FunctionNoProtoType *Proto = T->getAs<FunctionNoProtoType>()) {
|
||||
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
|
||||
return getFunctionNoProtoType(RetTy, Proto->getExtInfo());
|
||||
}
|
||||
|
||||
return T;
|
||||
}
|
||||
|
||||
bool ASTContext::hasSameFunctionTypeIgnoringPtrSizes(QualType T, QualType U) {
|
||||
return hasSameType(T, U) ||
|
||||
hasSameType(getFunctionTypeWithoutPtrSizes(T),
|
||||
getFunctionTypeWithoutPtrSizes(U));
|
||||
}
|
||||
|
||||
void ASTContext::adjustExceptionSpec(
|
||||
FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||
bool AsWritten) {
|
||||
|
@ -2301,6 +2301,16 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp
|
||||
case LangAS::cuda_device: ASString = "CUdevice"; break;
|
||||
case LangAS::cuda_constant: ASString = "CUconstant"; break;
|
||||
case LangAS::cuda_shared: ASString = "CUshared"; break;
|
||||
// <ptrsize-addrspace> ::= [ "ptr32_sptr" | "ptr32_uptr" | "ptr64" ]
|
||||
case LangAS::ptr32_sptr:
|
||||
ASString = "ptr32_sptr";
|
||||
break;
|
||||
case LangAS::ptr32_uptr:
|
||||
ASString = "ptr32_uptr";
|
||||
break;
|
||||
case LangAS::ptr64:
|
||||
ASString = "ptr64";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ASString.empty())
|
||||
|
@ -279,8 +279,6 @@ class MicrosoftCXXNameMangler {
|
||||
|
||||
ASTContext &getASTContext() const { return Context.getASTContext(); }
|
||||
|
||||
// FIXME: If we add support for __ptr32/64 qualifiers, then we should push
|
||||
// this check into mangleQualifiers().
|
||||
const bool PointersAre64Bit;
|
||||
|
||||
public:
|
||||
@ -335,6 +333,13 @@ private:
|
||||
return ND == Structor || getStructor(ND) == Structor;
|
||||
}
|
||||
|
||||
bool is64BitPointer(Qualifiers Quals) const {
|
||||
LangAS AddrSpace = Quals.getAddressSpace();
|
||||
return AddrSpace == LangAS::ptr64 ||
|
||||
(PointersAre64Bit && !(AddrSpace == LangAS::ptr32_sptr ||
|
||||
AddrSpace == LangAS::ptr32_uptr));
|
||||
}
|
||||
|
||||
void mangleUnqualifiedName(const NamedDecl *ND) {
|
||||
mangleUnqualifiedName(ND, ND->getDeclName());
|
||||
}
|
||||
@ -1703,8 +1708,10 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
|
||||
|
||||
void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
|
||||
QualType PointeeType) {
|
||||
if (PointersAre64Bit &&
|
||||
(PointeeType.isNull() || !PointeeType->isFunctionType()))
|
||||
// Check if this is a default 64-bit pointer or has __ptr64 qualifier.
|
||||
bool is64Bit = PointeeType.isNull() ? PointersAre64Bit :
|
||||
is64BitPointer(PointeeType.getQualifiers());
|
||||
if (is64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType()))
|
||||
Out << 'E';
|
||||
|
||||
if (Quals.hasRestrict())
|
||||
@ -1864,6 +1871,10 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
|
||||
case LangAS::cuda_shared:
|
||||
Extra.mangleSourceName("_ASCUshared");
|
||||
break;
|
||||
case LangAS::ptr32_sptr:
|
||||
case LangAS::ptr32_uptr:
|
||||
case LangAS::ptr64:
|
||||
llvm_unreachable("don't mangle ptr address spaces with _AS");
|
||||
}
|
||||
}
|
||||
|
||||
@ -2597,10 +2608,13 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals,
|
||||
manglePointerCVQualifiers(Quals);
|
||||
manglePointerExtQualifiers(Quals, PointeeType);
|
||||
|
||||
if (PointeeType.getQualifiers().hasAddressSpace())
|
||||
mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
|
||||
else
|
||||
// For pointer size address spaces, go down the same type mangling path as
|
||||
// non address space types.
|
||||
LangAS AddrSpace = PointeeType.getQualifiers().getAddressSpace();
|
||||
if (isPtrSizeAddressSpace(AddrSpace) || AddrSpace == LangAS::Default)
|
||||
mangleType(PointeeType, Range);
|
||||
else
|
||||
mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range);
|
||||
}
|
||||
|
||||
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
|
||||
|
@ -1792,6 +1792,12 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
|
||||
return "__constant__";
|
||||
case LangAS::cuda_shared:
|
||||
return "__shared__";
|
||||
case LangAS::ptr32_sptr:
|
||||
return "__sptr __ptr32";
|
||||
case LangAS::ptr32_uptr:
|
||||
return "__uptr __ptr32";
|
||||
case LangAS::ptr64:
|
||||
return "__ptr64";
|
||||
default:
|
||||
return std::to_string(toTargetAddressSpace(AS));
|
||||
}
|
||||
|
@ -47,7 +47,10 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
|
||||
Generic, // opencl_generic
|
||||
Global, // cuda_device
|
||||
Constant, // cuda_constant
|
||||
Local // cuda_shared
|
||||
Local, // cuda_shared
|
||||
Generic, // ptr32_sptr
|
||||
Generic, // ptr32_uptr
|
||||
Generic // ptr64
|
||||
};
|
||||
|
||||
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
|
||||
@ -59,7 +62,11 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
|
||||
Generic, // opencl_generic
|
||||
Global, // cuda_device
|
||||
Constant, // cuda_constant
|
||||
Local // cuda_shared
|
||||
Local, // cuda_shared
|
||||
Generic, // ptr32_sptr
|
||||
Generic, // ptr32_uptr
|
||||
Generic // ptr64
|
||||
|
||||
};
|
||||
} // namespace targets
|
||||
} // namespace clang
|
||||
|
@ -33,6 +33,9 @@ static const unsigned NVPTXAddrSpaceMap[] = {
|
||||
1, // cuda_device
|
||||
4, // cuda_constant
|
||||
3, // cuda_shared
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0 // ptr64
|
||||
};
|
||||
|
||||
/// The DWARF address class. Taken from
|
||||
|
@ -30,7 +30,10 @@ static const unsigned SPIRAddrSpaceMap[] = {
|
||||
4, // opencl_generic
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0 // cuda_shared
|
||||
0, // cuda_shared
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0 // ptr64
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo {
|
||||
|
@ -39,7 +39,10 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
|
||||
0, // opencl_generic
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0 // cuda_shared
|
||||
0, // cuda_shared
|
||||
0, // ptr32_sptr
|
||||
0, // ptr32_uptr
|
||||
0, // ptr64
|
||||
};
|
||||
|
||||
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
|
||||
|
@ -22,6 +22,21 @@
|
||||
namespace clang {
|
||||
namespace targets {
|
||||
|
||||
static const unsigned X86AddrSpaceMap[] = {
|
||||
0, // Default
|
||||
0, // opencl_global
|
||||
0, // opencl_local
|
||||
0, // opencl_constant
|
||||
0, // opencl_private
|
||||
0, // opencl_generic
|
||||
0, // cuda_device
|
||||
0, // cuda_constant
|
||||
0, // cuda_shared
|
||||
270, // ptr32_sptr
|
||||
271, // ptr32_uptr
|
||||
272 // ptr64
|
||||
};
|
||||
|
||||
// X86 target abstract base class; x86-32 and x86-64 are very close, so
|
||||
// most of the implementation can be shared.
|
||||
class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
|
||||
@ -45,6 +60,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
|
||||
AMD3DNowAthlon
|
||||
} MMX3DNowLevel = NoMMX3DNow;
|
||||
enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP;
|
||||
enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };
|
||||
|
||||
bool HasAES = false;
|
||||
bool HasVAES = false;
|
||||
@ -130,6 +146,7 @@ public:
|
||||
X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
|
||||
: TargetInfo(Triple) {
|
||||
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
|
||||
AddrSpaceMap = &X86AddrSpaceMap;
|
||||
}
|
||||
|
||||
const char *getLongDoubleMangling() const override {
|
||||
@ -328,6 +345,18 @@ public:
|
||||
void setSupportedOpenCLOpts() override {
|
||||
getSupportedOpenCLOpts().supportAll();
|
||||
}
|
||||
|
||||
uint64_t getPointerWidthV(unsigned AddrSpace) const override {
|
||||
if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr)
|
||||
return 32;
|
||||
if (AddrSpace == ptr64)
|
||||
return 64;
|
||||
return PointerWidth;
|
||||
}
|
||||
|
||||
uint64_t getPointerAlignV(unsigned AddrSpace) const override {
|
||||
return getPointerWidthV(AddrSpace);
|
||||
}
|
||||
};
|
||||
|
||||
// X86-32 generic target
|
||||
|
@ -3656,6 +3656,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
||||
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
|
||||
}
|
||||
|
||||
// Check if the function types are compatible when pointer size address
|
||||
// spaces are ignored.
|
||||
if (Context.hasSameFunctionTypeIgnoringPtrSizes(OldQType, NewQType))
|
||||
return false;
|
||||
|
||||
// GNU C permits a K&R definition to follow a prototype declaration
|
||||
// if the declared types of the parameters in the K&R definition
|
||||
// match the types in the prototype declaration, even when the
|
||||
|
@ -2933,8 +2933,12 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType,
|
||||
N = NewType->param_type_begin(),
|
||||
E = OldType->param_type_end();
|
||||
O && (O != E); ++O, ++N) {
|
||||
if (!Context.hasSameType(O->getUnqualifiedType(),
|
||||
N->getUnqualifiedType())) {
|
||||
// Ignore address spaces in pointee type. This is to disallow overloading
|
||||
// on __ptr32/__ptr64 address spaces.
|
||||
QualType Old = Context.removePtrSizeAddrSpace(O->getUnqualifiedType());
|
||||
QualType New = Context.removePtrSizeAddrSpace(N->getUnqualifiedType());
|
||||
|
||||
if (!Context.hasSameType(Old, New)) {
|
||||
if (ArgPos)
|
||||
*ArgPos = O - OldType->param_type_begin();
|
||||
return false;
|
||||
|
@ -6497,37 +6497,38 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
||||
break;
|
||||
}
|
||||
|
||||
llvm::SmallSet<attr::Kind, 2> Attrs;
|
||||
attr::Kind NewAttrKind = A->getKind();
|
||||
QualType Desugared = Type;
|
||||
const AttributedType *AT = dyn_cast<AttributedType>(Type);
|
||||
while (AT) {
|
||||
attr::Kind CurAttrKind = AT->getAttrKind();
|
||||
|
||||
// You cannot specify duplicate type attributes, so if the attribute has
|
||||
// already been applied, flag it.
|
||||
if (NewAttrKind == CurAttrKind) {
|
||||
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// You cannot have both __sptr and __uptr on the same type, nor can you
|
||||
// have __ptr32 and __ptr64.
|
||||
if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) ||
|
||||
(CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) {
|
||||
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||
<< "'__ptr32'" << "'__ptr64'";
|
||||
return true;
|
||||
} else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) ||
|
||||
(CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) {
|
||||
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||
<< "'__sptr'" << "'__uptr'";
|
||||
return true;
|
||||
}
|
||||
|
||||
Desugared = AT->getEquivalentType();
|
||||
Attrs.insert(AT->getAttrKind());
|
||||
Desugared = AT->getModifiedType();
|
||||
AT = dyn_cast<AttributedType>(Desugared);
|
||||
}
|
||||
|
||||
// You cannot specify duplicate type attributes, so if the attribute has
|
||||
// already been applied, flag it.
|
||||
if (Attrs.count(NewAttrKind)) {
|
||||
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
|
||||
return true;
|
||||
}
|
||||
Attrs.insert(NewAttrKind);
|
||||
|
||||
// You cannot have both __sptr and __uptr on the same type, nor can you
|
||||
// have __ptr32 and __ptr64.
|
||||
if (Attrs.count(attr::Ptr32) && Attrs.count(attr::Ptr64)) {
|
||||
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||
<< "'__ptr32'"
|
||||
<< "'__ptr64'";
|
||||
return true;
|
||||
} else if (Attrs.count(attr::SPtr) && Attrs.count(attr::UPtr)) {
|
||||
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
|
||||
<< "'__sptr'"
|
||||
<< "'__uptr'";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pointer type qualifiers can only operate on pointer types, but not
|
||||
// pointer-to-member types.
|
||||
//
|
||||
@ -6543,7 +6544,26 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
|
||||
return true;
|
||||
}
|
||||
|
||||
Type = State.getAttributedType(A, Type, Type);
|
||||
// Add address space to type based on its attributes.
|
||||
LangAS ASIdx = LangAS::Default;
|
||||
uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0);
|
||||
if (PtrWidth == 32) {
|
||||
if (Attrs.count(attr::Ptr64))
|
||||
ASIdx = LangAS::ptr64;
|
||||
else if (Attrs.count(attr::UPtr))
|
||||
ASIdx = LangAS::ptr32_uptr;
|
||||
} else if (PtrWidth == 64 && Attrs.count(attr::Ptr32)) {
|
||||
if (Attrs.count(attr::UPtr))
|
||||
ASIdx = LangAS::ptr32_uptr;
|
||||
else
|
||||
ASIdx = LangAS::ptr32_sptr;
|
||||
}
|
||||
|
||||
QualType Pointee = Type->getPointeeType();
|
||||
if (ASIdx != LangAS::Default)
|
||||
Pointee = S.Context.getAddrSpaceQualType(
|
||||
S.Context.removeAddrSpaceQualType(Pointee), ASIdx);
|
||||
Type = State.getAttributedType(A, Type, S.Context.getPointerType(Pointee));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
51
clang/test/CodeGen/ms-mixed-ptr-sizes.c
Normal file
51
clang/test/CodeGen/ms-mixed-ptr-sizes.c
Normal file
@ -0,0 +1,51 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -emit-llvm -O2 \
|
||||
// RUN: < %s | FileCheck %s --check-prefixes=X64,CHECK
|
||||
// RUN: %clang_cc1 -triple i386-pc-win32 -fms-extensions -emit-llvm -O2 \
|
||||
// RUN: < %s | FileCheck %s --check-prefixes=X86,CHECK
|
||||
|
||||
struct Foo {
|
||||
int * __ptr32 p32;
|
||||
int * __ptr64 p64;
|
||||
};
|
||||
void use_foo(struct Foo *f);
|
||||
void test_sign_ext(struct Foo *f, int * __ptr32 __sptr i) {
|
||||
// X64-LABEL: define dso_local void @test_sign_ext({{.*}}i32 addrspace(270)* %i)
|
||||
// X86-LABEL: define dso_local void @test_sign_ext(%struct.Foo* %f, i32* %i)
|
||||
// X64: %{{.+}} = addrspacecast i32 addrspace(270)* %i to i32*
|
||||
// X86: %{{.+}} = addrspacecast i32* %i to i32 addrspace(272)*
|
||||
f->p64 = i;
|
||||
use_foo(f);
|
||||
}
|
||||
void test_zero_ext(struct Foo *f, int * __ptr32 __uptr i) {
|
||||
// X64-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* %i)
|
||||
// X86-LABEL: define dso_local void @test_zero_ext({{.*}}i32 addrspace(271)* %i)
|
||||
// X64: %{{.+}} = addrspacecast i32 addrspace(271)* %i to i32*
|
||||
// X86: %{{.+}} = addrspacecast i32 addrspace(271)* %i to i32 addrspace(272)*
|
||||
f->p64 = i;
|
||||
use_foo(f);
|
||||
}
|
||||
void test_trunc(struct Foo *f, int * __ptr64 i) {
|
||||
// X64-LABEL: define dso_local void @test_trunc(%struct.Foo* %f, i32* %i)
|
||||
// X86-LABEL: define dso_local void @test_trunc({{.*}}i32 addrspace(272)* %i)
|
||||
// X64: %{{.+}} = addrspacecast i32* %i to i32 addrspace(270)*
|
||||
// X86: %{{.+}} = addrspacecast i32 addrspace(272)* %i to i32*
|
||||
f->p32 = i;
|
||||
use_foo(f);
|
||||
}
|
||||
void test_noop(struct Foo *f, int * __ptr32 i) {
|
||||
// X64-LABEL: define dso_local void @test_noop({{.*}}i32 addrspace(270)* %i)
|
||||
// X86-LABEL: define dso_local void @test_noop({{.*}}i32* %i)
|
||||
// X64-NOT: addrspacecast
|
||||
// X86-NOT: addrspacecast
|
||||
f->p32 = i;
|
||||
use_foo(f);
|
||||
}
|
||||
|
||||
void test_other(struct Foo *f, __attribute__((address_space(10))) int *i) {
|
||||
// X64-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* %i)
|
||||
// X86-LABEL: define dso_local void @test_other({{.*}}i32 addrspace(10)* %i)
|
||||
// X64: %{{.+}} = addrspacecast i32 addrspace(10)* %i to i32 addrspace(270)*
|
||||
// X86: %{{.+}} = addrspacecast i32 addrspace(10)* %i to i32*
|
||||
f->p32 = (int * __ptr32)i;
|
||||
use_foo(f);
|
||||
}
|
18
clang/test/CodeGenCXX/mangle-ptr-size-address-space.cpp
Normal file
18
clang/test/CodeGenCXX/mangle-ptr-size-address-space.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// RUN: %clang_cc1 -fms-extensions -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s --check-prefixes=CHECK
|
||||
// RUN: %clang_cc1 -fms-extensions -emit-llvm -triple x86_64-windows-msvc -o - %s | FileCheck %s --check-prefixes=WIN
|
||||
|
||||
// CHECK-LABEL: define {{.*}}void @_Z2f0PU10ptr32_sptri
|
||||
// WIN-LABEL: define {{.*}}void @"?f0@@YAXPAH@Z"
|
||||
void f0(int * __ptr32 p) {}
|
||||
|
||||
// CHECK-LABEL: define {{.*}}i8 addrspace(271)* @_Z2f1PU10ptr32_sptri
|
||||
// WIN-LABEL: define {{.*}}i8 addrspace(271)* @"?f1@@YAPAXPAH@Z"
|
||||
void * __ptr32 __uptr f1(int * __ptr32 p) { return 0; }
|
||||
|
||||
// CHECK-LABEL: define {{.*}}void @_Z2f2Pi
|
||||
// WIN-LABEL: define {{.*}}void @"?f2@@YAXPEAH@Z"
|
||||
void f2(int * __ptr64 p) {}
|
||||
|
||||
// CHECK-LABEL: define {{.*}}i8* @_Z2f3Pi
|
||||
// WIN-LABEL: define {{.*}}i8* @"?f3@@YAPEAXPEAH@Z"
|
||||
void * __ptr64 f3(int * __ptr64 p) { return 0; }
|
@ -150,6 +150,20 @@ void ptr_func(int * __ptr64 i) {} // expected-error {{redefinition of 'ptr_func'
|
||||
void ptr_func2(int * __sptr __ptr32 i) {} // expected-note {{previous definition is here}}
|
||||
void ptr_func2(int * __uptr __ptr32 i) {} // expected-error {{redefinition of 'ptr_func2'}}
|
||||
|
||||
// Check for warning when return types have the type attribute.
|
||||
void *__ptr32 ptr_func3() { return 0; } // expected-note {{previous definition is here}}
|
||||
void *__ptr64 ptr_func3() { return 0; } // expected-error {{redefinition of 'ptr_func3'}}
|
||||
|
||||
// Test that __ptr32/__ptr64 can be passed as arguments with other address
|
||||
// spaces.
|
||||
void ptr_func4(int *i);
|
||||
void ptr_func5(int *__ptr32 i);
|
||||
void test_ptr_arguments() {
|
||||
int *__ptr64 i64;
|
||||
ptr_func4(i64);
|
||||
ptr_func5(i64);
|
||||
}
|
||||
|
||||
int * __sptr __ptr32 __sptr wrong4; // expected-warning {{attribute '__sptr' is already applied}}
|
||||
|
||||
__ptr32 int *wrong5; // expected-error {{'__ptr32' attribute only applies to pointer arguments}}
|
||||
|
@ -43,7 +43,7 @@ void neg() {
|
||||
|
||||
template <long int I>
|
||||
void tooBig() {
|
||||
__attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388598)}}
|
||||
__attribute__((address_space(I))) int *bounds; // expected-error {{address space is larger than the maximum supported (8388595)}}
|
||||
}
|
||||
|
||||
template <long int I>
|
||||
@ -101,7 +101,7 @@ int main() {
|
||||
car<1, 2, 3>(); // expected-note {{in instantiation of function template specialization 'car<1, 2, 3>' requested here}}
|
||||
HasASTemplateFields<1> HASTF;
|
||||
neg<-1>(); // expected-note {{in instantiation of function template specialization 'neg<-1>' requested here}}
|
||||
correct<0x7FFFF6>();
|
||||
correct<0x7FFFF3>();
|
||||
tooBig<8388650>(); // expected-note {{in instantiation of function template specialization 'tooBig<8388650>' requested here}}
|
||||
|
||||
__attribute__((address_space(1))) char *x;
|
||||
|
Loading…
Reference in New Issue
Block a user