Skip to content

Commit

Permalink
[IR] Introduce the opaque pointer type
Browse files Browse the repository at this point in the history
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
  • Loading branch information
aeubanks committed May 13, 2021
1 parent 83ff0ff commit 2155dc5
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 11 deletions.
12 changes: 11 additions & 1 deletion llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3307,11 +3307,17 @@ are target-specific.
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
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:

::

<type> *
ptr

:Examples:

Expand All @@ -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 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:
Expand Down
3 changes: 3 additions & 0 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Changes to the LLVM IR
* The ``inalloca`` attribute now has a mandatory type field, similar
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
------------------------

Expand Down
6 changes: 4 additions & 2 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,10 @@ enum TypeCodes {

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 {
Expand Down
19 changes: 17 additions & 2 deletions llvm/include/llvm/IR/DerivedTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ inline ElementCount VectorType::getElementCount() const {
/// Class to represent pointers.
class PointerType : public Type {
explicit PointerType(Type *ElType, unsigned AddrSpace);
explicit PointerType(LLVMContext &C, unsigned AddrSpace);

Type *PointeeTy;

Expand All @@ -643,14 +644,28 @@ class PointerType : public Type {
/// 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).
/// default address space (address space zero).
static PointerType *getUnqual(Type *ElementType) {
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.
static bool isValidElementType(Type *ElemTy);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ lltok::Kind LLLexer::LexIdentifier() {
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

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
while (true) {
switch (Lex.getKind()) {
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1807,6 +1807,13 @@ Error BitcodeReader::parseTypeTableBody() {
ResultTy = PointerType::get(ResultTy, AddressSpace);
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: {
// Deprecated, but still needed to read old bitcode files.
// FUNCTION: [vararg, attrid, retty, paramty x N]
Expand Down
25 changes: 20 additions & 5 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,12 @@ void ModuleBitcodeWriter::writeTypeTable() {
Abbv->Add(BitCodeAbbrevOp(0)); // Addrspace = 0
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.
Abbv = std::make_shared<BitCodeAbbrev>();
Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_FUNCTION));
Expand Down Expand Up @@ -928,12 +934,21 @@ void ModuleBitcodeWriter::writeTypeTable() {
break;
case Type::PointerTyID: {
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();
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: {
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,12 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
}
case Type::PointerTyID: {
PointerType *PTy = cast<PointerType>(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 << ')';
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/IR/LLVMContextImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1445,6 +1445,8 @@ class LLVMContextImpl {

DenseMap<std::pair<Type *, uint64_t>, ArrayType*> ArrayTypes;
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<std::pair<Type*, unsigned>, PointerType*> ASPointerTypes;

Expand Down
22 changes: 21 additions & 1 deletion llvm/lib/IR/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,21 +699,41 @@ PointerType *PointerType::get(Type *EltTy, unsigned AddressSpace) {
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;
NumContainedTys = 1;
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<Type*>(this), addrs);
}

bool PointerType::isValidElementType(Type *ElemTy) {
return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() &&
!ElemTy->isMetadataTy() && !ElemTy->isTokenTy() &&
!ElemTy->isX86_AMXTy();
!ElemTy->isX86_AMXTy() &&
!(ElemTy->isPointerTy() && cast<PointerType>(ElemTy)->isOpaque());
}

bool PointerType::isLoadableOrStorableType(Type *ElemTy) {
Expand Down
7 changes: 7 additions & 0 deletions llvm/test/Assembler/invalid-opaque-ptr.ll
Original file line number Diff line number Diff line change
@@ -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
}
26 changes: 26 additions & 0 deletions llvm/test/Assembler/opaque-ptr.ll
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 2155dc5

Please sign in to comment.