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
+