diff --git a/docs/LangRef.rst b/docs/LangRef.rst index d4d0ee325c9..7f69d693294 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -546,6 +546,26 @@ An example of an identified structure specification is: Prior to the LLVM 3.0 release, identified types were structurally uniqued. Only literal types are uniqued in recent versions of LLVM. +.. _nointptrtype: + +Non-Integral Pointer Type +------------------------- + +Note: non-integral pointer types are a work in progress, and they should be +considered experimental at this time. + +LLVM IR optionally allows the frontend to denote pointers in certain address +spaces as "non-integral" via the :ref:```datalayout`` +string`. Non-integral pointer types represent pointers that +have an *unspecified* bitwise representation; that is, the integral +representation may be target dependent or unstable (not backed by a fixed +integer). + +``inttoptr`` instructions converting integers to non-integral pointer types are +ill-typed, and so are ``ptrtoint`` instructions converting values of +non-integral pointer types to integers. Vector versions of said instructions +are ill-typed as well. + .. _globalvars: Global Variables @@ -1831,6 +1851,10 @@ as follows: ``n32:64`` for PowerPC 64, or ``n8:16:32:64`` for X86-64. Elements of this set are considered to support most general arithmetic operations efficiently. +``ni:
:
:
...`` + This specifies pointer types with the specified address spaces + as :ref:`Non-Integral Pointer Type ` s. The ``0`` + address space cannot be specified as non-integral. On every specification that takes a ``:``, specifying the ```` alignment is optional. If omitted, the preceding ``:`` diff --git a/include/llvm/IR/DataLayout.h b/include/llvm/IR/DataLayout.h index 173121b72ff..2b481fb6607 100644 --- a/include/llvm/IR/DataLayout.h +++ b/include/llvm/IR/DataLayout.h @@ -21,6 +21,7 @@ #define LLVM_IR_DATALAYOUT_H #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" #include "llvm/Pass.h" @@ -144,6 +145,10 @@ private: // The StructType -> StructLayout map. mutable void *LayoutMap; + /// Pointers in these address spaces are non-integral, and don't have a + /// well-defined bitwise representation. + SmallVector NonIntegralAddressSpaces; + void setAlignment(AlignTypeEnum align_type, unsigned abi_align, unsigned pref_align, uint32_t bit_width); unsigned getAlignmentInfo(AlignTypeEnum align_type, uint32_t bit_width, @@ -199,6 +204,7 @@ public: LegalIntWidths = DL.LegalIntWidths; Alignments = DL.Alignments; Pointers = DL.Pointers; + NonIntegralAddressSpaces = DL.NonIntegralAddressSpaces; return *this; } @@ -320,6 +326,18 @@ public: /// the backends/clients are updated. unsigned getPointerSize(unsigned AS = 0) const; + /// Return the address spaces containing non-integral pointers. Pointers in + /// this address space don't have a well-defined bitwise representation. + ArrayRef getNonIntegralAddressSpaces() const { + return NonIntegralAddressSpaces; + } + + bool isNonIntegralPointerType(PointerType *PT) const { + ArrayRef NonIntegralSpaces = getNonIntegralAddressSpaces(); + return find(NonIntegralSpaces, PT->getAddressSpace()) != + NonIntegralSpaces.end(); + } + /// Layout pointer size, in bits /// FIXME: The defaults need to be removed once all of /// the backends/clients are updated. diff --git a/lib/IR/DataLayout.cpp b/lib/IR/DataLayout.cpp index 20a15fb8831..d7ed73015ee 100644 --- a/lib/IR/DataLayout.cpp +++ b/lib/IR/DataLayout.cpp @@ -182,6 +182,7 @@ void DataLayout::reset(StringRef Desc) { BigEndian = false; StackNaturalAlign = 0; ManglingMode = MM_None; + NonIntegralAddressSpaces.clear(); // Default alignments for (const LayoutAlignElem &E : DefaultAlignments) { @@ -234,6 +235,19 @@ void DataLayout::parseSpecifier(StringRef Desc) { StringRef &Tok = Split.first; // Current token. StringRef &Rest = Split.second; // The rest of the string. + if (Tok == "ni") { + do { + Split = split(Rest, ':'); + Rest = Split.second; + unsigned AS = getInt(Split.first); + if (AS == 0) + report_fatal_error("Address space 0 can never be non-integral"); + NonIntegralAddressSpaces.push_back(AS); + } while (!Rest.empty()); + + continue; + } + char Specifier = Tok.front(); Tok = Tok.substr(1); diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 659a22428e2..7815207fd9f 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -2409,6 +2409,11 @@ void Verifier::visitPtrToIntInst(PtrToIntInst &I) { Assert(SrcTy->getScalarType()->isPointerTy(), "PtrToInt source must be pointer", &I); + + if (auto *PTy = dyn_cast(SrcTy->getScalarType())) + Assert(!M->getDataLayout().isNonIntegralPointerType(PTy), + "ptrtoint not supported for non-integral pointers"); + Assert(DestTy->getScalarType()->isIntegerTy(), "PtrToInt result must be integral", &I); Assert(SrcTy->isVectorTy() == DestTy->isVectorTy(), "PtrToInt type mismatch", @@ -2433,6 +2438,11 @@ void Verifier::visitIntToPtrInst(IntToPtrInst &I) { "IntToPtr source must be an integral", &I); Assert(DestTy->getScalarType()->isPointerTy(), "IntToPtr result must be a pointer", &I); + + if (auto *PTy = dyn_cast(DestTy->getScalarType())) + Assert(!M->getDataLayout().isNonIntegralPointerType(PTy), + "inttoptr not supported for non-integral pointers"); + Assert(SrcTy->isVectorTy() == DestTy->isVectorTy(), "IntToPtr type mismatch", &I); if (SrcTy->isVectorTy()) { diff --git a/test/Verifier/non-integral-pointers.ll b/test/Verifier/non-integral-pointers.ll new file mode 100644 index 00000000000..221dd350522 --- /dev/null +++ b/test/Verifier/non-integral-pointers.ll @@ -0,0 +1,45 @@ +; RUN: not opt -verify < %s 2>&1 | FileCheck %s + +target datalayout = "e-ni:4:6" + +define i64 @f_0(i8 addrspace(4)* %ptr) { +; CHECK: ptrtoint not supported for non-integral pointers + %val = ptrtoint i8 addrspace(4)* %ptr to i64 + ret i64 %val +} + +define <4 x i64> @f_1(<4 x i8 addrspace(4)*> %ptr) { +; CHECK: ptrtoint not supported for non-integral pointers + %val = ptrtoint <4 x i8 addrspace(4)*> %ptr to <4 x i64> + ret <4 x i64> %val +} + +define i64 @f_2(i8 addrspace(3)* %ptr) { +; Negative test + %val = ptrtoint i8 addrspace(3)* %ptr to i64 + ret i64 %val +} + +define i8 addrspace(4)* @f_3(i64 %integer) { +; CHECK: inttoptr not supported for non-integral pointers + %val = inttoptr i64 %integer to i8 addrspace(4)* + ret i8 addrspace(4)* %val +} + +define <4 x i8 addrspace(4)*> @f_4(<4 x i64> %integer) { +; CHECK: inttoptr not supported for non-integral pointers + %val = inttoptr <4 x i64> %integer to <4 x i8 addrspace(4)*> + ret <4 x i8 addrspace(4)*> %val +} + +define i8 addrspace(3)* @f_5(i64 %integer) { +; Negative test + %val = inttoptr i64 %integer to i8 addrspace(3)* + ret i8 addrspace(3)* %val +} + +define i64 @f_6(i8 addrspace(6)* %ptr) { +; CHECK: ptrtoint not supported for non-integral pointers + %val = ptrtoint i8 addrspace(6)* %ptr to i64 + ret i64 %val +}