Skip to content

Commit

Permalink
Add support for non-zero null pointer for C and OpenCL
Browse files Browse the repository at this point in the history
In amdgcn target, null pointers in global, constant, and generic address space take value 0 but null pointers in private and local address space take value -1. Currently LLVM assumes all null pointers take value 0, which results in incorrectly translated IR. To workaround this issue, instead of emit null pointers in local and private address space, a null pointer in generic address space is emitted and casted to local and private address space.

Tentative definition of global variables with non-zero initializer will have weak linkage instead of common linkage since common linkage requires zero initializer and does not have explicit section to hold the non-zero value.

Virtual member functions getNullPointer and performAddrSpaceCast are added to TargetCodeGenInfo which by default returns ConstantPointerNull and emitting addrspacecast instruction. A virtual member function getNullPointerValue is added to TargetInfo which by default returns 0. Each target can override these virtual functions to get target specific null pointer and the null pointer value for specific address space, and perform specific translations for addrspacecast.

Wrapper functions getNullPointer is added to CodegenModule and getTargetNullPointerValue is added to ASTContext to facilitate getting the target specific null pointers and their values.

This change has no effect on other targets except amdgcn target. Other targets can provide support of non-zero null pointer in a similar way.

This change only provides support for non-zero null pointer for C and OpenCL. Supporting for other languages will be added later incrementally.

Differential Revision: https://reviews.llvm.org/D26196

llvm-svn: 289252
  • Loading branch information
yxsamliu committed Dec 9, 2016
1 parent df41b13 commit 8f66b4b
Show file tree
Hide file tree
Showing 18 changed files with 765 additions and 67 deletions.
14 changes: 8 additions & 6 deletions clang/include/clang/AST/APValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,15 @@ class APValue {
}
APValue(const APValue &RHS);
APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }
APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex,
bool IsNullPtr = false)
: Kind(Uninitialized) {
MakeLValue(); setLValue(B, O, N, CallIndex);
MakeLValue(); setLValue(B, O, N, CallIndex, IsNullPtr);
}
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
bool OnePastTheEnd, unsigned CallIndex)
bool OnePastTheEnd, unsigned CallIndex, bool IsNullPtr = false)
: Kind(Uninitialized) {
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex, IsNullPtr);
}
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
MakeArray(InitElts, Size);
Expand Down Expand Up @@ -254,6 +255,7 @@ class APValue {
bool hasLValuePath() const;
ArrayRef<LValuePathEntry> getLValuePath() const;
unsigned getLValueCallIndex() const;
bool isNullPointer() const;

APValue &getVectorElt(unsigned I) {
assert(isVector() && "Invalid accessor");
Expand Down Expand Up @@ -374,10 +376,10 @@ class APValue {
((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I);
}
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
unsigned CallIndex);
unsigned CallIndex, bool IsNullPtr);
void setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
unsigned CallIndex);
unsigned CallIndex, bool IsNullPtr);
void setUnion(const FieldDecl *Field, const APValue &Value) {
assert(isUnion() && "Invalid accessor");
((UnionData*)(char*)Data.buffer)->Field = Field;
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
return (*AddrSpaceMap)[AS - LangAS::Offset];
}

/// Get target-dependent integer value for null pointer which is used for
/// constant folding.
uint64_t getTargetNullPointerValue(QualType QT) const;

bool addressSpaceMapManglingFor(unsigned AS) const {
return AddrSpaceMapMangling ||
AS < LangAS::Offset ||
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class DiagnosticsEngine;
class LangOptions;
class CodeGenOptions;
class MacroBuilder;
class QualType;
class SourceLocation;
class SourceManager;

Expand Down Expand Up @@ -300,6 +301,12 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
return PointerWidth;
}

/// \brief Get integer value for null pointer.
/// \param AddrSpace address space of pointee in source language.
virtual uint64_t getNullPointerValue(unsigned AddrSpace) const {
return 0;
}

/// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits.
unsigned getBoolWidth() const { return BoolWidth; }

Expand Down
17 changes: 13 additions & 4 deletions clang/lib/AST/APValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace {
CharUnits Offset;
unsigned PathLength;
unsigned CallIndex;
bool IsNullPtr;
};
}

Expand Down Expand Up @@ -149,10 +150,11 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) {
MakeLValue();
if (RHS.hasLValuePath())
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex());
RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(),
RHS.isNullPointer());
else
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
RHS.getLValueCallIndex());
RHS.getLValueCallIndex(), RHS.isNullPointer());
break;
case Array:
MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
Expand Down Expand Up @@ -579,20 +581,26 @@ unsigned APValue::getLValueCallIndex() const {
return ((const LV*)(const char*)Data.buffer)->CallIndex;
}

bool APValue::isNullPointer() const {
assert(isLValue() && "Invalid usage");
return ((const LV*)(const char*)Data.buffer)->IsNullPtr;
}

void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
unsigned CallIndex) {
unsigned CallIndex, bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
LVal.BaseAndIsOnePastTheEnd.setInt(false);
LVal.Offset = O;
LVal.CallIndex = CallIndex;
LVal.resizePath((unsigned)-1);
LVal.IsNullPtr = IsNullPtr;
}

void APValue::setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
unsigned CallIndex) {
unsigned CallIndex, bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
Expand All @@ -601,6 +609,7 @@ void APValue::setLValue(LValueBase B, const CharUnits &O,
LVal.CallIndex = CallIndex;
LVal.resizePath(Path.size());
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
LVal.IsNullPtr = IsNullPtr;
}

const ValueDecl *APValue::getMemberPointerDecl() const {
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9426,6 +9426,16 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,

}

uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
unsigned AS;
if (QT->getUnqualifiedDesugaredType()->isNullPtrType())
AS = 0;
else
AS = QT->getPointeeType().getAddressSpace();

return getTargetInfo().getNullPointerValue(AS);
}

// Explicitly instantiate this in case a Redeclarable<T> is used from a TU that
// doesn't include ASTContext.h
template
Expand Down
57 changes: 42 additions & 15 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1070,20 +1070,23 @@ namespace {
unsigned InvalidBase : 1;
unsigned CallIndex : 31;
SubobjectDesignator Designator;
bool IsNullPtr;

const APValue::LValueBase getLValueBase() const { return Base; }
CharUnits &getLValueOffset() { return Offset; }
const CharUnits &getLValueOffset() const { return Offset; }
unsigned getLValueCallIndex() const { return CallIndex; }
SubobjectDesignator &getLValueDesignator() { return Designator; }
const SubobjectDesignator &getLValueDesignator() const { return Designator;}
bool isNullPointer() const { return IsNullPtr;}

void moveInto(APValue &V) const {
if (Designator.Invalid)
V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex);
V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex,
IsNullPtr);
else
V = APValue(Base, Offset, Designator.Entries,
Designator.IsOnePastTheEnd, CallIndex);
Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);
}
void setFrom(ASTContext &Ctx, const APValue &V) {
assert(V.isLValue());
Expand All @@ -1092,14 +1095,17 @@ namespace {
InvalidBase = false;
CallIndex = V.getLValueCallIndex();
Designator = SubobjectDesignator(Ctx, V);
IsNullPtr = V.isNullPointer();
}

void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {
void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false,
bool IsNullPtr_ = false, uint64_t Offset_ = 0) {
Base = B;
Offset = CharUnits::Zero();
Offset = CharUnits::fromQuantity(Offset_);
InvalidBase = BInvalid;
CallIndex = I;
Designator = SubobjectDesignator(getType(B));
IsNullPtr = IsNullPtr_;
}

void setInvalid(APValue::LValueBase B, unsigned I = 0) {
Expand All @@ -1112,7 +1118,7 @@ namespace {
CheckSubobjectKind CSK) {
if (Designator.Invalid)
return false;
if (!Base) {
if (IsNullPtr) {
Info.CCEDiag(E, diag::note_constexpr_null_subobject)
<< CSK;
Designator.setInvalid();
Expand Down Expand Up @@ -1141,9 +1147,22 @@ namespace {
if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
Designator.addComplexUnchecked(EltTy, Imag);
}
void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
if (N && checkNullPointer(Info, E, CSK_ArrayIndex))
Designator.adjustIndex(Info, E, N);
void clearIsNullPointer() {
IsNullPtr = false;
}
void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, uint64_t Index,
CharUnits ElementSize) {
// Compute the new offset in the appropriate width.
Offset += Index * ElementSize;
if (Index && checkNullPointer(Info, E, CSK_ArrayIndex))
Designator.adjustIndex(Info, E, Index);
if (Index)
clearIsNullPointer();
}
void adjustOffset(CharUnits N) {
Offset += N;
if (N.getQuantity())
clearIsNullPointer();
}
};

Expand Down Expand Up @@ -2018,7 +2037,7 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
}

unsigned I = FD->getFieldIndex();
LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I));
LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I)));
LVal.addDecl(Info, E, FD);
return true;
}
Expand Down Expand Up @@ -2072,9 +2091,7 @@ static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee))
return false;

// Compute the new offset in the appropriate width.
LVal.Offset += Adjustment * SizeOfPointee;
LVal.adjustIndex(Info, E, Adjustment);
LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee);
return true;
}

Expand Down Expand Up @@ -5060,7 +5077,9 @@ class PointerExprEvaluator
return true;
}
bool ZeroInitialization(const Expr *E) {
return Success((Expr*)nullptr);
auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType());
Result.set((Expr*)nullptr, 0, false, true, Offset);
return true;
}

bool VisitBinaryOperator(const BinaryOperator *E);
Expand Down Expand Up @@ -5159,6 +5178,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
else
CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
}
if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
ZeroInitialization(E);
return true;

case CK_DerivedToBase:
Expand Down Expand Up @@ -5200,6 +5221,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
Result.Offset = CharUnits::fromQuantity(N);
Result.CallIndex = 0;
Result.Designator.setInvalid();
Result.IsNullPtr = false;
return true;
} else {
// Cast is of an lvalue, no need to change value.
Expand Down Expand Up @@ -8334,8 +8356,13 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return true;
}

APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
SrcType);
uint64_t V;
if (LV.isNullPointer())
V = Info.Ctx.getTargetNullPointerValue(SrcType);
else
V = LV.getLValueOffset().getQuantity();

APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType);
return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E);
}

Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Basic/Targets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,13 @@ class AMDGPUTargetInfo final : public TargetInfo {
return CCCR_OK;
}
}

// In amdgcn target the null pointer in global, constant, and generic
// address space has value 0 but in private and local address space has
// value ~0.
uint64_t getNullPointerValue(unsigned AS) const override {
return AS != LangAS::opencl_local && AS != 0 ? 0 : ~0;
}
};

const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
}

auto ty = cast<llvm::PointerType>(tempLV.getAddress().getElementType());
llvm::Value *zero = llvm::ConstantPointerNull::get(ty);
llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType());

// If __weak, we want to use a barrier under certain conditions.
if (lifetime == Qualifiers::OCL_Weak)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,8 @@ static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
return true;
// (int*)0 - Null pointer expressions.
if (const CastExpr *ICE = dyn_cast<CastExpr>(E))
return ICE->getCastKind() == CK_NullToPointer;
return ICE->getCastKind() == CK_NullToPointer &&
CGF.getTypes().isPointerZeroInitializable(E->getType());
// '\0'
if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E))
return CL->getValue() == 0;
Expand Down
Loading

0 comments on commit 8f66b4b

Please sign in to comment.