Skip to content
Draft
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
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static const char *const DataLayoutStringR600 =
"-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1";

static const char *const DataLayoutStringAMDGCN =
"e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32"
"e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32:32"
"-p7:160:256:256:32-p8:128:128:128:48-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-S32-A5-G1-ni:7:8:9";
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@

// RUN: %clang_cc1 -triple amdgcn-unknown -target-cpu hawaii -o - -emit-llvm %s \
// RUN: | FileCheck %s -check-prefix=R600SI
// R600SI: target datalayout = "e-m: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:128:48-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-S32-A5-G1-ni:7:8:9"
// R600SI: target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-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-S32-A5-G1-ni:7:8:9"

// Test default -target-cpu
// RUN: %clang_cc1 -triple amdgcn-unknown -o - -emit-llvm %s \
// RUN: | FileCheck %s -check-prefix=R600SIDefault
// R600SIDefault: target datalayout = "e-m: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:128:48-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-S32-A5-G1-ni:7:8:9"
// R600SIDefault: target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-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-S32-A5-G1-ni:7:8:9"

// RUN: %clang_cc1 -triple arm64-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=AARCH64
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenOpenCL/amdgpu-env-amdgcn.cl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 %s -O0 -triple amdgcn -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -O0 -triple amdgcn---opencl -emit-llvm -o - | FileCheck %s

// CHECK: target datalayout = "e-m: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:128:48-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-S32-A5-G1-ni:7:8:9"
// CHECK: target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128:128:48-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-S32-A5-G1-ni:7:8:9"
void foo(void) {}
6 changes: 3 additions & 3 deletions lld/test/ELF/lto/amdgcn-oses.ll
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

;--- amdhsa.ll
target triple = "amdgcn-amd-amdhsa"
target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32: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-S32-A5"
target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32: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-S32-A5"

!llvm.module.flags = !{!0}
!0 = !{i32 1, !"amdhsa_code_object_version", i32 500}
Expand All @@ -36,15 +36,15 @@ define void @_start() {

;--- amdpal.ll
target triple = "amdgcn-amd-amdpal"
target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32: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-S32-A5"
target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32: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-S32-A5"

define amdgpu_cs void @_start() {
ret void
}

;--- mesa3d.ll
target triple = "amdgcn-amd-mesa3d"
target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32: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-S32-A5"
target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32: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-S32-A5"

define void @_start() {
ret void
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/lto/amdgcn.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
; Make sure the amdgcn triple is handled

target triple = "amdgcn-amd-amdhsa"
target datalayout = "e-m:e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32: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-S32-A5"
target datalayout = "e-m:e-p:64:64-p1:64:64-po2:32:32-po3:32:32-p4:64:64-po5:32:32-p6:32: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-S32-A5"

define void @_start() {
ret void
Expand Down
8 changes: 6 additions & 2 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3322,8 +3322,12 @@ as follows:
default address space 0. The value of ``<as>`` must be in the range [1,2^24).
The optional ``<flags>`` are used to specify properties of pointers in this
address space: the character ``u`` marks pointers as having an unstable
representation, and ``e`` marks pointers having external state. See
:ref:`Non-Integral Pointer Types <nointptrtype>`.
representation; ``e`` marks pointers having external state; ``z`` marks the
value of the nullptr as all-zeros (default behavior if it is not specified);
``o`` marks the value of the nullptr as all-ones; ``c`` marks the value of
the nullptr as custom (neither all-zeros nor all-ones), such that LLVM will
not be able to fold various casts involving nullptr.
See :ref:`Non-Integral Pointer Types <nointptrtype>`.

``i<size>:<abi>[:<pref>]``
This specifies the alignment for an integer type of a given bit
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/Constant.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ class Constant : public User {

LLVM_ABI static Constant *getNullValue(Type *Ty);

LLVM_ABI static Constant *getZeroValue(Type *Ty);

/// @returns the value for an integer or vector of integer constant of the
/// given type that has all its bits set to true.
/// Get the all ones value
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/IR/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,9 @@ class ConstantAggregate : public Constant {
/// Transparently provide more efficient getOperand methods.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant);

/// Return true if the constant aggregate contains all null values.
inline bool isNullValue() const;

/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const Value *V) {
return V->getValueID() >= ConstantAggregateFirstVal &&
Expand Down Expand Up @@ -443,6 +446,8 @@ class ConstantArray final : public ConstantAggregate {
// ConstantArray accessors
LLVM_ABI static Constant *get(ArrayType *T, ArrayRef<Constant *> V);

LLVM_ABI static Constant *getNullValue(ArrayType *T);

private:
static Constant *getImpl(ArrayType *T, ArrayRef<Constant *> V);

Expand Down Expand Up @@ -475,6 +480,8 @@ class ConstantStruct final : public ConstantAggregate {
// ConstantStruct accessors
LLVM_ABI static Constant *get(StructType *T, ArrayRef<Constant *> V);

LLVM_ABI static Constant *getNullValue(StructType *T);

template <typename... Csts>
static std::enable_if_t<are_base_of<Constant, Csts...>::value, Constant *>
get(StructType *T, Csts *...Vs) {
Expand Down Expand Up @@ -527,6 +534,8 @@ class ConstantVector final : public ConstantAggregate {
// ConstantVector accessors
LLVM_ABI static Constant *get(ArrayRef<Constant *> V);

LLVM_ABI static Constant *getNullValue(VectorType *T);

private:
static Constant *getImpl(ArrayRef<Constant *> V);

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

/// Internal helper to get alignment for integer of given bitwidth.
LLVM_ABI Align getIntegerAlignment(uint32_t BitWidth, bool abi_or_pref) const;
Expand Down Expand Up @@ -697,6 +703,11 @@ class DataLayout {
///
/// This includes an explicitly requested alignment (if the global has one).
LLVM_ABI Align getPreferredAlign(const GlobalVariable *GV) const;

/// Returns the value of the nullptr in the given address space.
LLVM_ABI std::optional<APInt> getNullPtrValue(unsigned AddrSpace) const {
return getPointerSpec(AddrSpace).NullPtrValue;
}
};

inline DataLayout *unwrap(LLVMTargetDataRef P) {
Expand Down
41 changes: 40 additions & 1 deletion llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,21 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
llvm_unreachable("Missing case");
case Instruction::PtrToAddr:
case Instruction::PtrToInt:
// If the input is a nullptr, we can fold it to the corresponding nullptr
// value.
if (Opcode == Instruction::PtrToInt && C->isNullValue()) {
if (std::optional<APInt> NullPtrValue = DL.getNullPtrValue(
C->getType()->getScalarType()->getPointerAddressSpace())) {
if (NullPtrValue->isZero()) {
return Constant::getZeroValue(DestTy);
} else if (NullPtrValue->isAllOnes()) {
return ConstantInt::get(
DestTy, NullPtrValue->zextOrTrunc(DestTy->getScalarSizeInBits()));
} else {
llvm_unreachable("invalid nullptr value");
}
Comment on lines +1505 to +1512
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (NullPtrValue->isZero()) {
return Constant::getZeroValue(DestTy);
} else if (NullPtrValue->isAllOnes()) {
return ConstantInt::get(
DestTy, NullPtrValue->zextOrTrunc(DestTy->getScalarSizeInBits()));
} else {
llvm_unreachable("invalid nullptr value");
}
assert(NullPtrValue->isZero() || NullPtrValue->isAllOnes());
return ConstantInt::get(
DestTy, NullPtrValue->zextOrTrunc(DestTy->getScalarSizeInBits()));

I believe this is equivalent and a bit simpler.

}
}
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
Constant *FoldedValue = nullptr;
// If the input is an inttoptr, eliminate the pair. This requires knowing
Expand Down Expand Up @@ -1543,6 +1558,13 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
}
break;
case Instruction::IntToPtr:
// We can fold it to a null pointer if the input is the nullptr value.
if (std::optional<APInt> NullPtrValue = DL.getNullPtrValue(
DestTy->getScalarType()->getPointerAddressSpace())) {
if ((NullPtrValue->isZero() && C->isZeroValue()) ||
(NullPtrValue->isAllOnes() && C->isAllOnesValue()))
Copy link
Member

Choose a reason for hiding this comment

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

I think we have to check the width of the input value for all ones since inttoptr zero-extends, so a short value would not end up as canonical nullptr.

return Constant::getNullValue(DestTy);
}
// If the input is a ptrtoint, turn the pair into a ptr to ptr bitcast if
// the int size is >= the ptr size and the address spaces are the same.
// This requires knowing the width of a pointer, so it can't be done in
Expand All @@ -1561,6 +1583,24 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
}
}
break;
case Instruction::AddrSpaceCast:
// A null pointer (`ptr addrspace(N) null` in IR presentation,
// `ConstantPointerNull` in LLVM class, not `nullptr` in C/C++) used to
// represent a zero-value pointer in the corresponding address space.
// Therefore, we can't simply fold an address space cast of a null pointer
// from one address space to another, because on some targets, the nullptr
// of an address space could be non-zero.
//
// Recently, the semantic of `ptr addrspace(N) null` is changed to represent
// the actual nullptr in the corresponding address space. It can be zero or
// non-zero, depending on the target. Therefore, we can fold an address
// space cast of a nullptr from one address space to another.

// If the input is a nullptr, we can fold it to the corresponding
// nullptr in the destination address space.
if (C->isNullValue())
Copy link
Member

Choose a reason for hiding this comment

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

Is this actually true? Are null values in one address space always null in all others? I imagine this is almost always true, but maybe you could have some where this conversion is not valid?

Copy link
Member

Choose a reason for hiding this comment

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

I don't see this property in langref so we should either add it or drop this fold.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this actually true? Are null values in one address space always null in all others? I imagine this is almost always true, but maybe you could have some where this conversion is not valid?

This is actually the whole point of this PR. The semantic would be, convert the nullptr in AS X to AS Y, so it would still be a nullptr in AS Y. I don't think the semantic should be convert the value of nullptr in AS X to the corresponding pointer value in AS Y.

I'll clarify this in the LangRef.

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good

return Constant::getNullValue(DestTy);
[[fallthrough]];
case Instruction::Trunc:
case Instruction::ZExt:
case Instruction::SExt:
Expand All @@ -1570,7 +1610,6 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
case Instruction::SIToFP:
case Instruction::FPToUI:
case Instruction::FPToSI:
case Instruction::AddrSpaceCast:
break;
case Instruction::BitCast:
return FoldBitCast(C, DestTy, DL);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6575,7 +6575,7 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
if (auto *TETy = dyn_cast<TargetExtType>(Ty))
if (!TETy->hasProperty(TargetExtType::HasZeroInit))
return error(ID.Loc, "invalid type for null constant");
V = Constant::getNullValue(Ty);
V = Constant::getZeroValue(Ty);
return false;
case ValID::t_None:
if (!Ty->isTokenTy())
Expand Down
11 changes: 9 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4275,8 +4275,15 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,
return emitGlobalConstantFP(CFP, AP);
}

if (isa<ConstantPointerNull>(CV)) {
AP.OutStreamer->emitIntValue(0, Size);
if (auto *NullPtr = dyn_cast<ConstantPointerNull>(CV)) {
if (std::optional<APInt> NullPtrVal =
DL.getNullPtrValue(NullPtr->getType()->getPointerAddressSpace())) {
AP.OutStreamer->emitIntValue(NullPtrVal->getSExtValue(), Size);
} else {
// We fall back to the default behavior of emitting a zero value if we
// can't get the null pointer value from the data layout.
AP.OutStreamer->emitIntValue(0, Size);
}
Comment on lines +4279 to +4286
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (std::optional<APInt> NullPtrVal =
DL.getNullPtrValue(NullPtr->getType()->getPointerAddressSpace())) {
AP.OutStreamer->emitIntValue(NullPtrVal->getSExtValue(), Size);
} else {
// We fall back to the default behavior of emitting a zero value if we
// can't get the null pointer value from the data layout.
AP.OutStreamer->emitIntValue(0, Size);
}
APInt NullPtrVal = DL.getNullPtrValue(NullPtr->getType()->getPointerAddressSpace());
AP.OutStreamer->emitIntValue(NullPtrVal.getSExtValue(), Size);

I wonder if we should drop the std::optional from the DataLayout and just always have a defined value? We could then also either drop the 'c' flag or do something like pc{0xaaaaa}3:64:64 to define a AS3 pointer with nullptr value of 0xaaaa?

Silently falling back to zero here seems like it would cause more pain for hypothetical targets with custom null pointers than forcing them to set the datalayout?

return;
}

Expand Down
15 changes: 12 additions & 3 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3768,9 +3768,18 @@ bool IRTranslator::translate(const Constant &C, Register Reg) {
EntryBuilder->buildFConstant(Reg, *CF);
} else if (isa<UndefValue>(C))
EntryBuilder->buildUndef(Reg);
else if (isa<ConstantPointerNull>(C))
EntryBuilder->buildConstant(Reg, 0);
else if (auto GV = dyn_cast<GlobalValue>(&C))
else if (auto *NullPtr = dyn_cast<ConstantPointerNull>(&C)) {
const DataLayout &DL = EntryBuilder->getMF().getDataLayout();
if (std::optional<APInt> NullPtrValue =
DL.getNullPtrValue(NullPtr->getType()->getAddressSpace())) {
if (NullPtrValue->isZero())
EntryBuilder->buildConstant(Reg, 0);
else if (NullPtrValue->isAllOnes())
EntryBuilder->buildConstant(Reg, -1);
else
llvm_unreachable("unknown null pointer value");
}
} else if (auto GV = dyn_cast<GlobalValue>(&C))
EntryBuilder->buildGlobalValue(Reg, GV);
else if (auto CPA = dyn_cast<ConstantPtrAuth>(&C)) {
Register Addr = getOrCreateVReg(*CPA->getPointer());
Expand Down
14 changes: 12 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1872,8 +1872,18 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
getValue(CPA->getDiscriminator()));
}

if (isa<ConstantPointerNull>(C))
return DAG.getConstant(0, getCurSDLoc(), VT);
if (auto *NullPtr = dyn_cast<ConstantPointerNull>(C)) {
const DataLayout &DL = DAG.getDataLayout();
if (std::optional<APInt> NullPtrValue =
DL.getNullPtrValue(NullPtr->getType()->getAddressSpace())) {
if (NullPtrValue->isZero())
return DAG.getConstant(0, getCurSDLoc(), VT);
else if (NullPtrValue->isAllOnes())
return DAG.getAllOnesConstant(getCurSDLoc(), VT);
else
llvm_unreachable("unknown null pointer value");
}
}

if (match(C, m_VScale()))
return DAG.getVScale(getCurSDLoc(), VT, APInt(VT.getSizeInBits(), 1));
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1806,6 +1806,15 @@ static void writeConstantInternal(raw_ostream &Out, const Constant *CV,
}
}

// Use zeroinitializer for inttoptr(0) constant expression.
if (CE->getOpcode() == Instruction::IntToPtr) {
Constant *SrcCI = cast<Constant>(CE->getOperand(0));
if (SrcCI->isZeroValue()) {
Out << "zeroinitializer";
return;
}
}

Out << CE->getOpcodeName();
writeOptimizationInfo(Out, CE);
Out << " (";
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/IR/ConstantFold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,40 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V,
if (isa<PoisonValue>(V))
return PoisonValue::get(DestTy);

if (opc == Instruction::IntToPtr) {
// We can't fold inttoptr(0) to ConstantPointerNull without checking the
// target data layout. However, since data layout is not available here, we
// can't do this.
if (V->isZeroValue())
return nullptr;
Comment on lines +130 to +134
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// We can't fold inttoptr(0) to ConstantPointerNull without checking the
// target data layout. However, since data layout is not available here, we
// can't do this.
if (V->isZeroValue())
return nullptr;
// Note: We can't fold inttoptr(0) to ConstantPointerNull without checking
// the target data layout since null pointers could also be all-ones.

I don't think we need the early return here? Although I guess it's a cheap check and so might actually be better to have it.

Copy link
Member

Choose a reason for hiding this comment

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

Ah is this because of the V->isNullValue() below? In that case let's keep it.

// If the input is a ptrtoint(0), we can fold it to the corresponding zero
// value pointer.
if (auto *CE = dyn_cast<ConstantExpr>(V)) {
if (CE->getOpcode() == Instruction::PtrToInt) {
if (CE->getOperand(0)->isZeroValue())
return Constant::getZeroValue(DestTy);
}
}
}
if (opc == Instruction::PtrToInt) {
// Similarly, we can't fold ptrtoint(nullptr) to null.
if (V->isNullValue())
return nullptr;
// If the input is a inttoptr(0), we can fold it to the corresponding
// zero value.
if (auto *CE = dyn_cast<ConstantExpr>(V)) {
if (CE->getOpcode() == Instruction::IntToPtr) {
if (CE->getOperand(0)->isZeroValue())
return Constant::getZeroValue(DestTy);
}
}
}
// However, since the recent change of the semantic of `ptr addrspace(N)
// null`, we can fold address space cast of a nullptr to the corresponding
// nullptr in the destination address space.
if (opc == Instruction::AddrSpaceCast && V->isNullValue())
return Constant::getNullValue(DestTy);

if (isa<UndefValue>(V)) {
// zext(undef) = 0, because the top bits will be zero.
// sext(undef) = 0, because the top bits will all be the same.
Expand Down
Loading
Loading