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 @@ -2361,6 +2361,10 @@ /// Determine if two types are similar, ignoring only CVR qualifiers. bool hasCvrSimilarType(QualType T1, QualType T2); + /// Determine if two types are similar, ignoring only pointer size address + /// space. + bool hasPtrSizeSimilarType(QualType T1, QualType T2); + /// Retrieves the "canonical" nested name specifier for a /// given nested name specifier. /// 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 @@ -472,7 +472,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 mixed sized pointers to be equivalent. + (isPtrSizeOrDefaultAddressSpace(A) && + isPtrSizeOrDefaultAddressSpace(B)); } /// 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 isPtrSizeOrDefaultAddressSpace(LangAS AS) { + return (AS == LangAS::Default || AS == LangAS::ptr32_sptr || + AS == LangAS::ptr32_uptr || AS == LangAS::ptr64); +} + } // namespace clang #endif // LLVM_CLANG_BASIC_ADDRESSSPACES_H 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 @@ -789,15 +789,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 { @@ -5314,6 +5317,31 @@ } } +bool ASTContext::hasPtrSizeSimilarType(QualType T1, QualType T2) { + while (true) { + const PointerType *T1Ptr = dyn_cast(T1); + const PointerType *T2Ptr = dyn_cast(T2); + + if (!T1Ptr || !T2Ptr) + return hasSameType(T1, T2); + + Qualifiers Quals1, Quals2; + T1 = getUnqualifiedArrayType(T1Ptr->getPointeeType(), Quals1); + T2 = getUnqualifiedArrayType(T2Ptr->getPointeeType(), Quals2); + + if (isPtrSizeOrDefaultAddressSpace(Quals1.getAddressSpace())) + Quals1.removeAddressSpace(); + if (isPtrSizeOrDefaultAddressSpace(Quals2.getAddressSpace())) + Quals2.removeAddressSpace(); + + if (Quals1 != Quals2) + return false; + + if (hasSameType(T1, T2)) + return true; + } +} + DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { 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 @@ -2266,6 +2266,10 @@ 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()); } @@ -1661,6 +1666,7 @@ // ::= 3 # ? // ::= 4 # ? // ::= 5 # not really based + bool HasConst = Quals.hasConst(), HasVolatile = Quals.hasVolatile(); @@ -1709,8 +1715,10 @@ void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType) { - if (PointersAre64Bit && - (PointeeType.isNull() || !PointeeType->isFunctionType())) + // Check if this is a defulat 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()) @@ -2603,10 +2611,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 (isPtrSizeOrDefaultAddressSpace(AddrSpace)) 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 @@ -1819,6 +1819,15 @@ case LangAS::cuda_shared: OS << "__shared__"; break; + case LangAS::ptr32_sptr: + OS << "__ptr32_sptr"; + break; + case LangAS::ptr32_uptr: + OS << "__ptr32_uptr"; + break; + case LangAS::ptr64: + OS << "__ptr64"; + break; default: OS << "__attribute__((address_space("; OS << toTargetAddressSpace(addrspace); 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 @@ -46,7 +46,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 = { @@ -58,7 +61,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/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2871,6 +2871,14 @@ O && (O != E); ++O, ++N) { if (!Context.hasSameType(O->getUnqualifiedType(), N->getUnqualifiedType())) { + + // Treat pointers with pointer size qualifiers as equivalent to pointers + // without those qualifiers, so pointer size qualifiers cannot be used to + // overload. + if (Context.hasPtrSizeSimilarType(O->getUnqualifiedType(), + N->getUnqualifiedType())) + continue; + 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 @@ -6462,6 +6462,8 @@ attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast(Type); + llvm::SmallSet Attrs; + Attrs.insert(NewAttrKind); while (AT) { attr::Kind CurAttrKind = AT->getAttrKind(); @@ -6488,7 +6490,8 @@ } Desugared = AT->getEquivalentType(); - AT = dyn_cast(Desugared); + AT = dyn_cast(AT->getModifiedType()); + Attrs.insert(CurAttrKind); } // Pointer type qualifiers can only operate on pointer types, but not @@ -6506,7 +6509,26 @@ return true; } - Type = State.getAttributedType(A, Type, Type); + // Add address space qualifier. + 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,33 @@ +// RUN: %clang_cc1 -triple i386-unknown-windows-msvc -fms-extensions -O0 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=X86 +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fms-extensions -O0 \ +// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=X64 + +// X86: %p32 = alloca i32*, align 4 +// X86: %p64 = alloca i32 addrspace(272)*, align 8 +// X86: %p32s = alloca i32*, align 4 +// X86: %p32u = alloca i32 addrspace(271)*, align 4 +// X86: %p64s = alloca i32 addrspace(272)*, align 8 +// X86: %p64u = alloca i32 addrspace(272)*, align 8 +// X86: %ps = alloca i32*, align 4 +// X86: %pu = alloca i32 addrspace(271)*, align 4 + +// X64: %p32 = alloca i32 addrspace(270)*, align 4 +// X64: %p64 = alloca i32*, align 8 +// X64: %p32s = alloca i32 addrspace(270)*, align 4 +// X64: %p32u = alloca i32 addrspace(271)*, align 4 +// X64: %p64s = alloca i32*, align 8 +// X64: %p64u = alloca i32*, align 8 +// X64: %ps = alloca i32*, align 8 +// X64: %pu = alloca i32*, align 8 + +void test() { + int * __ptr32 p32; + int * __ptr64 p64; + int * __ptr32 __sptr p32s; + int * __ptr32 __uptr p32u; + int * __ptr64 __sptr p64s; + int * __ptr64 __uptr p64u; + int * __sptr ps; + int * __uptr pu; +} 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 @@ -143,12 +143,14 @@ int * __sptr __sptr wrong3; // expected-warning {{attribute '__sptr' is already applied}} // It is illegal to overload based on the type attribute. +// Expect conflicting types warning instead of redefinition warning because +// pointers with type attributes are lowered to different types. void ptr_func(int * __ptr32 i) {} // expected-note {{previous definition is here}} -void ptr_func(int * __ptr64 i) {} // expected-error {{redefinition of 'ptr_func'}} +void ptr_func(int * __ptr64 i) {} // expected-error {{conflicting types for 'ptr_func'}} // It is also illegal to overload based on the pointer type attribute. 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'}} +void ptr_func2(int * __uptr __ptr32 i) {} // expected-error {{conflicting types for 'ptr_func2'}} int * __sptr __ptr32 __sptr wrong4; // expected-warning {{attribute '__sptr' is already applied}} 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; diff --git a/llvm/lib/Target/X86/X86.h b/llvm/lib/Target/X86/X86.h --- a/llvm/lib/Target/X86/X86.h +++ b/llvm/lib/Target/X86/X86.h @@ -146,4 +146,15 @@ void initializeX86SpeculativeLoadHardeningPassPass(PassRegistry &); } // End llvm namespace +namespace X86AS { +enum : unsigned { + GS = 256, + FS = 257, + SS = 258, + PTR32_SPTR = 270, + PTR32_UPTR = 271, + PTR64 = 272 +}; +} + #endif diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2219,12 +2219,11 @@ AM.Scale = cast(Mgs->getScale())->getZExtValue(); unsigned AddrSpace = cast(Parent)->getPointerInfo().getAddrSpace(); - // AddrSpace 256 -> GS, 257 -> FS, 258 -> SS. - if (AddrSpace == 256) + if (AddrSpace == X86AS::GS) AM.Segment = CurDAG->getRegister(X86::GS, MVT::i16); - if (AddrSpace == 257) + if (AddrSpace == X86AS::FS) AM.Segment = CurDAG->getRegister(X86::FS, MVT::i16); - if (AddrSpace == 258) + if (AddrSpace == X86AS::SS) AM.Segment = CurDAG->getRegister(X86::SS, MVT::i16); SDLoc DL(N); diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -277,6 +277,10 @@ setOperationAction(ISD::FP_TO_UINT , MVT::i8 , Promote); setOperationAction(ISD::FP_TO_UINT , MVT::i16 , Promote); + // Handle address space casts between mixed sized pointers. + setOperationAction(ISD::ADDRSPACECAST, MVT::i32, Custom); + setOperationAction(ISD::ADDRSPACECAST, MVT::i64, Custom); + if (Subtarget.is64Bit()) { if (!Subtarget.useSoftFloat() && Subtarget.hasAVX512()) { // FP_TO_UINT-i32/i64 is legal for f32/f64, but custom for f80. @@ -2353,10 +2357,21 @@ return TargetLowering::getSafeStackPointerLocation(IRB); } +static bool isPtrSizeOrDefaultAddrSpace(unsigned AS) { + return (AS == 0 || AS == X86AS::PTR32_SPTR || AS == X86AS::PTR32_UPTR || + AS == X86AS::PTR64); +} + bool X86TargetLowering::isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { assert(SrcAS != DestAS && "Expected different address spaces!"); + const TargetMachine &TM = getTargetMachine(); + if ((isPtrSizeOrDefaultAddrSpace(SrcAS) && + isPtrSizeOrDefaultAddrSpace(DestAS)) && + TM.getPointerSize(SrcAS) != TM.getPointerSize(DestAS)) + return false; + return SrcAS < 256 && DestAS < 256; } @@ -27409,6 +27424,33 @@ return DAG.getMergeValues({Extract, NewGather.getValue(2)}, dl); } +static SDValue LowerADDRSPACECAST(SDValue Op, SelectionDAG &DAG) { + SDLoc dl(Op); + SDValue Src = Op.getOperand(0); + MVT DstVT = Op.getSimpleValueType(); + + AddrSpaceCastSDNode *N = cast(Op.getNode()); + unsigned SrcAS = N->getSrcAddressSpace(); + unsigned DstAS = N->getDestAddressSpace(); + + assert(SrcAS != DstAS && + "addrspacecast must be between different address spaces"); + + if (isPtrSizeOrDefaultAddrSpace(SrcAS) && + isPtrSizeOrDefaultAddrSpace(DstAS)) { + if (SrcAS == X86AS::PTR32_UPTR && DstVT == MVT::i64) { + Op = DAG.getNode(ISD::ZERO_EXTEND, dl, DstVT, Src); + } else if (DstVT == MVT::i64) { + Op = DAG.getNode(ISD::SIGN_EXTEND, dl, DstVT, Src); + } else if (DstVT == MVT::i32) { + Op = DAG.getNode(ISD::TRUNCATE, dl, DstVT, Src); + } + } else { + report_fatal_error("Bad address space in addrspacecast"); + } + return Op; +} + SDValue X86TargetLowering::LowerGC_TRANSITION_START(SDValue Op, SelectionDAG &DAG) const { // TODO: Eventually, the lowering of these nodes should be informed by or @@ -27571,6 +27613,8 @@ case ISD::GC_TRANSITION_START: return LowerGC_TRANSITION_START(Op, DAG); case ISD::GC_TRANSITION_END: return LowerGC_TRANSITION_END(Op, DAG); + case ISD::ADDRSPACECAST: + return LowerADDRSPACECAST(Op, DAG); } } @@ -28493,6 +28537,32 @@ Results.push_back(Res.getValue(1)); return; } + case ISD::ADDRSPACECAST: { + SDValue Src = N->getOperand(0); + EVT DstVT = N->getValueType(0); + AddrSpaceCastSDNode *CastN = cast(N); + unsigned SrcAS = CastN->getSrcAddressSpace(); + unsigned DstAS = CastN->getDestAddressSpace(); + + assert(SrcAS != DstAS && + "addrspacecast must be between different address spaces"); + + SDValue Res; + if (isPtrSizeOrDefaultAddrSpace(SrcAS) && + isPtrSizeOrDefaultAddrSpace(DstAS)) { + if (SrcAS == X86AS::PTR32_UPTR && DstVT == MVT::i64) + Res = DAG.getNode(ISD::ZERO_EXTEND, dl, DstVT, Src); + else if (DstVT == MVT::i64) + Res = DAG.getNode(ISD::SIGN_EXTEND, dl, DstVT, Src); + else + Res = DAG.getNode(ISD::TRUNCATE, dl, DstVT, Src); + } else { + report_fatal_error("Unrecognized addrspacecast type legalization"); + } + + Results.push_back(Res); + return; + } } } diff --git a/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll b/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll @@ -0,0 +1,110 @@ +; RUN: llc < %s | FileCheck --check-prefixes=CHECK %s + +; Source to regenerate: +; struct Foo { +; int * __ptr32 p32; +; int * __ptr64 p64; +; } +; void test_sign_ext(struct Foo *f, int * __ptr32 i) { +; f->p64 = i; +; } +; void test_sign_ext2(struct Foo *f, int * __ptr32 __sptr i) { +; f->p64 = i; +; } +; void test_zero_ext(struct Foo *f, int * __ptr32 __uptr i) { +; f->p64 = i; +; } +; void test_trunc(struct Foo *f, int * __ptr64 i) { +; f->p32 = i; +; } +; void test_noop1(struct Foo *f, int * __ptr32 i) { +; f->p32 = i; +; } +; void test_noop2(struct Foo *f, int * __ptr64 i) { +; f->p64 = i; +; } +; +; $ clang -cc1 -triple x86_64-windows-msvc -fms-extensions -O2 -emit-llvm -x c t.cpp + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-windows-msvc" + +%struct.Foo = type { i32 addrspace(270)*, i32* } + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_sign_ext(%struct.Foo* nocapture %f, i32 addrspace(270)* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_sign_ext: +; CHECK: movslq %edx, %rax +entry: + %0 = addrspacecast i32 addrspace(270)* %i to i32* + %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 + store i32* %0, i32** %p64, align 8, !tbaa !2 + ret void +} + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_sign_ext2(%struct.Foo* nocapture %f, i32 addrspace(270)* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_sign_ext2: +; CHECK: movslq %edx, %rax +entry: + %0 = addrspacecast i32 addrspace(270)* %i to i32* + %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 + store i32* %0, i32** %p64, align 8, !tbaa !2 + ret void +} + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_zero_ext(%struct.Foo* nocapture %f, i32 addrspace(271)* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_zero_ext: +; CHECK: movl %edx, %eax +entry: + %0 = addrspacecast i32 addrspace(271)* %i to i32* + %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 + store i32* %0, i32** %p64, align 8, !tbaa !2 + ret void +} + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_trunc(%struct.Foo* nocapture %f, i32* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_trunc: +; CHECK: movl %edx, (%rcx) +entry: + %0 = addrspacecast i32* %i to i32 addrspace(270)* + %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 0 + store i32 addrspace(270)* %0, i32 addrspace(270)** %p32, align 8, !tbaa !7 + ret void +} + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_noop1(%struct.Foo* nocapture %f, i32 addrspace(270)* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_noop1: +; CHECK: movl %edx, (%rcx) +entry: + %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 0 + store i32 addrspace(270)* %i, i32 addrspace(270)** %p32, align 8, !tbaa !7 + ret void +} + +; Function Attrs: nofree norecurse nounwind writeonly +define dso_local void @test_noop2(%struct.Foo* nocapture %f, i32* %i) local_unnamed_addr #0 { +; CHECK-LABEL: test_noop2: +; CHECK: movq %rdx, 8(%rcx) +entry: + %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 + store i32* %i, i32** %p64, align 8, !tbaa !2 + ret void +} + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git b4887f121b485fb2b6d4c1fa8296724fb78a244d)"} +!2 = !{!3, !4, i64 8} +!3 = !{!"Foo", !4, i64 0, !4, i64 8} +!4 = !{!"any pointer", !5, i64 0} +!5 = !{!"omnipotent char", !6, i64 0} +!6 = !{!"Simple C/C++ TBAA"} +!7 = !{!3, !4, i64 0}