forked from OSchip/llvm-project
[IR] Introduce the opaque pointer type
The opaque pointer type is essentially just a normal pointer type with a null pointee type. This also adds support for the opaque pointer type to the bitcode reader/writer, as well as to textual IR. To avoid confusion with existing pointer types, we disallow creating a pointer to an opaque pointer. Opaque pointer types should not be widely used at this point since many parts of LLVM still do not support them. The next steps are to add some very simple use cases of opaque pointers to make sure they work, then start pretending that all pointers are opaque pointers and see what breaks. https://lists.llvm.org/pipermail/llvm-dev/2021-May/150359.html Reviewed By: dblaikie, dexonsmith, pcc Differential Revision: https://reviews.llvm.org/D101704
This commit is contained in:
parent
83ff0ff463
commit
2155dc51d7
|
@ -3307,11 +3307,17 @@ are target-specific.
|
||||||
Note that LLVM does not permit pointers to void (``void*``) nor does it
|
Note that LLVM does not permit pointers to void (``void*``) nor does it
|
||||||
permit pointers to labels (``label*``). Use ``i8*`` instead.
|
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
|
||||||
|
specify the type of the underlying memory they are interacting with. Opaque
|
||||||
|
pointers are still in the process of being worked on and are not complete.
|
||||||
|
|
||||||
:Syntax:
|
:Syntax:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
<type> *
|
<type> *
|
||||||
|
ptr
|
||||||
|
|
||||||
:Examples:
|
:Examples:
|
||||||
|
|
||||||
|
@ -3320,7 +3326,11 @@ permit pointers to labels (``label*``). Use ``i8*`` instead.
|
||||||
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
| ``i32 (i32*) *`` | A :ref:`pointer <t_pointer>` to a :ref:`function <t_function>` that takes an ``i32*``, returning an ``i32``. |
|
| ``i32 (i32*) *`` | A :ref:`pointer <t_pointer>` to a :ref:`function <t_function>` that takes an ``i32*``, returning an ``i32``. |
|
||||||
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
| ``i32 addrspace(5)*`` | A :ref:`pointer <t_pointer>` to an ``i32`` value that resides in address space #5. |
|
| ``i32 addrspace(5)*`` | A :ref:`pointer <t_pointer>` to an ``i32`` value that resides in address space 5. |
|
||||||
|
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
|
| ``ptr`` | An opaque pointer type to a value that resides in address space 0. |
|
||||||
|
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
|
| ``ptr addrspace(5)`` | An opaque pointer type to a value that resides in address space 5. |
|
||||||
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
+-------------------------+--------------------------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
.. _t_vector:
|
.. _t_vector:
|
||||||
|
|
|
@ -61,6 +61,9 @@ Changes to the LLVM IR
|
||||||
* The ``inalloca`` attribute now has a mandatory type field, similar
|
* The ``inalloca`` attribute now has a mandatory type field, similar
|
||||||
to ``byval`` and ``sret``.
|
to ``byval`` and ``sret``.
|
||||||
|
|
||||||
|
* The opaque pointer type ``ptr`` has been introduced. It is still in the
|
||||||
|
process of being worked on and should not be used yet.
|
||||||
|
|
||||||
Changes to building LLVM
|
Changes to building LLVM
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
|
@ -168,8 +168,10 @@ enum TypeCodes {
|
||||||
|
|
||||||
TYPE_CODE_TOKEN = 22, // TOKEN
|
TYPE_CODE_TOKEN = 22, // TOKEN
|
||||||
|
|
||||||
TYPE_CODE_BFLOAT = 23, // BRAIN FLOATING POINT
|
TYPE_CODE_BFLOAT = 23, // BRAIN FLOATING POINT
|
||||||
TYPE_CODE_X86_AMX = 24 // X86 AMX
|
TYPE_CODE_X86_AMX = 24, // X86 AMX
|
||||||
|
|
||||||
|
TYPE_CODE_OPAQUE_POINTER = 25, // OPAQUE_POINTER: [addrspace]
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OperandBundleTagCode {
|
enum OperandBundleTagCode {
|
||||||
|
|
|
@ -633,6 +633,7 @@ inline ElementCount VectorType::getElementCount() const {
|
||||||
/// Class to represent pointers.
|
/// Class to represent pointers.
|
||||||
class PointerType : public Type {
|
class PointerType : public Type {
|
||||||
explicit PointerType(Type *ElType, unsigned AddrSpace);
|
explicit PointerType(Type *ElType, unsigned AddrSpace);
|
||||||
|
explicit PointerType(LLVMContext &C, unsigned AddrSpace);
|
||||||
|
|
||||||
Type *PointeeTy;
|
Type *PointeeTy;
|
||||||
|
|
||||||
|
@ -643,14 +644,28 @@ public:
|
||||||
/// This constructs a pointer to an object of the specified type in a numbered
|
/// This constructs a pointer to an object of the specified type in a numbered
|
||||||
/// address space.
|
/// address space.
|
||||||
static PointerType *get(Type *ElementType, unsigned AddressSpace);
|
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
|
/// This constructs a pointer to an object of the specified type in the
|
||||||
/// generic address space (address space zero).
|
/// default address space (address space zero).
|
||||||
static PointerType *getUnqual(Type *ElementType) {
|
static PointerType *getUnqual(Type *ElementType) {
|
||||||
return PointerType::get(ElementType, 0);
|
return PointerType::get(ElementType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *getElementType() const { return PointeeTy; }
|
/// This constructs an opaque pointer to an object in the
|
||||||
|
/// default 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.
|
/// Return true if the specified type is valid as a element type.
|
||||||
static bool isValidElementType(Type *ElemTy);
|
static bool isValidElementType(Type *ElemTy);
|
||||||
|
|
|
@ -845,6 +845,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
||||||
TYPEKEYWORD("x86_mmx", Type::getX86_MMXTy(Context));
|
TYPEKEYWORD("x86_mmx", Type::getX86_MMXTy(Context));
|
||||||
TYPEKEYWORD("x86_amx", Type::getX86_AMXTy(Context));
|
TYPEKEYWORD("x86_amx", Type::getX86_AMXTy(Context));
|
||||||
TYPEKEYWORD("token", Type::getTokenTy(Context));
|
TYPEKEYWORD("token", Type::getTokenTy(Context));
|
||||||
|
TYPEKEYWORD("ptr", PointerType::getUnqual(Context));
|
||||||
|
|
||||||
#undef TYPEKEYWORD
|
#undef TYPEKEYWORD
|
||||||
|
|
||||||
|
|
|
@ -2595,6 +2595,13 @@ bool LLParser::parseType(Type *&Result, const Twine &Msg, bool AllowVoid) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Result->isPointerTy() && cast<PointerType>(Result)->isOpaque()) {
|
||||||
|
unsigned AddrSpace;
|
||||||
|
if (parseOptionalAddrSpace(AddrSpace))
|
||||||
|
return true;
|
||||||
|
Result = PointerType::get(getContext(), AddrSpace);
|
||||||
|
}
|
||||||
|
|
||||||
// parse the type suffixes.
|
// parse the type suffixes.
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (Lex.getKind()) {
|
switch (Lex.getKind()) {
|
||||||
|
|
|
@ -1807,6 +1807,13 @@ Error BitcodeReader::parseTypeTableBody() {
|
||||||
ResultTy = PointerType::get(ResultTy, AddressSpace);
|
ResultTy = PointerType::get(ResultTy, AddressSpace);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case bitc::TYPE_CODE_OPAQUE_POINTER: { // OPAQUE_POINTER: [addrspace]
|
||||||
|
if (Record.size() != 1)
|
||||||
|
return error("Invalid record");
|
||||||
|
unsigned AddressSpace = Record[0];
|
||||||
|
ResultTy = PointerType::get(Context, AddressSpace);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case bitc::TYPE_CODE_FUNCTION_OLD: {
|
case bitc::TYPE_CODE_FUNCTION_OLD: {
|
||||||
// Deprecated, but still needed to read old bitcode files.
|
// Deprecated, but still needed to read old bitcode files.
|
||||||
// FUNCTION: [vararg, attrid, retty, paramty x N]
|
// FUNCTION: [vararg, attrid, retty, paramty x N]
|
||||||
|
|
|
@ -858,6 +858,12 @@ void ModuleBitcodeWriter::writeTypeTable() {
|
||||||
Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0
|
Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0
|
||||||
unsigned PtrAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
unsigned PtrAbbrev = Stream.EmitAbbrev(std::move(Abbv));
|
||||||
|
|
||||||
|
// Abbrev for TYPE_CODE_OPAQUE_POINTER.
|
||||||
|
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||||
|
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.
|
// Abbrev for TYPE_CODE_FUNCTION.
|
||||||
Abbv = std::make_shared<BitCodeAbbrev>();
|
Abbv = std::make_shared<BitCodeAbbrev>();
|
||||||
Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION));
|
Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION));
|
||||||
|
@ -928,12 +934,21 @@ void ModuleBitcodeWriter::writeTypeTable() {
|
||||||
break;
|
break;
|
||||||
case Type::PointerTyID: {
|
case Type::PointerTyID: {
|
||||||
PointerType *PTy = cast<PointerType>(T);
|
PointerType *PTy = cast<PointerType>(T);
|
||||||
// POINTER: [pointee type, address space]
|
|
||||||
Code = bitc::TYPE_CODE_POINTER;
|
|
||||||
TypeVals.push_back(VE.getTypeID(PTy->getElementType()));
|
|
||||||
unsigned AddressSpace = PTy->getAddressSpace();
|
unsigned AddressSpace = PTy->getAddressSpace();
|
||||||
TypeVals.push_back(AddressSpace);
|
if (PTy->isOpaque()) {
|
||||||
if (AddressSpace == 0) AbbrevToUse = PtrAbbrev;
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
case Type::FunctionTyID: {
|
case Type::FunctionTyID: {
|
||||||
|
|
|
@ -651,6 +651,12 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
|
||||||
}
|
}
|
||||||
case Type::PointerTyID: {
|
case Type::PointerTyID: {
|
||||||
PointerType *PTy = cast<PointerType>(Ty);
|
PointerType *PTy = cast<PointerType>(Ty);
|
||||||
|
if (PTy->isOpaque()) {
|
||||||
|
OS << "ptr";
|
||||||
|
if (unsigned AddressSpace = PTy->getAddressSpace())
|
||||||
|
OS << " addrspace(" << AddressSpace << ')';
|
||||||
|
return;
|
||||||
|
}
|
||||||
print(PTy->getElementType(), OS);
|
print(PTy->getElementType(), OS);
|
||||||
if (unsigned AddressSpace = PTy->getAddressSpace())
|
if (unsigned AddressSpace = PTy->getAddressSpace())
|
||||||
OS << " addrspace(" << AddressSpace << ')';
|
OS << " addrspace(" << AddressSpace << ')';
|
||||||
|
|
|
@ -1445,6 +1445,8 @@ public:
|
||||||
|
|
||||||
DenseMap<std::pair<Type *, uint64_t>, ArrayType*> ArrayTypes;
|
DenseMap<std::pair<Type *, uint64_t>, ArrayType*> ArrayTypes;
|
||||||
DenseMap<std::pair<Type *, ElementCount>, VectorType*> VectorTypes;
|
DenseMap<std::pair<Type *, ElementCount>, VectorType*> VectorTypes;
|
||||||
|
// TODO: clean up the following after we no longer support non-opaque pointer
|
||||||
|
// types.
|
||||||
DenseMap<Type*, PointerType*> PointerTypes; // Pointers in AddrSpace = 0
|
DenseMap<Type*, PointerType*> PointerTypes; // Pointers in AddrSpace = 0
|
||||||
DenseMap<std::pair<Type*, unsigned>, PointerType*> ASPointerTypes;
|
DenseMap<std::pair<Type*, unsigned>, PointerType*> ASPointerTypes;
|
||||||
|
|
||||||
|
|
|
@ -699,6 +699,20 @@ PointerType *PointerType::get(Type *EltTy, unsigned AddressSpace) {
|
||||||
return Entry;
|
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)
|
PointerType::PointerType(Type *E, unsigned AddrSpace)
|
||||||
: Type(E->getContext(), PointerTyID), PointeeTy(E) {
|
: Type(E->getContext(), PointerTyID), PointeeTy(E) {
|
||||||
ContainedTys = &PointeeTy;
|
ContainedTys = &PointeeTy;
|
||||||
|
@ -706,6 +720,11 @@ PointerType::PointerType(Type *E, unsigned AddrSpace)
|
||||||
setSubclassData(AddrSpace);
|
setSubclassData(AddrSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PointerType::PointerType(LLVMContext &C, unsigned AddrSpace)
|
||||||
|
: Type(C, PointerTyID), PointeeTy(nullptr) {
|
||||||
|
setSubclassData(AddrSpace);
|
||||||
|
}
|
||||||
|
|
||||||
PointerType *Type::getPointerTo(unsigned addrs) const {
|
PointerType *Type::getPointerTo(unsigned addrs) const {
|
||||||
return PointerType::get(const_cast<Type*>(this), addrs);
|
return PointerType::get(const_cast<Type*>(this), addrs);
|
||||||
}
|
}
|
||||||
|
@ -713,7 +732,8 @@ PointerType *Type::getPointerTo(unsigned addrs) const {
|
||||||
bool PointerType::isValidElementType(Type *ElemTy) {
|
bool PointerType::isValidElementType(Type *ElemTy) {
|
||||||
return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() &&
|
return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() &&
|
||||||
!ElemTy->isMetadataTy() && !ElemTy->isTokenTy() &&
|
!ElemTy->isMetadataTy() && !ElemTy->isTokenTy() &&
|
||||||
!ElemTy->isX86_AMXTy();
|
!ElemTy->isX86_AMXTy() &&
|
||||||
|
!(ElemTy->isPointerTy() && cast<PointerType>(ElemTy)->isOpaque());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PointerType::isLoadableOrStorableType(Type *ElemTy) {
|
bool PointerType::isLoadableOrStorableType(Type *ElemTy) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: pointer to this type is invalid
|
||||||
|
define void @f(ptr %a) {
|
||||||
|
%b = bitcast ptr %a to ptr*
|
||||||
|
ret void
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
|
||||||
|
; RUN: verify-uselistorder %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
|
||||||
|
}
|
Loading…
Reference in New Issue