diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1155,6 +1155,10 @@ /// 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 @@ 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; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -477,7 +477,10 @@ 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 diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h --- a/clang/include/clang/Basic/AddressSpaces.h +++ b/clang/include/clang/Basic/AddressSpaces.h @@ -42,6 +42,11 @@ 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 @@ (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 diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2975,22 +2975,22 @@ 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 { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3139,6 +3139,44 @@ 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``). diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -825,15 +825,18 @@ // 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 @@ return getExtQualType(TypeNode, Quals); } +QualType ASTContext::removePtrSizeAddrSpace(QualType T) const { + if (const PointerType *Ptr = T->getAs()) { + 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 @@ getFunctionTypeWithExceptionSpec(U, EST_None))); } +QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) { + if (const auto *Proto = T->getAs()) { + QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); + SmallVector 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()) { + 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) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2301,6 +2301,16 @@ case LangAS::cuda_device: ASString = "CUdevice"; break; case LangAS::cuda_constant: ASString = "CUconstant"; break; case LangAS::cuda_shared: ASString = "CUshared"; break; + // ::= [ "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()) diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -279,8 +279,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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, diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1792,6 +1792,12 @@ 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)); } diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -47,7 +47,10 @@ 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 @@ 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 diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -33,6 +33,9 @@ 1, // cuda_device 4, // cuda_constant 3, // cuda_shared + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 }; /// The DWARF address class. Taken from diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -30,7 +30,10 @@ 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 { diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -39,7 +39,10 @@ 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 { diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -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 @@ 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 @@ X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + AddrSpaceMap = &X86AddrSpaceMap; } const char *getLongDoubleMangling() const override { @@ -328,6 +345,18 @@ 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 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3656,6 +3656,11 @@ 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 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2933,8 +2933,12 @@ 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; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -6497,35 +6497,36 @@ break; } + llvm::SmallSet Attrs; attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast(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; - } + Attrs.insert(AT->getAttrKind()); + Desugared = AT->getModifiedType(); + AT = dyn_cast(Desugared); + } - // 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; - } + // 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); - Desugared = AT->getEquivalentType(); - AT = dyn_cast(Desugared); + // 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 @@ -6543,7 +6544,26 @@ 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; } diff --git a/clang/test/CodeGen/ms-mixed-ptr-sizes.c b/clang/test/CodeGen/ms-mixed-ptr-sizes.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/ms-mixed-ptr-sizes.c @@ -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); +} diff --git a/clang/test/CodeGenCXX/mangle-ptr-size-address-space.cpp b/clang/test/CodeGenCXX/mangle-ptr-size-address-space.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-ptr-size-address-space.cpp @@ -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; } diff --git a/clang/test/Sema/MicrosoftExtensions.c b/clang/test/Sema/MicrosoftExtensions.c --- a/clang/test/Sema/MicrosoftExtensions.c +++ b/clang/test/Sema/MicrosoftExtensions.c @@ -150,6 +150,20 @@ 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}} diff --git a/clang/test/SemaTemplate/address_space-dependent.cpp b/clang/test/SemaTemplate/address_space-dependent.cpp --- a/clang/test/SemaTemplate/address_space-dependent.cpp +++ b/clang/test/SemaTemplate/address_space-dependent.cpp @@ -43,7 +43,7 @@ template 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 @@ -101,7 +101,7 @@ 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;