diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -3307,6 +3307,10 @@ Note that LLVM does not permit pointers to void (``void*``) nor does it permit pointers to labels (``label*``). Use ``i8*`` instead. +LLVM is in the process of transitioning to opaque pointers. Opaque pointers do +not have a pointee type. Rather, instructions interacting through pointers +typically specify the type of the underlying memory they are interacting with. + :Syntax: :: @@ -3322,6 +3326,10 @@ +-------------------------+--------------------------------------------------------------------------------------------------------------+ | ``i32 addrspace(5)*`` | A :ref:`pointer ` to an ``i32`` value that resides in address space #5. | +-------------------------+--------------------------------------------------------------------------------------------------------------+ +| ``ptr`` | An opaque pointer type. | ++-------------------------+--------------------------------------------------------------------------------------------------------------+ +| ``ptr addrspace(5)`` | An opaque pointer type to a value that resides in address space #5. | ++-------------------------+--------------------------------------------------------------------------------------------------------------+ .. _t_vector: diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -168,8 +168,10 @@ TYPE_CODE_TOKEN = 22, // TOKEN - TYPE_CODE_BFLOAT = 23, // BRAIN FLOATING POINT - TYPE_CODE_X86_AMX = 24 // X86 AMX + TYPE_CODE_BFLOAT = 23, // BRAIN FLOATING POINT + TYPE_CODE_X86_AMX = 24, // X86 AMX + + TYPE_CODE_OPAQUE_POINTER = 25, // OPAQUE_POINTER: [addrspace] }; enum OperandBundleTagCode { diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h --- a/llvm/include/llvm/IR/DerivedTypes.h +++ b/llvm/include/llvm/IR/DerivedTypes.h @@ -633,6 +633,7 @@ /// Class to represent pointers. class PointerType : public Type { explicit PointerType(Type *ElType, unsigned AddrSpace); + explicit PointerType(LLVMContext &C, unsigned AddrSpace); Type *PointeeTy; @@ -643,6 +644,9 @@ /// This constructs a pointer to an object of the specified type in a numbered /// address space. static PointerType *get(Type *ElementType, unsigned AddressSpace); + /// This constructs an opaque pointer to an object in a numbered address + /// space. + static PointerType *get(LLVMContext &C, unsigned AddressSpace); /// This constructs a pointer to an object of the specified type in the /// generic address space (address space zero). @@ -650,7 +654,18 @@ return PointerType::get(ElementType, 0); } - Type *getElementType() const { return PointeeTy; } + /// This constructs an opaque pointer to an object in the + /// generic address space (address space zero). + static PointerType *getUnqual(LLVMContext &C) { + return PointerType::get(C, 0); + } + + Type *getElementType() const { + assert(!isOpaque() && "Attempting to get element type of opaque pointer"); + return PointeeTy; + } + + bool isOpaque() const { return !PointeeTy; } /// Return true if the specified type is valid as a element type. static bool isValidElementType(Type *ElemTy); diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -845,6 +845,7 @@ TYPEKEYWORD("x86_mmx", Type::getX86_MMXTy(Context)); TYPEKEYWORD("x86_amx", Type::getX86_AMXTy(Context)); TYPEKEYWORD("token", Type::getTokenTy(Context)); + TYPEKEYWORD("ptr", PointerType::getUnqual(Context)); #undef TYPEKEYWORD diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2595,6 +2595,13 @@ } } + if (Result->isPointerTy() && cast(Result)->isOpaque()) { + unsigned AddrSpace; + if (parseOptionalAddrSpace(AddrSpace)) + return true; + Result = PointerType::get(getContext(), AddrSpace); + } + // parse the type suffixes. while (true) { switch (Lex.getKind()) { diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -1807,6 +1807,16 @@ ResultTy = PointerType::get(ResultTy, AddressSpace); break; } + case bitc::TYPE_CODE_OPAQUE_POINTER: { // OPAQUE_POINTER: [] or + // [addrspace] + if (Record.empty()) + return error("Invalid record"); + unsigned AddressSpace = 0; + if (Record.size() == 1) + AddressSpace = Record[0]; + ResultTy = PointerType::get(Context, AddressSpace); + break; + } case bitc::TYPE_CODE_FUNCTION_OLD: { // Deprecated, but still needed to read old bitcode files. // FUNCTION: [vararg, attrid, retty, paramty x N] diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -858,6 +858,12 @@ Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0 unsigned PtrAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for TYPE_CODE_OPAQUE_POINTER. + Abbv = std::make_shared(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_OPAQUE_POINTER)); + Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0 + unsigned OpaquePtrAbbrev = Stream.EmitAbbrev(std::move(Abbv)); + // Abbrev for TYPE_CODE_FUNCTION. Abbv = std::make_shared(); Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION)); @@ -928,12 +934,21 @@ break; case Type::PointerTyID: { PointerType *PTy = cast(T); - // POINTER: [pointee type, address space] - Code = bitc::TYPE_CODE_POINTER; - TypeVals.push_back(VE.getTypeID(PTy->getElementType())); unsigned AddressSpace = PTy->getAddressSpace(); - TypeVals.push_back(AddressSpace); - if (AddressSpace == 0) AbbrevToUse = PtrAbbrev; + if (PTy->isOpaque()) { + // OPAQUE_POINTER: [address space] + Code = bitc::TYPE_CODE_OPAQUE_POINTER; + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = OpaquePtrAbbrev; + } else { + // POINTER: [pointee type, address space] + Code = bitc::TYPE_CODE_POINTER; + TypeVals.push_back(VE.getTypeID(PTy->getElementType())); + TypeVals.push_back(AddressSpace); + if (AddressSpace == 0) + AbbrevToUse = PtrAbbrev; + } break; } case Type::FunctionTyID: { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -651,6 +651,12 @@ } case Type::PointerTyID: { PointerType *PTy = cast(Ty); + if (PTy->isOpaque()) { + OS << "ptr"; + if (unsigned AddressSpace = PTy->getAddressSpace()) + OS << " addrspace(" << AddressSpace << ')'; + return; + } print(PTy->getElementType(), OS); if (unsigned AddressSpace = PTy->getAddressSpace()) OS << " addrspace(" << AddressSpace << ')'; diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1445,6 +1445,8 @@ DenseMap, ArrayType*> ArrayTypes; DenseMap, VectorType*> VectorTypes; + // TODO: clean up the following after we no longer support non-opaque pointer + // types. DenseMap PointerTypes; // Pointers in AddrSpace = 0 DenseMap, PointerType*> ASPointerTypes; diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -699,6 +699,20 @@ return Entry; } +PointerType *PointerType::get(LLVMContext &C, unsigned AddressSpace) { + LLVMContextImpl *CImpl = C.pImpl; + + // Since AddressSpace #0 is the common case, we special case it. + PointerType *&Entry = + AddressSpace == 0 + ? CImpl->PointerTypes[nullptr] + : CImpl->ASPointerTypes[std::make_pair(nullptr, AddressSpace)]; + + if (!Entry) + Entry = new (CImpl->Alloc) PointerType(C, AddressSpace); + return Entry; +} + PointerType::PointerType(Type *E, unsigned AddrSpace) : Type(E->getContext(), PointerTyID), PointeeTy(E) { ContainedTys = &PointeeTy; @@ -706,6 +720,11 @@ setSubclassData(AddrSpace); } +PointerType::PointerType(LLVMContext &C, unsigned AddrSpace) + : Type(C, PointerTyID), PointeeTy(nullptr) { + setSubclassData(AddrSpace); +} + PointerType *Type::getPointerTo(unsigned addrs) const { return PointerType::get(const_cast(this), addrs); } @@ -713,7 +732,8 @@ bool PointerType::isValidElementType(Type *ElemTy) { return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && !ElemTy->isMetadataTy() && !ElemTy->isTokenTy() && - !ElemTy->isX86_AMXTy(); + !ElemTy->isX86_AMXTy() && + !(ElemTy->isPointerTy() && cast(ElemTy)->isOpaque()); } bool PointerType::isLoadableOrStorableType(Type *ElemTy) { diff --git a/llvm/test/Assembler/opaque-ptr.ll b/llvm/test/Assembler/opaque-ptr.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/opaque-ptr.ll @@ -0,0 +1,25 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +; CHECK: define ptr @f(ptr %a) { +; CHECK: %b = bitcast ptr %a to ptr +; CHECK: ret ptr %b +define ptr @f(ptr %a) { + %b = bitcast ptr %a to ptr + ret ptr %b +} + +; CHECK: define ptr @g(ptr addrspace(2) %a) { +; CHECK: %b = addrspacecast ptr addrspace(2) %a to ptr +; CHECK: ret ptr %b +define ptr @g(ptr addrspace(2) %a) { + %b = addrspacecast ptr addrspace(2) %a to ptr addrspace(0) + ret ptr addrspace(0) %b +} + +; CHECK: define ptr addrspace(2) @g2(ptr %a) { +; CHECK: %b = addrspacecast ptr %a to ptr addrspace(2) +; CHECK: ret ptr addrspace(2) %b +define ptr addrspace(2) @g2(ptr addrspace(0) %a) { + %b = addrspacecast ptr addrspace(0) %a to ptr addrspace(2) + ret ptr addrspace(2) %b +}