Skip to content

Commit a3f0889

Browse files
committed
[WIP][IR][Constants] Use ptr addrspace(N) zeroinitializer to represent a zero-value pointer
1 parent 260f9e9 commit a3f0889

39 files changed

+307
-203
lines changed

llvm/include/llvm/IR/Constant.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ class Constant : public User {
189189

190190
LLVM_ABI static Constant *getNullValue(Type *Ty);
191191

192+
LLVM_ABI static Constant *getZeroValue(Type *Ty);
193+
192194
/// @returns the value for an integer or vector of integer constant of the
193195
/// given type that has all its bits set to true.
194196
/// Get the all ones value

llvm/include/llvm/IR/DataLayout.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ class DataLayout {
8383
/// for additional metadata (e.g. AMDGPU buffer fat pointers with bounds
8484
/// and other flags or CHERI capabilities that contain bounds+permissions).
8585
uint32_t IndexBitWidth;
86+
/// The value of the nullptr in this address space. It can be three values:
87+
/// all-zeros, all-ones, or std::nullopt. Since we don't have a way to
88+
/// represent an arbitrary bit pattern, we use std::nullopt to represent the
89+
/// case where the nullptr value is neither 0 nor -1.
90+
std::optional<APInt> NullPtrValue;
8691
/// Pointers in this address space don't have a well-defined bitwise
8792
/// representation (e.g. they may be relocated by a copying garbage
8893
/// collector and thus have different addresses at different times).
@@ -158,7 +163,8 @@ class DataLayout {
158163
/// Sets or updates the specification for pointer in the given address space.
159164
void setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth, Align ABIAlign,
160165
Align PrefAlign, uint32_t IndexBitWidth,
161-
bool HasUnstableRepr, bool HasExternalState);
166+
std::optional<APInt> NullPtrValue, bool HasUnstableRepr,
167+
bool HasExternalState);
162168

163169
/// Internal helper to get alignment for integer of given bitwidth.
164170
LLVM_ABI Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const;
@@ -697,6 +703,11 @@ class DataLayout {
697703
///
698704
/// This includes an explicitly requested alignment (if the global has one).
699705
LLVM_ABI Align getPreferredAlign(const GlobalVariable *GV) const;
706+
707+
/// Returns the value of the nullptr in the given address space.
708+
LLVM_ABI std::optional<APInt> getNullPtrValue(unsigned AddrSpace) const {
709+
return getPointerSpec(AddrSpace).NullPtrValue;
710+
}
700711
};
701712

702713
inline DataLayout *unwrap(LLVMTargetDataRef P) {

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,19 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
14971497
llvm_unreachable("Missing case");
14981498
case Instruction::PtrToAddr:
14991499
case Instruction::PtrToInt:
1500+
// If the input is a nullptr, we can fold it to the corresponding nullptr
1501+
// value.
1502+
if (Opcode == Instruction::PtrToInt && C->isNullValue()) {
1503+
if (std::optional<APInt> NullPtrValue = DL.getNullPtrValue(
1504+
C->getType()->getScalarType()->getPointerAddressSpace())) {
1505+
if (NullPtrValue->isZero())
1506+
return Constant::getZeroValue(DestTy);
1507+
else if (NullPtrValue->isAllOnes())
1508+
return Constant::getAllOnesValue(DestTy);
1509+
else
1510+
llvm_unreachable("invalid nullptr value");
1511+
}
1512+
}
15001513
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
15011514
Constant *FoldedValue = nullptr;
15021515
// If the input is an inttoptr, eliminate the pair. This requires knowing
@@ -1543,6 +1556,13 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
15431556
}
15441557
break;
15451558
case Instruction::IntToPtr:
1559+
// We can fold it to a null pointer if the input is the nullptr value.
1560+
if (std::optional<APInt> NullPtrValue = DL.getNullPtrValue(
1561+
DestTy->getScalarType()->getPointerAddressSpace())) {
1562+
if ((NullPtrValue->isZero() && C->isZeroValue()) ||
1563+
(NullPtrValue->isAllOnes() && C->isAllOnesValue()))
1564+
return Constant::getNullValue(DestTy);
1565+
}
15461566
// If the input is a ptrtoint, turn the pair into a ptr to ptr bitcast if
15471567
// the int size is >= the ptr size and the address spaces are the same.
15481568
// This requires knowing the width of a pointer, so it can't be done in

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6575,7 +6575,7 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
65756575
if (auto *TETy = dyn_cast<TargetExtType>(Ty))
65766576
if (!TETy->hasProperty(TargetExtType::HasZeroInit))
65776577
return error(ID.Loc, "invalid type for null constant");
6578-
V = Constant::getNullValue(Ty);
6578+
V = Constant::getZeroValue(Ty);
65796579
return false;
65806580
case ValID::t_None:
65816581
if (!Ty->isTokenTy())

llvm/lib/IR/AsmWriter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,15 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
18061806
}
18071807
}
18081808

1809+
// Use zeroinitializer for inttoptr(0) constant expression.
1810+
if (CE->getOpcode() == Instruction::IntToPtr) {
1811+
Constant *SrcCI = cast<Constant>(CE->getOperand(0));
1812+
if (SrcCI->isZeroValue()) {
1813+
Out << "zeroinitializer";
1814+
return;
1815+
}
1816+
}
1817+
18091818
Out << CE->getOpcodeName();
18101819
writeOptimizationInfo(Out, CE);
18111820
Out << " (";

llvm/lib/IR/ConstantFold.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V,
126126
if (isa<PoisonValue>(V))
127127
return PoisonValue::get(DestTy);
128128

129+
// TODO: For the following two cases, we can fold the constant to a constant
130+
// according to the data layout.
131+
132+
// We can't fold inttoptr(0) to ConstantNullPointer.
133+
if (opc == Instruction::IntToPtr && V->isZeroValue())
134+
return nullptr;
135+
// We can't fold ptrtoint(nullptr) to null.
136+
if (opc == Instruction::PtrToInt && V->isNullValue())
137+
return nullptr;
138+
129139
if (isa<UndefValue>(V)) {
130140
// zext(undef) = 0, because the top bits will be zero.
131141
// sext(undef) = 0, because the top bits will all be the same.

llvm/lib/IR/Constants.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,21 @@ bool Constant::isNegativeZeroValue() const {
7272
}
7373

7474
// Return true iff this constant is positive zero (floating point), negative
75-
// zero (floating point), or a null value.
75+
// zero (floating point), zero-value pointer, or a null value.
7676
bool Constant::isZeroValue() const {
7777
// Floating point values have an explicit -0.0 value.
7878
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
7979
return CFP->isZero();
8080

81+
// Zero value pointer is a constant expression of inttoptr(0).
82+
if (const auto *CE = dyn_cast<ConstantExpr>(this)) {
83+
if (CE->getOpcode() == Instruction::IntToPtr) {
84+
Constant *SrcCI = cast<Constant>(CE->getOperand(0));
85+
if (SrcCI->isZeroValue())
86+
return true;
87+
}
88+
}
89+
8190
// Check for constant splat vectors of 1 values.
8291
if (getType()->isVectorTy())
8392
if (const auto *SplatCFP = dyn_cast_or_null<ConstantFP>(getSplatValue()))
@@ -369,7 +378,10 @@ bool Constant::containsConstantExpression() const {
369378
return false;
370379
}
371380

372-
/// Constructor to create a '0' constant of arbitrary type.
381+
/// Constructor that creates a null constant of any type. For most types, this
382+
/// means a constant with value '0', but for pointer types, it represents a
383+
/// nullptr constant. A nullptr isn't always a zero-value pointer in certain
384+
/// address spaces on some targets.
373385
Constant *Constant::getNullValue(Type *Ty) {
374386
switch (Ty->getTypeID()) {
375387
case Type::IntegerTyID:
@@ -400,6 +412,19 @@ Constant *Constant::getNullValue(Type *Ty) {
400412
}
401413
}
402414

415+
/// Constructor that creates a zero constant of any type. For most types, this
416+
/// is equivalent to getNullValue. For pointer types, it creates an inttoptr
417+
/// constant expression.
418+
Constant *Constant::getZeroValue(Type *Ty) {
419+
switch (Ty->getTypeID()) {
420+
case Type::PointerTyID:
421+
return ConstantExpr::getIntToPtr(
422+
ConstantInt::get(Type::getInt8Ty(Ty->getContext()), 0), Ty);
423+
default:
424+
return Constant::getNullValue(Ty);
425+
}
426+
}
427+
403428
Constant *Constant::getIntegerValue(Type *Ty, const APInt &V) {
404429
Type *ScalarTy = Ty->getScalarType();
405430

@@ -735,7 +760,7 @@ static bool constantIsDead(const Constant *C, bool RemoveDeadUsers) {
735760
ReplaceableMetadataImpl::SalvageDebugInfo(*C);
736761
const_cast<Constant *>(C)->destroyConstant();
737762
}
738-
763+
739764
return true;
740765
}
741766

llvm/lib/IR/DataLayout.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,11 @@ constexpr DataLayout::PrimitiveSpec DefaultVectorSpecs[] = {
193193
};
194194

195195
// Default pointer type specifications.
196-
constexpr DataLayout::PointerSpec DefaultPointerSpecs[] = {
196+
const DataLayout::PointerSpec DefaultPointerSpecs[] = {
197197
// p0:64:64:64:64
198-
{0, 64, Align::Constant<8>(), Align::Constant<8>(), 64, false, false},
198+
{0, 64, Align::Constant<8>(), Align::Constant<8>(), /*IndexBitWidth=*/64,
199+
/*NullPtrValue=*/APInt(64, 0), /*HasUnstableRepr=*/false,
200+
/*HasExternalState=*/false},
199201
};
200202

201203
DataLayout::DataLayout()
@@ -461,8 +463,9 @@ Error DataLayout::parsePointerSpec(StringRef Spec) {
461463
return createStringError(
462464
"index size cannot be larger than the pointer size");
463465

466+
// TODO: update the spec string parser to get the correct nullptr value.
464467
setPointerSpec(AddrSpace, BitWidth, ABIAlign, PrefAlign, IndexBitWidth,
465-
UnstableRepr, ExternalState);
468+
APInt(BitWidth, 0), UnstableRepr, ExternalState);
466469
return Error::success();
467470
}
468471

@@ -638,6 +641,7 @@ Error DataLayout::parseLayoutString(StringRef LayoutString) {
638641
// the spec for AS0, and we then update that to mark it non-integral.
639642
const PointerSpec &PS = getPointerSpec(AS);
640643
setPointerSpec(AS, PS.BitWidth, PS.ABIAlign, PS.PrefAlign, PS.IndexBitWidth,
644+
PS.NullPtrValue,
641645
/*HasUnstableRepr=*/true, /*HasExternalState=*/false);
642646
}
643647

@@ -686,18 +690,20 @@ DataLayout::getPointerSpec(uint32_t AddrSpace) const {
686690

687691
void DataLayout::setPointerSpec(uint32_t AddrSpace, uint32_t BitWidth,
688692
Align ABIAlign, Align PrefAlign,
689-
uint32_t IndexBitWidth, bool HasUnstableRepr,
690-
bool HasExternalState) {
693+
uint32_t IndexBitWidth,
694+
std::optional<APInt> NullPtrValue,
695+
bool HasUnstableRepr, bool HasExternalState) {
691696
auto I = lower_bound(PointerSpecs, AddrSpace, LessPointerAddrSpace());
692697
if (I == PointerSpecs.end() || I->AddrSpace != AddrSpace) {
693698
PointerSpecs.insert(I, PointerSpec{AddrSpace, BitWidth, ABIAlign, PrefAlign,
694-
IndexBitWidth, HasUnstableRepr,
695-
HasExternalState});
699+
IndexBitWidth, NullPtrValue,
700+
HasUnstableRepr, HasExternalState});
696701
} else {
697702
I->BitWidth = BitWidth;
698703
I->ABIAlign = ABIAlign;
699704
I->PrefAlign = PrefAlign;
700705
I->IndexBitWidth = IndexBitWidth;
706+
I->NullPtrValue = NullPtrValue;
701707
I->HasUnstableRepresentation = HasUnstableRepr;
702708
I->HasExternalState = HasExternalState;
703709
}

llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-constants.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ define i32 @ptrtoint_very_short() {
193193
define <2 x i160> @ptrtoint_vec() {
194194
; CHECK-LABEL: define <2 x i160> @ptrtoint_vec
195195
; CHECK-SAME: () #[[ATTR0]] {
196-
; CHECK-NEXT: ret <2 x i160> zeroinitializer
196+
; CHECK-NEXT: ret <2 x i160> ptrtoint (<2 x ptr addrspace(7)> zeroinitializer to <2 x i160>)
197197
;
198198
ret <2 x i160> ptrtoint (<2 x ptr addrspace(7)> zeroinitializer to <2 x i160>)
199199
}

llvm/test/CodeGen/AMDGPU/remove-incompatible-s-time.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
]
3434

3535
; REALTIME: @ConstantExpr0 = internal global i64 ptrtoint (ptr @needs_s_memrealtime to i64)
36-
; NOREALTIME: @ConstantExpr0 = internal global i64 0
36+
; NOREALTIME: @ConstantExpr0 = internal global i64 ptrtoint (ptr null to i64)
3737
@ConstantExpr0 = internal global i64 ptrtoint (ptr @needs_s_memrealtime to i64)
3838

3939
; MEMTIME: @ConstantExpr1 = internal global i64 ptrtoint (ptr @needs_s_memtime to i64)
40-
; NOMEMTIME: @ConstantExpr1 = internal global i64 0
40+
; NOMEMTIME: @ConstantExpr1 = internal global i64 ptrtoint (ptr null to i64)
4141
@ConstantExpr1 = internal global i64 ptrtoint (ptr @needs_s_memtime to i64)
4242

4343
; REALTIME: define i64 @needs_s_memrealtime

0 commit comments

Comments
 (0)