Skip to content

[WIP] Extend data layout to add sentinel pointer value for address space. #83109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3061,6 +3061,15 @@ 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.
``z[n]:<value>``
This specifies the sentinel pointer value for an address space. Sentinel
pointer value is the default non zero null value for a given address
space. ``n`` denotes the address space number, and if not specified, it
is considered to be for the unlisted address space. For unlisted address
space, the sentinel pointer value is ``0``. ``value`` denotes the sentinel
pointer value for an address space ``n``. To represent negatives values,
prefix ``neg`` is added to ``value``. for e.g., ``z0:neg1`` represents for
``0`` address space ``-1`` is the sentinel pointer value.
``ni:<address space0>:<address space1>:<address space2>...``
This specifies pointer types with the specified address spaces
as :ref:`Non-Integral Pointer Type <nointptrtype>` s. The ``0``
Expand Down Expand Up @@ -3093,6 +3102,7 @@ specifications are given in this list:
- ``v64:64:64`` - 64-bit vector is 64-bit aligned
- ``v128:128:128`` - 128-bit vector is 128-bit aligned
- ``a:0:64`` - aggregates are 64-bit aligned
- ``z:0`` - default null value of 0 for unlisted(INT_MAX) address space
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the "unlisted" AS be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlisted here means, for address spaces which are not specified in the data layout string.


When LLVM is determining the alignment for a given type, it uses the
following rules:
Expand Down
19 changes: 19 additions & 0 deletions llvm/include/llvm/IR/DataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -164,6 +165,9 @@ class DataLayout {
/// well-defined bitwise representation.
SmallVector<unsigned, 8> NonIntegralAddressSpaces;

DenseMap<unsigned, int64_t> AddrSpaceToSentinelValueMap;
bool sentinelValueDefined = false;

/// Attempts to set the alignment of the given type. Returns an error
/// description on failure.
Error setAlignment(AlignTypeEnum AlignType, Align ABIAlign, Align PrefAlign,
Expand Down Expand Up @@ -219,6 +223,8 @@ class DataLayout {
StructAlignment = DL.StructAlignment;
Pointers = DL.Pointers;
NonIntegralAddressSpaces = DL.NonIntegralAddressSpaces;
AddrSpaceToSentinelValueMap = DL.AddrSpaceToSentinelValueMap;
sentinelValueDefined = DL.isSentinelValueDefined();
return *this;
}

Expand Down Expand Up @@ -299,6 +305,19 @@ class DataLayout {
return ManglingMode == MM_WinCOFFX86;
}

int64_t getSentinelPointerValue(unsigned AddrSpace) const {
auto It = AddrSpaceToSentinelValueMap.find(AddrSpace);
if (It == AddrSpaceToSentinelValueMap.end())
return 0;
return It->second;
}

void setSentinelPointerValue(unsigned AddrSpace, int64_t Value) {
AddrSpaceToSentinelValueMap[AddrSpace] = Value;
}

bool isSentinelValueDefined() const { return sentinelValueDefined; }

/// Returns true if symbols with leading question marks should not receive IR
/// mangling. True for Windows mangling modes.
bool doNotMangleLeadingQuestionMark() const {
Expand Down
46 changes: 46 additions & 0 deletions llvm/lib/IR/DataLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ void DataLayout::reset(StringRef Desc) {
if (Error Err = setPointerAlignmentInBits(0, Align(8), Align(8), 64, 64))
return report_fatal_error(std::move(Err));

setSentinelPointerValue(INT_MAX, 0);

if (Error Err = parseSpecifier(Desc))
return report_fatal_error(std::move(Err));
}
Expand Down Expand Up @@ -251,6 +253,22 @@ template <typename IntTy> static Error getInt(StringRef R, IntTy &Result) {
return Error::success();
}

template <typename IntTy>
static Error getIntForAddrSpace(StringRef R, IntTy &Result) {
if (R.starts_with("neg")) {
StringRef AfterNeg = R.slice(3, R.size());
bool error = AfterNeg.getAsInteger(10, Result);
(void)error;
if (error || Result <= 0)
return reportError("not a number, or does not fit in an unsigned int");
Result *= -1;
} else if (R.contains("neg"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no else after return

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the return.

return reportError("not a valid value for address space");
else
return getInt<IntTy>(R, Result);
return Error::success();
}

/// Get an unsigned integer representing the number of bits and convert it into
/// bytes. Error out of not a byte width multiple.
template <typename IntTy>
Expand Down Expand Up @@ -502,6 +520,33 @@ Error DataLayout::parseSpecifier(StringRef Desc) {
return Err;
break;
}
case 'z': {
sentinelValueDefined = true;
unsigned AddrSpace = 0;
int64_t Value;
// for unlisted address spaces e.g., z:0
if (Tok.empty()) {
if (Error Err = getIntForAddrSpace(Rest, Value))
return Err;
setSentinelPointerValue(INT_MAX, Value);
break;
} else {
if (Error Err = getInt(Tok, AddrSpace))
return Err;
if (!isUInt<24>(AddrSpace))
return reportError("Invalid address space, must be a 24-bit integer");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error messages should start with lowercase

}
if (Rest.empty())
return reportError(
"Missing address space value specification for pointer in "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error messages should start with lowercase

"datalayout string");
if (Error Err = ::split(Rest, ':', Split))
return Err;
if (Error Err = getIntForAddrSpace(Tok, Value))
return Err;
setSentinelPointerValue(AddrSpace, Value);
break;
}
case 'G': { // Default address space for global variables.
if (Error Err = getAddrSpace(Tok, DefaultGlobalsAddrSpace))
return Err;
Expand Down Expand Up @@ -704,6 +749,7 @@ class StructLayoutMap {
} // end anonymous namespace

void DataLayout::clear() {

LegalIntWidths.clear();
IntAlignments.clear();
FloatAlignments.clear();
Expand Down
5 changes: 5 additions & 0 deletions llvm/test/Assembler/datalayout-invalid-address-space-value.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s 2>&1 | FileCheck %s

; CHECK: error: not a number, or does not fit in an unsigned int

target datalayout = "z:neg"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those should be unit tests in DataLayoutTest, IMO.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s 2>&1 | FileCheck %s

; CHECK: error: not a number, or does not fit in an unsigned int

target datalayout = "z:neg-1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s 2>&1 | FileCheck %s

; CHECK: error: Trailing separator in datalayout string

target datalayout = "z:"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline at end of file in most of these

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s 2>&1 | FileCheck %s

; CHECK: error: Trailing separator in datalayout string

target datalayout = "z:-1"
5 changes: 5 additions & 0 deletions llvm/test/Assembler/datalayout-invalid-address-space.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
; RUN: not llvm-as %s 2>&1 | FileCheck %s

; CHECK: error: not a number, or does not fit in an unsigned int

target datalayout = "za:0"
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/AMDGPU/datalayout-non-zero-lds-value.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt < %s -S -mtriple=amdgcn-- | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what this test is supposed to be showing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a positive test case to check if the data layout string related sentinel pointer value is parsed correctly.


; CHECK: target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z:0-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-z:0-z2:neg1-z3:neg1-z5:neg1-S32-A5-G1-ni:7:8:9"
@lds = addrspace(3) global [8 x i32] [i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8]

define amdgpu_kernel void @load_init_lds_global(ptr addrspace(1) %out, i1 %p) {
; CHECK-LABEL: define amdgpu_kernel void @load_init_lds_global(
; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]], i1 [[P:%.*]]) {
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [8 x i32], ptr addrspace(3) @lds, i32 0, i32 10
; CHECK-NEXT: [[LD:%.*]] = load i32, ptr addrspace(3) [[GEP]], align 4
; CHECK-NEXT: store i32 [[LD]], ptr addrspace(1) [[OUT]], align 4
; CHECK-NEXT: ret void
;
%gep = getelementptr [8 x i32], ptr addrspace(3) @lds, i32 0, i32 10
%ld = load i32, ptr addrspace(3) %gep
store i32 %ld, ptr addrspace(1) %out
ret void
}