diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2750,12 +2750,15 @@ ``A
`` Specifies the address space of objects created by '``alloca``'. Defaults to the default address space of 0. -``p[n]::[:][:]`` +``p[n]::[:][:][:]`` This specifies the *size* of a pointer and its ```` and ````\erred alignments for address space ``n``. ```` is optional and defaults to ````. The fourth parameter ```` is the size of the - index that used for address calculation. If not - specified, the default index size is equal to the pointer size. All sizes + index that used for address calculation. If not specified, the default index + size is equal to the pointer size. For targets that include additional + non-integral bits in the pointer representation (e.g. fat pointer metadata), + ```` specifies the number of integral bits, i.e. the address space + range. If not specified, ```` defaults to ````. All sizes are in bits. The address space, ``n``, is optional, and if not specified, denotes the default address space 0. The value of ``n`` must be in the range [1,2^23). diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h --- a/llvm/include/llvm/IR/DataLayout.h +++ b/llvm/include/llvm/IR/DataLayout.h @@ -95,11 +95,13 @@ uint32_t TypeBitWidth; uint32_t AddressSpace; uint32_t IndexBitWidth; + uint32_t IntegralBitWidth; /// Initializer static PointerAlignElem getInBits(uint32_t AddressSpace, Align ABIAlign, Align PrefAlign, uint32_t TypeBitWidth, - uint32_t IndexBitWidth); + uint32_t IndexBitWidth, + uint32_t IntegralBitWidth); bool operator==(const PointerAlignElem &rhs) const; }; @@ -182,7 +184,8 @@ /// Returns an error description on failure. Error setPointerAlignmentInBits(uint32_t AddrSpace, Align ABIAlign, Align PrefAlign, uint32_t TypeBitWidth, - uint32_t IndexBitWidth); + uint32_t IndexBitWidth, + uint32_t IntegralBitWidth); /// Internal helper to get alignment for integer of given bitwidth. Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const; @@ -373,12 +376,26 @@ /// the backends/clients are updated. Align getPointerPrefAlignment(unsigned AS = 0) const; - /// Layout pointer size in bytes, rounded up to a whole - /// number of bytes. + /// Layout pointer size in bytes, rounded up to a whole number of bytes. The + /// difference between this function and getPointerIntegralSize() is this one + /// returns the size of the entire pointer type (this includes metadata bits + /// for fat pointers) and the latter only returns the number of address bits. + /// \sa DataLayout::getPointerIntegralSize /// FIXME: The defaults need to be removed once all of /// the backends/clients are updated. unsigned getPointerSize(unsigned AS = 0) const; + /// Returns the integral size of a pointer in a given address space in bytes. + /// For targets that store bits in pointers that are not part of the address, + /// this returns the number of bits that can be manipulated using operations + /// that change the address (e.g. addition/subtraction). + /// For example, a 64-bit CHERI-enabled target has 128-bit pointers of which + /// only 64 are used to represent the address and the remaining ones are used + /// for metadata such as bounds and access permissions. In this case + /// getPointerSize() returns 16, but getPointerIntegralSize() returns 8. + /// \sa DataLayout::getPointerSize + unsigned getPointerIntegralSize(unsigned AS) const; + /// Returns the maximum index size over all address spaces. unsigned getMaxIndexSize() const; @@ -413,6 +430,10 @@ return getPointerAlignElem(AS).TypeBitWidth; } + unsigned getPointerIntegralSizeInBits(unsigned AS) const { + return getPointerAlignElem(AS).IntegralBitWidth; + } + /// Returns the maximum index size over all address spaces. unsigned getMaxIndexSizeInBits() const { return getMaxIndexSize() * 8; diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -128,7 +128,8 @@ PointerAlignElem PointerAlignElem::getInBits(uint32_t AddressSpace, Align ABIAlign, Align PrefAlign, uint32_t TypeBitWidth, - uint32_t IndexBitWidth) { + uint32_t IndexBitWidth, + uint32_t IntegralBitWidth) { assert(ABIAlign <= PrefAlign && "Preferred alignment worse than ABI!"); PointerAlignElem retval; retval.AddressSpace = AddressSpace; @@ -136,6 +137,7 @@ retval.PrefAlign = PrefAlign; retval.TypeBitWidth = TypeBitWidth; retval.IndexBitWidth = IndexBitWidth; + retval.IntegralBitWidth = IntegralBitWidth; return retval; } @@ -197,7 +199,7 @@ E.PrefAlign, E.TypeBitWidth)) return report_fatal_error(std::move(Err)); } - if (Error Err = setPointerAlignmentInBits(0, Align(8), Align(8), 64, 64)) + if (Error Err = setPointerAlignmentInBits(0, Align(8), Align(8), 64, 64, 64)) return report_fatal_error(std::move(Err)); if (Error Err = parseSpecifier(Desc)) @@ -338,6 +340,7 @@ // Size of index used in GEP for address calculation. // The parameter is optional. By default it is equal to size of pointer. unsigned IndexSize = PointerMemSize; + unsigned IntegralBits = IndexSize; // Preferred alignment. unsigned PointerPrefAlign = PointerABIAlign; @@ -359,13 +362,27 @@ if (!IndexSize) return reportError("Invalid index size of 0 bytes"); } + // Now read the integral range. It is the third optional parameter here. + IntegralBits = IndexSize; + if (!Rest.empty()) { + if (Error Err = ::split(Rest, ':', Split)) + return Err; + if (Error Err = getInt(Tok, IntegralBits)) + return Err; + if (!IntegralBits) + return reportError("Invalid integral size of 0 bytes"); + if (IntegralBits > PointerMemSize) + return reportError("Pointer integral size cannot be larger than " + "total pointer size"); + } + } + if (Error Err = setPointerAlignmentInBits( + AddrSpace, assumeAligned(PointerABIAlign), + assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize, + IntegralBits)) + return Err; + break; } - if (Error Err = setPointerAlignmentInBits( - AddrSpace, assumeAligned(PointerABIAlign), - assumeAligned(PointerPrefAlign), PointerMemSize, IndexSize)) - return Err; - break; - } case 'i': case 'v': case 'f': @@ -606,7 +623,8 @@ Error DataLayout::setPointerAlignmentInBits(uint32_t AddrSpace, Align ABIAlign, Align PrefAlign, uint32_t TypeBitWidth, - uint32_t IndexBitWidth) { + uint32_t IndexBitWidth, + uint32_t IntegralBitWidth) { if (PrefAlign < ABIAlign) return reportError( "Preferred alignment cannot be less than the ABI alignment"); @@ -616,9 +634,9 @@ return A.AddressSpace < AddressSpace; }); if (I == Pointers.end() || I->AddressSpace != AddrSpace) { - Pointers.insert(I, - PointerAlignElem::getInBits(AddrSpace, ABIAlign, PrefAlign, - TypeBitWidth, IndexBitWidth)); + Pointers.insert(I, PointerAlignElem::getInBits( + AddrSpace, ABIAlign, PrefAlign, TypeBitWidth, + IndexBitWidth, IntegralBitWidth)); } else { I->ABIAlign = ABIAlign; I->PrefAlign = PrefAlign; @@ -709,6 +727,10 @@ return divideCeil(getPointerAlignElem(AS).TypeBitWidth, 8); } +unsigned DataLayout::getPointerIntegralSize(unsigned AS) const { + return divideCeil(getPointerAlignElem(AS).IntegralBitWidth, 8); +} + unsigned DataLayout::getMaxIndexSize() const { unsigned MaxIndexSize = 0; for (auto &P : Pointers) diff --git a/llvm/test/Assembler/invalid-datalayout25.ll b/llvm/test/Assembler/invalid-datalayout25.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/invalid-datalayout25.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +target datalayout = "p0:32:32:32:32:64" + +; CHECK: error: Pointer integral size cannot be larger than total pointer size + diff --git a/llvm/test/Assembler/invalid-datalayout26.ll b/llvm/test/Assembler/invalid-datalayout26.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Assembler/invalid-datalayout26.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +target datalayout = "p0:32:32:32:32:0" + +; CHECK: error: Invalid integral size of 0 bytes +