<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 15 December 2016 at 00:09, Yaxun Liu via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: yaxunl<br>
Date: Thu Dec 15 02:09:08 2016<br>
New Revision: 289787<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=289787&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=289787&view=rev</a><br>
Log:<br>
Re-commit r289252 and r289285, and fix PR31374<br>
<br>
Added:<br>
cfe/trunk/test/CodeGenOpenCL/<a href="http://amdgpu-nullptr.cl" rel="noreferrer" target="_blank">a<wbr>mdgpu-nullptr.cl</a><br>
Modified:<br>
cfe/trunk/include/clang/AST/<wbr>APValue.h<br>
cfe/trunk/include/clang/AST/<wbr>ASTContext.h<br>
cfe/trunk/include/clang/Basic/<wbr>TargetInfo.h<br>
cfe/trunk/lib/AST/APValue.cpp<br>
cfe/trunk/lib/AST/ASTContext.<wbr>cpp<br>
cfe/trunk/lib/AST/<wbr>ExprConstant.cpp<br>
cfe/trunk/lib/Basic/Targets.<wbr>cpp<br>
cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CGExprAgg.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CGExprConstant.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CGExprScalar.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.h<br>
cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.h<br>
cfe/trunk/lib/CodeGen/<wbr>TargetInfo.cpp<br>
cfe/trunk/lib/CodeGen/<wbr>TargetInfo.h<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>APValue.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/APValue.h?rev=<wbr>289787&r1=289786&r2=289787&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>APValue.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>APValue.h Thu Dec 15 02:09:08 2016<br>
@@ -135,14 +135,15 @@ public:<br>
}<br>
APValue(const APValue &RHS);<br>
APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }<br>
- APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)<br>
+ APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex,<br>
+ bool IsNullPtr = false)<br></blockquote><div><br></div><div>Rather than tracking nullness with a separate flag, it would fit into the model better to track null pointer plus offset and all-zeroes pointer plus offset as having two different kinds of LValueBase in the address spaces where they're different.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
: Kind(Uninitialized) {<br>
- MakeLValue(); setLValue(B, O, N, CallIndex);<br>
+ MakeLValue(); setLValue(B, O, N, CallIndex, IsNullPtr);<br>
}<br>
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,<br>
- bool OnePastTheEnd, unsigned CallIndex)<br>
+ bool OnePastTheEnd, unsigned CallIndex, bool IsNullPtr = false)<br>
: Kind(Uninitialized) {<br>
- MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);<br>
+ MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex, IsNullPtr);<br>
}<br>
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {<br>
MakeArray(InitElts, Size);<br>
@@ -254,6 +255,7 @@ public:<br>
bool hasLValuePath() const;<br>
ArrayRef<LValuePathEntry> getLValuePath() const;<br>
unsigned getLValueCallIndex() const;<br>
+ bool isNullPointer() const;<br>
<br>
APValue &getVectorElt(unsigned I) {<br>
assert(isVector() && "Invalid accessor");<br>
@@ -374,10 +376,10 @@ public:<br>
((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I);<br>
}<br>
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,<br>
- unsigned CallIndex);<br>
+ unsigned CallIndex, bool IsNullPtr);<br>
void setLValue(LValueBase B, const CharUnits &O,<br>
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,<br>
- unsigned CallIndex);<br>
+ unsigned CallIndex, bool IsNullPtr);<br>
void setUnion(const FieldDecl *Field, const APValue &Value) {<br>
assert(isUnion() && "Invalid accessor");<br>
((UnionData*)(char*)Data.<wbr>buffer)->Field = Field;<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>ASTContext.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/ASTContext.h?rev=<wbr>289787&r1=289786&r2=289787&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>ASTContext.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>ASTContext.h Thu Dec 15 02:09:08 2016<br>
@@ -2299,6 +2299,10 @@ public:<br>
return (*AddrSpaceMap)[AS - LangAS::Offset];<br>
}<br>
<br>
+ /// Get target-dependent integer value for null pointer which is used for<br>
+ /// constant folding.<br>
+ uint64_t getTargetNullPointerValue(<wbr>QualType QT) const;<br>
+<br>
bool addressSpaceMapManglingFor(<wbr>unsigned AS) const {<br>
return AddrSpaceMapMangling ||<br>
AS < LangAS::Offset ||<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>TargetInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/TargetInfo.h?rev=<wbr>289787&r1=289786&r2=289787&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>TargetInfo.h (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>TargetInfo.h Thu Dec 15 02:09:08 2016<br>
@@ -42,6 +42,7 @@ class DiagnosticsEngine;<br>
class LangOptions;<br>
class CodeGenOptions;<br>
class MacroBuilder;<br>
+class QualType;<br>
class SourceLocation;<br>
class SourceManager;<br>
<br>
@@ -300,6 +301,12 @@ public:<br>
return PointerWidth;<br>
}<br>
<br>
+ /// \brief Get integer value for null pointer.<br>
+ /// \param AddrSpace address space of pointee in source language.<br>
+ virtual uint64_t getNullPointerValue(unsigned AddrSpace) const {<br>
+ return 0;<br>
+ }<br>
+<br>
/// \brief Return the size of '_Bool' and C++ 'bool' for this target, in bits.<br>
unsigned getBoolWidth() const { return BoolWidth; }<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/APValue.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>APValue.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/APValue.cpp (original)<br>
+++ cfe/trunk/lib/AST/APValue.cpp Thu Dec 15 02:09:08 2016<br>
@@ -27,6 +27,7 @@ namespace {<br>
CharUnits Offset;<br>
unsigned PathLength;<br>
unsigned CallIndex;<br>
+ bool IsNullPtr;<br>
};<br>
}<br>
<br>
@@ -149,10 +150,11 @@ APValue::APValue(const APValue &RHS) : K<br>
MakeLValue();<br>
if (RHS.hasLValuePath())<br>
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),<br>
- RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex());<br>
+ RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(),<br>
+ RHS.isNullPointer());<br>
else<br>
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),<br>
- RHS.getLValueCallIndex());<br>
+ RHS.getLValueCallIndex(), RHS.isNullPointer());<br>
break;<br>
case Array:<br>
MakeArray(RHS.<wbr>getArrayInitializedElts(), RHS.getArraySize());<br>
@@ -579,8 +581,13 @@ unsigned APValue::getLValueCallIndex() c<br>
return ((const LV*)(const char*)Data.buffer)->CallIndex;<br>
}<br>
<br>
+bool APValue::isNullPointer() const {<br>
+ assert(isLValue() && "Invalid usage");<br>
+ return ((const LV*)(const char*)Data.buffer)->IsNullPtr;<br>
+}<br>
+<br>
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,<br>
- unsigned CallIndex) {<br>
+ unsigned CallIndex, bool IsNullPtr) {<br>
assert(isLValue() && "Invalid accessor");<br>
LV &LVal = *((LV*)(char*)Data.buffer);<br>
LVal.BaseAndIsOnePastTheEnd.<wbr>setPointer(B);<br>
@@ -588,11 +595,12 @@ void APValue::setLValue(LValueBase B, co<br>
LVal.Offset = O;<br>
LVal.CallIndex = CallIndex;<br>
LVal.resizePath((unsigned)-1);<br>
+ LVal.IsNullPtr = IsNullPtr;<br>
}<br>
<br>
void APValue::setLValue(LValueBase B, const CharUnits &O,<br>
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,<br>
- unsigned CallIndex) {<br>
+ unsigned CallIndex, bool IsNullPtr) {<br>
assert(isLValue() && "Invalid accessor");<br>
LV &LVal = *((LV*)(char*)Data.buffer);<br>
LVal.BaseAndIsOnePastTheEnd.<wbr>setPointer(B);<br>
@@ -601,6 +609,7 @@ void APValue::setLValue(LValueBase B, co<br>
LVal.CallIndex = CallIndex;<br>
LVal.resizePath(Path.size());<br>
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));<br>
+ LVal.IsNullPtr = IsNullPtr;<br>
}<br>
<br>
const ValueDecl *APValue::<wbr>getMemberPointerDecl() const {<br>
<br>
Modified: cfe/trunk/lib/AST/ASTContext.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ASTContext.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/ASTContext.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTContext.<wbr>cpp Thu Dec 15 02:09:08 2016<br>
@@ -9434,6 +9434,16 @@ ASTContext::<wbr>ObjCMethodsAreEqual(const Ob<br>
<br>
}<br>
<br>
+uint64_t ASTContext::<wbr>getTargetNullPointerValue(<wbr>QualType QT) const {<br>
+ unsigned AS;<br>
+ if (QT-><wbr>getUnqualifiedDesugaredType()-<wbr>>isNullPtrType())<br>
+ AS = 0;<br>
+ else<br>
+ AS = QT->getPointeeType().<wbr>getAddressSpace();<br>
+<br>
+ return getTargetInfo().<wbr>getNullPointerValue(AS);<br>
+}<br>
+<br>
// Explicitly instantiate this in case a Redeclarable<T> is used from a TU that<br>
// doesn't include ASTContext.h<br>
template<br>
<br>
Modified: cfe/trunk/lib/AST/<wbr>ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ExprConstant.cpp?rev=289787&<wbr>r1=289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/<wbr>ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/<wbr>ExprConstant.cpp Thu Dec 15 02:09:08 2016<br>
@@ -1088,6 +1088,7 @@ namespace {<br>
unsigned InvalidBase : 1;<br>
unsigned CallIndex : 31;<br>
SubobjectDesignator Designator;<br>
+ bool IsNullPtr;<br>
<br>
const APValue::LValueBase getLValueBase() const { return Base; }<br>
CharUnits &getLValueOffset() { return Offset; }<br>
@@ -1095,13 +1096,15 @@ namespace {<br>
unsigned getLValueCallIndex() const { return CallIndex; }<br>
SubobjectDesignator &getLValueDesignator() { return Designator; }<br>
const SubobjectDesignator &getLValueDesignator() const { return Designator;}<br>
+ bool isNullPointer() const { return IsNullPtr;}<br>
<br>
void moveInto(APValue &V) const {<br>
if (Designator.Invalid)<br>
- V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex);<br>
+ V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex,<br>
+ IsNullPtr);<br>
else<br>
V = APValue(Base, Offset, Designator.Entries,<br>
- Designator.IsOnePastTheEnd, CallIndex);<br>
+ Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);<br>
}<br>
void setFrom(ASTContext &Ctx, const APValue &V) {<br>
assert(V.isLValue());<br>
@@ -1110,14 +1113,17 @@ namespace {<br>
InvalidBase = false;<br>
CallIndex = V.getLValueCallIndex();<br>
Designator = SubobjectDesignator(Ctx, V);<br>
+ IsNullPtr = V.isNullPointer();<br>
}<br>
<br>
- void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {<br>
+ void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false,<br>
+ bool IsNullPtr_ = false, uint64_t Offset_ = 0) {<br>
Base = B;<br>
- Offset = CharUnits::Zero();<br>
+ Offset = CharUnits::fromQuantity(<wbr>Offset_);<br>
InvalidBase = BInvalid;<br>
CallIndex = I;<br>
Designator = SubobjectDesignator(getType(B)<wbr>);<br>
+ IsNullPtr = IsNullPtr_;<br>
}<br>
<br>
void setInvalid(APValue::LValueBase B, unsigned I = 0) {<br>
@@ -1130,7 +1136,7 @@ namespace {<br>
CheckSubobjectKind CSK) {<br>
if (Designator.Invalid)<br>
return false;<br>
- if (!Base) {<br>
+ if (IsNullPtr) {<br>
Info.CCEDiag(E, diag::note_constexpr_null_<wbr>subobject)<br>
<< CSK;<br>
Designator.setInvalid();<br>
@@ -1159,9 +1165,22 @@ namespace {<br>
if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))<br>
Designator.<wbr>addComplexUnchecked(EltTy, Imag);<br>
}<br>
- void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {<br>
- if (N && checkNullPointer(Info, E, CSK_ArrayIndex))<br>
- Designator.adjustIndex(Info, E, N);<br>
+ void clearIsNullPointer() {<br>
+ IsNullPtr = false;<br>
+ }<br>
+ void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, uint64_t Index,<br>
+ CharUnits ElementSize) {<br>
+ // Compute the new offset in the appropriate width.<br>
+ Offset += Index * ElementSize;<br>
+ if (Index && checkNullPointer(Info, E, CSK_ArrayIndex))<br>
+ Designator.adjustIndex(Info, E, Index);<br>
+ if (Index)<br>
+ clearIsNullPointer();<br></blockquote><div><br></div><div>Is this really right? This means that "(char*)0 + 1 - 1" gets the all-zeroes representation rather than the null pointer representation, and that "((char*)0 + 1) - (char*)0" will not necessarily be 1.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+ }<br>
+ void adjustOffset(CharUnits N) {<br>
+ Offset += N;<br>
+ if (N.getQuantity())<br>
+ clearIsNullPointer();<br>
}<br>
};<br>
<br>
@@ -2036,7 +2055,7 @@ static bool HandleLValueMember(EvalInfo<br>
}<br>
<br>
unsigned I = FD->getFieldIndex();<br>
- LVal.Offset += Info.Ctx.toCharUnitsFromBits(<wbr>RL->getFieldOffset(I));<br>
+ LVal.adjustOffset(Info.Ctx.<wbr>toCharUnitsFromBits(RL-><wbr>getFieldOffset(I)));<br>
LVal.addDecl(Info, E, FD);<br>
return true;<br>
}<br>
@@ -2090,9 +2109,7 @@ static bool HandleLValueArrayAdjustment(<br>
if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee))<br>
return false;<br>
<br>
- // Compute the new offset in the appropriate width.<br>
- LVal.Offset += Adjustment * SizeOfPointee;<br>
- LVal.adjustIndex(Info, E, Adjustment);<br>
+ LVal.adjustOffsetAndIndex(<wbr>Info, E, Adjustment, SizeOfPointee);<br>
return true;<br>
}<br>
<br>
@@ -5081,7 +5098,9 @@ public:<br>
return true;<br>
}<br>
bool ZeroInitialization(const Expr *E) {<br>
- return Success((Expr*)nullptr);<br>
+ auto Offset = Info.Ctx.<wbr>getTargetNullPointerValue(E-><wbr>getType());<br>
+ Result.set((Expr*)nullptr, 0, false, true, Offset);<br>
+ return true;<br>
}<br>
<br>
bool VisitBinaryOperator(const BinaryOperator *E);<br>
@@ -5180,6 +5199,8 @@ bool PointerExprEvaluator::<wbr>VisitCastExpr<br>
else<br>
CCEDiag(E, diag::note_constexpr_invalid_<wbr>cast) << 2;<br>
}<br>
+ if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)<br>
+ ZeroInitialization(E);<br>
return true;<br>
<br>
case CK_DerivedToBase:<br>
@@ -5221,6 +5242,7 @@ bool PointerExprEvaluator::<wbr>VisitCastExpr<br>
Result.Offset = CharUnits::fromQuantity(N);<br>
Result.CallIndex = 0;<br>
Result.Designator.setInvalid()<wbr>;<br>
+ Result.IsNullPtr = false;<br>
return true;<br>
} else {<br>
// Cast is of an lvalue, no need to change value.<br>
@@ -8395,8 +8417,13 @@ bool IntExprEvaluator::<wbr>VisitCastExpr(con<br>
return true;<br>
}<br>
<br>
- APSInt AsInt = Info.Ctx.MakeIntValue(LV.<wbr>getLValueOffset().getQuantity(<wbr>),<br>
- SrcType);<br>
+ uint64_t V;<br>
+ if (LV.isNullPointer())<br>
+ V = Info.Ctx.<wbr>getTargetNullPointerValue(<wbr>SrcType);<br>
+ else<br>
+ V = LV.getLValueOffset().<wbr>getQuantity();<br>
+<br>
+ APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType);<br>
return Success(HandleIntToIntCast(<wbr>Info, E, DestType, SrcType, AsInt), E);<br>
}<br>
<br>
<br>
Modified: cfe/trunk/lib/Basic/Targets.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Basic/<wbr>Targets.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Basic/Targets.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Basic/Targets.<wbr>cpp Thu Dec 15 02:09:08 2016<br>
@@ -2245,6 +2245,13 @@ public:<br>
return CCCR_OK;<br>
}<br>
}<br>
+<br>
+ // In amdgcn target the null pointer in global, constant, and generic<br>
+ // address space has value 0 but in private and local address space has<br>
+ // value ~0.<br>
+ uint64_t getNullPointerValue(unsigned AS) const override {<br>
+ return AS != LangAS::opencl_local && AS != 0 ? 0 : ~0;<br>
+ }<br>
};<br>
<br>
const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[<wbr>] = {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGDecl.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp Thu Dec 15 02:09:08 2016<br>
@@ -708,7 +708,7 @@ void CodeGenFunction::<wbr>EmitScalarInit(con<br>
}<br>
<br>
auto ty = cast<llvm::PointerType>(<wbr>tempLV.getAddress().<wbr>getElementType());<br>
- llvm::Value *zero = llvm::ConstantPointerNull::<wbr>get(ty);<br>
+ llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType());<br>
<br>
// If __weak, we want to use a barrier under certain conditions.<br>
if (lifetime == Qualifiers::OCL_Weak)<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CGExprAgg.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGExprAgg.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CGExprAgg.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CGExprAgg.cpp Thu Dec 15 02:09:08 2016<br>
@@ -1052,7 +1052,8 @@ static bool isSimpleZero(const Expr *E,<br>
return true;<br>
// (int*)0 - Null pointer expressions.<br>
if (const CastExpr *ICE = dyn_cast<CastExpr>(E))<br>
- return ICE->getCastKind() == CK_NullToPointer;<br>
+ return ICE->getCastKind() == CK_NullToPointer &&<br>
+ CGF.getTypes().<wbr>isPointerZeroInitializable(E-><wbr>getType());<br>
// '\0'<br>
if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E))<br>
return CL->getValue() == 0;<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CGExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGExprConstant.cpp?rev=289787&<wbr>r1=289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CGExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CGExprConstant.cpp Thu Dec 15 02:09:08 2016<br>
@@ -16,6 +16,7 @@<br>
#include "CGObjCRuntime.h"<br>
#include "CGRecordLayout.h"<br>
#include "CodeGenModule.h"<br>
+#include "TargetInfo.h"<br>
#include "clang/AST/APValue.h"<br>
#include "clang/AST/ASTContext.h"<br>
#include "clang/AST/RecordLayout.h"<br>
@@ -1262,6 +1263,10 @@ llvm::Constant *CodeGenModule::EmitConst<br>
return C;<br>
}<br>
<br>
+llvm::Constant *CodeGenModule::<wbr>getNullPointer(llvm::<wbr>PointerType *T, QualType QT) {<br>
+ return getTargetCodeGenInfo().<wbr>getNullPointer(*this, T, QT);<br>
+}<br>
+<br>
llvm::Constant *CodeGenModule::<wbr>EmitConstantValue(const APValue &Value,<br>
QualType DestType,<br>
CodeGenFunction *CGF) {<br>
@@ -1293,6 +1298,7 @@ llvm::Constant *CodeGenModule::EmitConst<br>
llvm::ConstantInt::get(<wbr>Int64Ty, Value.getLValueOffset().<wbr>getQuantity());<br>
<br>
llvm::Constant *C = nullptr;<br>
+<br>
if (APValue::LValueBase LVBase = Value.getLValueBase()) {<br>
// An array can be represented as an lvalue referring to the base.<br>
if (isa<llvm::ArrayType>(DestTy)) {<br>
@@ -1323,7 +1329,9 @@ llvm::Constant *CodeGenModule::EmitConst<br>
<br>
// Convert to the appropriate type; this could be an lvalue for<br>
// an integer.<br>
- if (isa<llvm::PointerType>(<wbr>DestTy)) {<br>
+ if (auto PT = dyn_cast<llvm::PointerType>(<wbr>DestTy)) {<br>
+ if (Value.isNullPointer())<br>
+ return getNullPointer(PT, DestType);<br>
// Convert the integer to a pointer-sized integer before converting it<br>
// to a pointer.<br>
C = llvm::ConstantExpr::<wbr>getIntegerCast(<br>
@@ -1510,7 +1518,7 @@ static llvm::Constant *EmitNullConstantF<br>
const CXXRecordDecl *base);<br>
<br>
static llvm::Constant *EmitNullConstant(<wbr>CodeGenModule &CGM,<br>
- const CXXRecordDecl *record,<br>
+ const RecordDecl *record,<br>
bool asCompleteObject) {<br>
const CGRecordLayout &layout = CGM.getTypes().<wbr>getCGRecordLayout(record);<br>
llvm::StructType *structure =<br>
@@ -1520,25 +1528,29 @@ static llvm::Constant *EmitNullConstant(<br>
unsigned numElements = structure->getNumElements();<br>
std::vector<llvm::Constant *> elements(numElements);<br>
<br>
+ auto CXXR = dyn_cast<CXXRecordDecl>(<wbr>record);<br>
// Fill in all the bases.<br>
- for (const auto &I : record->bases()) {<br>
- if (I.isVirtual()) {<br>
- // Ignore virtual bases; if we're laying out for a complete<br>
- // object, we'll lay these out later.<br>
- continue;<br>
- }<br>
+ if (CXXR) {<br>
+ for (const auto &I : CXXR->bases()) {<br>
+ if (I.isVirtual()) {<br>
+ // Ignore virtual bases; if we're laying out for a complete<br>
+ // object, we'll lay these out later.<br>
+ continue;<br>
+ }<br>
<br>
- const CXXRecordDecl *base =<br>
- cast<CXXRecordDecl>(I.getType(<wbr>)->castAs<RecordType>()-><wbr>getDecl());<br>
+ const CXXRecordDecl *base =<br>
+ cast<CXXRecordDecl>(I.getType(<wbr>)->castAs<RecordType>()-><wbr>getDecl());<br>
<br>
- // Ignore empty bases.<br>
- if (base->isEmpty() ||<br>
- CGM.getContext().<wbr>getASTRecordLayout(base).<wbr>getNonVirtualSize().isZero())<br>
- continue;<br>
-<br>
- unsigned fieldIndex = layout.<wbr>getNonVirtualBaseLLVMFieldNo(<wbr>base);<br>
- llvm::Type *baseType = structure->getElementType(<wbr>fieldIndex);<br>
- elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);<br>
+ // Ignore empty bases.<br>
+ if (base->isEmpty() ||<br>
+ CGM.getContext().<wbr>getASTRecordLayout(base).<wbr>getNonVirtualSize()<br>
+ .isZero())<br>
+ continue;<br>
+<br>
+ unsigned fieldIndex = layout.<wbr>getNonVirtualBaseLLVMFieldNo(<wbr>base);<br>
+ llvm::Type *baseType = structure->getElementType(<wbr>fieldIndex);<br>
+ elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);<br>
+ }<br>
}<br>
<br>
// Fill in all the fields.<br>
@@ -1562,8 +1574,8 @@ static llvm::Constant *EmitNullConstant(<br>
}<br>
<br>
// Fill in the virtual bases, if we're working with the complete object.<br>
- if (asCompleteObject) {<br>
- for (const auto &I : record->vbases()) {<br>
+ if (CXXR && asCompleteObject) {<br>
+ for (const auto &I : CXXR->vbases()) {<br>
const CXXRecordDecl *base =<br>
cast<CXXRecordDecl>(I.getType(<wbr>)->castAs<RecordType>()-><wbr>getDecl());<br>
<br>
@@ -1605,6 +1617,10 @@ static llvm::Constant *EmitNullConstantF<br>
}<br>
<br>
llvm::Constant *CodeGenModule::<wbr>EmitNullConstant(QualType T) {<br>
+ if (T->getAs<PointerType>())<br>
+ return getNullPointer(<br>
+ cast<llvm::PointerType>(<wbr>getTypes().ConvertTypeForMem(<wbr>T)), T);<br>
+<br>
if (getTypes().<wbr>isZeroInitializable(T))<br>
return llvm::Constant::getNullValue(<wbr>getTypes().ConvertTypeForMem(<wbr>T));<br>
<br>
@@ -1620,10 +1636,8 @@ llvm::Constant *CodeGenModule::EmitNullC<br>
return llvm::ConstantArray::get(ATy, Array);<br>
}<br>
<br>
- if (const RecordType *RT = T->getAs<RecordType>()) {<br>
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT-><wbr>getDecl());<br>
- return ::EmitNullConstant(*this, RD, /*complete object*/ true);<br>
- }<br>
+ if (const RecordType *RT = T->getAs<RecordType>())<br>
+ return ::EmitNullConstant(*this, RT->getDecl(), /*complete object*/ true);<br>
<br>
assert(T-><wbr>isMemberDataPointerType() &&<br>
"Should only see pointers to data members here!");<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CGExprScalar.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGExprScalar.cpp?rev=289787&<wbr>r1=289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CGExprScalar.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CGExprScalar.cpp Thu Dec 15 02:09:08 2016<br>
@@ -19,6 +19,7 @@<br>
#include "TargetInfo.h"<br>
#include "clang/AST/ASTContext.h"<br>
#include "clang/AST/DeclObjC.h"<br>
+#include "clang/AST/Expr.h"<br>
#include "clang/AST/RecordLayout.h"<br>
#include "clang/AST/StmtVisitor.h"<br>
#include "clang/Basic/TargetInfo.h"<br>
@@ -171,9 +172,9 @@ public:<br>
}<br>
<br>
/// EmitPointerToBoolConversion - Perform a pointer to boolean conversion.<br>
- Value *EmitPointerToBoolConversion(<wbr>Value *V) {<br>
- Value *Zero = llvm::ConstantPointerNull::<wbr>get(<br>
- cast<llvm::PointerType>(V-><wbr>getType()));<br>
+ Value *EmitPointerToBoolConversion(<wbr>Value *V, QualType QT) {<br>
+ Value *Zero = CGF.CGM.getNullPointer(cast<<wbr>llvm::PointerType>(V->getType(<wbr>)), QT);<br>
+<br>
return Builder.CreateICmpNE(V, Zero, "tobool");<br>
}<br>
<br>
@@ -597,7 +598,7 @@ Value *ScalarExprEmitter::<wbr>EmitConversion<br>
return EmitIntToBoolConversion(Src);<br>
<br>
assert(isa<llvm::PointerType>(<wbr>Src->getType()));<br>
- return EmitPointerToBoolConversion(<wbr>Src);<br>
+ return EmitPointerToBoolConversion(<wbr>Src, SrcType);<br>
}<br>
<br>
void ScalarExprEmitter::<wbr>EmitFloatConversionCheck(<br>
@@ -1400,11 +1401,23 @@ Value *ScalarExprEmitter::<wbr>VisitCastExpr(<br>
return Builder.CreateBitCast(Src, DstTy);<br>
}<br>
case CK_AddressSpaceConversion: {<br>
- Value *Src = Visit(const_cast<Expr*>(E));<br>
+ Expr::EvalResult Result;<br>
+ if (E->EvaluateAsRValue(Result, CGF.getContext()) &&<br>
+ Result.Val.isNullPointer()) {<br>
+ // If E has side effect, it is emitted even if its final result is a<br>
+ // null pointer. In that case, a DCE pass should be able to<br>
+ // eliminate the useless instructions emitted during translating E.<br>
+ if (Result.HasSideEffects)<br>
+ Visit(E);<br>
+ return CGF.CGM.getNullPointer(cast<<wbr>llvm::PointerType>(<br>
+ ConvertType(DestTy)), DestTy);<br>
+ }<br>
// Since target may map different address spaces in AST to the same address<br>
// space, an address space conversion may end up as a bitcast.<br>
- return Builder.<wbr>CreatePointerBitCastOrAddrSpac<wbr>eCast(Src,<br>
- ConvertType(DestTy));<br>
+ auto *Src = Visit(E);<br>
+ return CGF.CGM.getTargetCodeGenInfo()<wbr>.performAddrSpaceCast(CGF, Src,<br>
+ E->getType(),<br>
+ DestTy);<br>
}<br>
case CK_AtomicToNonAtomic:<br>
case CK_NonAtomicToAtomic:<br>
@@ -1459,8 +1472,8 @@ Value *ScalarExprEmitter::<wbr>VisitCastExpr(<br>
if (MustVisitNullValue(E))<br>
(void) Visit(E);<br>
<br>
- return llvm::ConstantPointerNull::<wbr>get(<br>
- cast<llvm::PointerType>(<wbr>ConvertType(DestTy)));<br>
+ return CGF.CGM.getNullPointer(cast<<wbr>llvm::PointerType>(<wbr>ConvertType(DestTy)),<br>
+ DestTy);<br>
<br>
case CK_NullToMemberPointer: {<br>
if (MustVisitNullValue(E))<br>
@@ -1553,7 +1566,7 @@ Value *ScalarExprEmitter::<wbr>VisitCastExpr(<br>
case CK_IntegralToBoolean:<br>
return EmitIntToBoolConversion(Visit(<wbr>E));<br>
case CK_PointerToBoolean:<br>
- return EmitPointerToBoolConversion(<wbr>Visit(E));<br>
+ return EmitPointerToBoolConversion(<wbr>Visit(E), E->getType());<br>
case CK_FloatingToBoolean:<br>
return EmitFloatToBoolConversion(<wbr>Visit(E));<br>
case CK_MemberPointerToBoolean: {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp?rev=289787&<wbr>r1=289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp Thu Dec 15 02:09:08 2016<br>
@@ -2663,9 +2663,16 @@ void CodeGenModule::<wbr>EmitGlobalVarDefinit<br>
else<br>
GV->setDLLStorageClass(llvm::<wbr>GlobalVariable::<wbr>DefaultStorageClass);<br>
<br>
- if (Linkage == llvm::GlobalVariable::<wbr>CommonLinkage)<br>
+ if (Linkage == llvm::GlobalVariable::<wbr>CommonLinkage) {<br>
// common vars aren't constant even if declared const.<br>
GV->setConstant(false);<br>
+ // Tentative definition of global variables may be initialized with<br>
+ // non-zero null pointers. In this case they should have weak linkage<br>
+ // since common linkage must have zero initializer and must not have<br>
+ // explicit section therefore cannot have non-zero initial value.<br>
+ if (!GV->getInitializer()-><wbr>isNullValue())<br>
+ GV->setLinkage(llvm::<wbr>GlobalVariable::<wbr>WeakAnyLinkage);<br>
+ }<br>
<br>
setNonAliasAttributes(D, GV);<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.h?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.h (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.h Thu Dec 15 02:09:08 2016<br>
@@ -1156,6 +1156,11 @@ public:<br>
llvm::Value *<br>
createOpenCLIntToSamplerConver<wbr>sion(const Expr *E, CodeGenFunction &CGF);<br>
<br>
+ /// Get target specific null pointer.<br>
+ /// \param T is the LLVM type of the null pointer.<br>
+ /// \param QT is the clang QualType of the null pointer.<br>
+ llvm::Constant *getNullPointer(llvm::<wbr>PointerType *T, QualType QT);<br>
+<br>
private:<br>
llvm::Constant *<br>
GetOrCreateLLVMFunction(<wbr>StringRef MangledName, llvm::Type *Ty, GlobalDecl D,<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.cpp?rev=289787&<wbr>r1=289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.cpp Thu Dec 15 02:09:08 2016<br>
@@ -736,10 +736,14 @@ CodeGenTypes::<wbr>getCGRecordLayout(const Re<br>
return *Layout;<br>
}<br>
<br>
+bool CodeGenTypes::<wbr>isPointerZeroInitializable(<wbr>QualType T) {<br>
+ assert (T->isAnyPointerType() && "Invalid type");<br>
+ return isZeroInitializable(T);<br>
+}<br>
+<br>
bool CodeGenTypes::<wbr>isZeroInitializable(QualType T) {<br>
- // No need to check for member pointers when not compiling C++.<br>
- if (!Context.getLangOpts().<wbr>CPlusPlus)<br>
- return true;<br>
+ if (T->getAs<PointerType>())<br>
+ return Context.<wbr>getTargetNullPointerValue(T) == 0;<br>
<br>
if (const auto *AT = Context.getAsArrayType(T)) {<br>
if (isa<IncompleteArrayType>(AT))<br>
@@ -753,7 +757,7 @@ bool CodeGenTypes::<wbr>isZeroInitializable(Q<br>
// Records are non-zero-initializable if they contain any<br>
// non-zero-initializable subobjects.<br>
if (const RecordType *RT = T->getAs<RecordType>()) {<br>
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT-><wbr>getDecl());<br>
+ auto RD = cast<RecordDecl>(RT->getDecl()<wbr>);<br>
return isZeroInitializable(RD);<br>
}<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.h?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.h (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CodeGenTypes.h Thu Dec 15 02:09:08 2016<br>
@@ -352,6 +352,10 @@ public: // These are internal details o<br>
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.<br>
bool isZeroInitializable(QualType T);<br>
<br>
+ /// Check if the pointer type can be zero-initialized (in the C++ sense)<br>
+ /// with an LLVM zeroinitializer.<br>
+ bool isPointerZeroInitializable(<wbr>QualType T);<br>
+<br>
/// IsZeroInitializable - Return whether a record type can be<br>
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.<br>
bool isZeroInitializable(const RecordDecl *RD);<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>TargetInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>TargetInfo.cpp?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>TargetInfo.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>TargetInfo.cpp Thu Dec 15 02:09:08 2016<br>
@@ -401,6 +401,20 @@ unsigned TargetCodeGenInfo::<wbr>getOpenCLKer<br>
return llvm::CallingConv::C;<br>
}<br>
<br>
+llvm::Constant *TargetCodeGenInfo::<wbr>getNullPointer(const CodeGen::CodeGenModule &CGM,<br>
+ llvm::PointerType *T, QualType QT) const {<br>
+ return llvm::ConstantPointerNull::<wbr>get(T);<br>
+}<br>
+<br>
+llvm::Value *TargetCodeGenInfo::<wbr>performAddrSpaceCast(<br>
+ CodeGen::CodeGenFunction &CGF, llvm::Value *Src, QualType SrcTy,<br>
+ QualType DestTy) const {<br>
+ // Since target may map different address spaces in AST to the same address<br>
+ // space, an address space conversion may end up as a bitcast.<br>
+ return CGF.Builder.<wbr>CreatePointerBitCastOrAddrSpac<wbr>eCast(Src,<br>
+ CGF.ConvertType(DestTy));<br>
+}<br>
+<br>
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);<br>
<br>
/// isEmptyField - Return true iff a the field is "empty", that is it<br>
@@ -7075,8 +7089,10 @@ public:<br>
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,<br>
CodeGen::CodeGenModule &M) const override;<br>
unsigned getOpenCLKernelCallingConv() const override;<br>
-};<br>
<br>
+ llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,<br>
+ llvm::PointerType *T, QualType QT) const override;<br>
+};<br>
}<br>
<br>
static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM);<br>
@@ -7140,6 +7156,24 @@ unsigned AMDGPUTargetCodeGenInfo::<wbr>getOpe<br>
return llvm::CallingConv::AMDGPU_<wbr>KERNEL;<br>
}<br>
<br>
+// Currently LLVM assumes null pointers always have value 0,<br>
+// which results in incorrectly transformed IR. Therefore, instead of<br>
+// emitting null pointers in private and local address spaces, a null<br>
+// pointer in generic address space is emitted which is casted to a<br>
+// pointer in local or private address space.<br>
+llvm::Constant *AMDGPUTargetCodeGenInfo::<wbr>getNullPointer(<br>
+ const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT,<br>
+ QualType QT) const {<br>
+ if (CGM.getContext().<wbr>getTargetNullPointerValue(QT) == 0)<br>
+ return llvm::ConstantPointerNull::<wbr>get(PT);<br>
+<br>
+ auto &Ctx = CGM.getContext();<br>
+ auto NPT = llvm::PointerType::get(PT-><wbr>getElementType(),<br>
+ Ctx.getTargetAddressSpace(<wbr>LangAS::opencl_generic));<br>
+ return llvm::ConstantExpr::<wbr>getAddrSpaceCast(<br>
+ llvm::ConstantPointerNull::<wbr>get(NPT), PT);<br>
+}<br>
+<br>
//===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
// SPARC v8 ABI Implementation.<br>
// Based on the SPARC Compliance Definition version 2.4.1.<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>TargetInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.h?rev=289787&r1=289786&r2=289787&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>TargetInfo.h?rev=289787&r1=<wbr>289786&r2=289787&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>TargetInfo.h (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>TargetInfo.h Thu Dec 15 02:09:08 2016<br>
@@ -220,6 +220,22 @@ public:<br>
<br>
/// Get LLVM calling convention for OpenCL kernel.<br>
virtual unsigned getOpenCLKernelCallingConv() const;<br>
+<br>
+ /// Get target specific null pointer.<br>
+ /// \param T is the LLVM type of the null pointer.<br>
+ /// \param QT is the clang QualType of the null pointer.<br>
+ /// \return ConstantPointerNull with the given type \p T.<br>
+ /// Each target can override it to return its own desired constant value.<br>
+ virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,<br>
+ llvm::PointerType *T, QualType QT) const;<br>
+<br>
+ /// Perform address space cast of an expression of pointer type.<br>
+ /// \param V is the LLVM value to be casted to another address space.<br>
+ /// \param SrcTy is the QualType of \p V.<br>
+ /// \param DestTy is the destination QualType.<br>
+ virtual llvm::Value *performAddrSpaceCast(CodeGen:<wbr>:CodeGenFunction &CGF,<br>
+ llvm::Value *V, QualType SrcTy, QualType DestTy) const;<br>
+<br>
};<br>
<br>
} // namespace CodeGen<br>
<br>
Added: cfe/trunk/test/CodeGenOpenCL/<a href="http://amdgpu-nullptr.cl" rel="noreferrer" target="_blank">a<wbr>mdgpu-nullptr.cl</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenOpenCL/amdgpu-nullptr.cl?rev=289787&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>CodeGenOpenCL/amdgpu-nullptr.<wbr>cl?rev=289787&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CodeGenOpenCL/<a href="http://amdgpu-nullptr.cl" rel="noreferrer" target="_blank">a<wbr>mdgpu-nullptr.cl</a> (added)<br>
+++ cfe/trunk/test/CodeGenOpenCL/<a href="http://amdgpu-nullptr.cl" rel="noreferrer" target="_blank">a<wbr>mdgpu-nullptr.cl</a> Thu Dec 15 02:09:08 2016<br>
@@ -0,0 +1,534 @@<br>
+// RUN: %clang_cc1 %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck %s<br>
+// RUN: %clang_cc1 %s -O0 -cl-std=CL2.0 -include opencl-c.h -triple amdgcn -emit-llvm -o - | FileCheck --check-prefix=NOOPT %s<br>
+<br>
+typedef struct {<br>
+ private char *p1;<br>
+ local char *p2;<br>
+ constant char *p3;<br>
+ global char *p4;<br>
+ generic char *p5;<br>
+} StructTy1;<br>
+<br>
+typedef struct {<br>
+ constant char *p3;<br>
+ global char *p4;<br>
+ generic char *p5;<br>
+} StructTy2;<br>
+<br>
+// LLVM requests global variable with common linkage to be initialized with zeroinitializer, therefore use -fno-common<br>
+// to suppress common linkage for tentative definition.<br>
+<br>
+// Test 0 as initializer.<br>
+<br>
+// CHECK: @private_p = local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+private char *private_p = 0;<br>
+<br>
+// CHECK: @local_p = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4<br>
+local char *local_p = 0;<br>
+<br>
+// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4<br>
+global char *global_p = 0;<br>
+<br>
+// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4<br>
+constant char *constant_p = 0;<br>
+<br>
+// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4<br>
+generic char *generic_p = 0;<br>
+<br>
+// Test NULL as initializer.<br>
+<br>
+// CHECK: @private_p_NULL = local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+private char *private_p_NULL = NULL;<br>
+<br>
+// CHECK: @local_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4<br>
+local char *local_p_NULL = NULL;<br>
+<br>
+// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4<br>
+global char *global_p_NULL = NULL;<br>
+<br>
+// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4<br>
+constant char *constant_p_NULL = NULL;<br>
+<br>
+// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4<br>
+generic char *generic_p_NULL = NULL;<br>
+<br>
+// Test constant folding of null pointer.<br>
+// A null pointer should be folded to a null pointer in the target address space.<br>
+<br>
+// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 4<br>
+generic int *fold_generic = (global int*)(generic float*)(private char*)0;<br>
+<br>
+// CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16* addrspacecast (i16 addrspace(4)* null to i16*), align 4<br>
+private short *fold_priv = (private short*)(generic int*)(global void*)0;<br>
+<br>
+// CHECK: @fold_priv_arith = local_unnamed_addr addrspace(1) global i8* inttoptr (i32 9 to i8*), align 4<br>
+private char *fold_priv_arith = (private char*)0 + 10;<br>
+<br>
+// CHECK: @fold_int = local_unnamed_addr addrspace(1) global i32 13, align 4<br>
+int fold_int = (int)(private void*)(generic char*)(global int*)0 + 14;<br>
+<br>
+// CHECK: @fold_int2 = local_unnamed_addr addrspace(1) global i32 12, align 4<br>
+int fold_int2 = (int) ((private void*)0 + 13);<br>
+<br>
+// CHECK: @fold_int3 = local_unnamed_addr addrspace(1) global i32 -1, align 4<br>
+int fold_int3 = (int) ((private int*)0);<br>
+<br>
+// CHECK: @fold_int4 = local_unnamed_addr addrspace(1) global i32 7, align 4<br>
+int fold_int4 = (int) &((private int*)0)[2];<br>
+<br>
+// CHECK: @fold_int5 = local_unnamed_addr addrspace(1) global i32 3, align 4<br>
+int fold_int5 = (int) &((private StructTy1*)0)->p2;<br>
+<br>
+// Test static variable initialization.<br>
+<br>
+// NOOPT: @test_static_var.sp1 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+// NOOPT: @test_static_var.sp2 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+// NOOPT: @test_static_var.sp3 = internal addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+// NOOPT: @test_static_var.sp4 = internal addrspace(1) global i8* null, align 4<br>
+// NOOPT: @test_static_var.sp5 = internal addrspace(1) global i8* null, align 4<br>
+// NOOPT: @test_static_var.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4<br>
+// NOOPT: @test_static_var.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4<br>
+<br>
+void test_static_var(void) {<br>
+ static private char *sp1 = 0;<br>
+ static private char *sp2 = NULL;<br>
+ static private char *sp3;<br>
+ static private char *sp4 = (private char*)((void)0, 0);<br>
+ const int x = 0;<br>
+ static private char *sp5 = (private char*)x;<br>
+ static StructTy1 SS1;<br>
+ static StructTy2 SS2;<br>
+}<br>
+<br>
+// Test function-scope variable initialization.<br>
+// NOOPT-LABEL: test_func_scope_var<br>
+// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** %sp1, align 4<br>
+// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** %sp2, align 4<br>
+// NOOPT: store i8* null, i8** %sp3, align 4<br>
+// NOOPT: store i8* null, i8** %sp4, align 4<br>
+// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8*<br>
+// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false)<br>
+// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8*<br>
+// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 4, i1 false)<br>
+<br>
+void test_func_scope_var(void) {<br>
+ private char *sp1 = 0;<br>
+ private char *sp2 = NULL;<br>
+ private char *sp3 = (private char*)((void)0, 0);<br>
+ const int x = 0;<br>
+ private char *sp4 = (private char*)x;<br>
+ StructTy1 SS1 = {0, 0, 0, 0, 0};<br>
+ StructTy2 SS2 = {0, 0, 0};<br>
+}<br>
+<br>
+// Test default initialization of pointers.<br>
+<br>
+// Tentative definition of global variables with non-zero initializer<br>
+// cannot have common linkage since common linkage requires zero initialization<br>
+// and does not have explicit section.<br>
+<br>
+// CHECK: @p1 = weak local_unnamed_addr addrspace(1) global i8* addrspacecast (i8 addrspace(4)* null to i8*), align 4<br>
+private char *p1;<br>
+<br>
+// CHECK: @p2 = weak local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4<br>
+local char *p2;<br>
+<br>
+// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4<br>
+constant char *p3;<br>
+<br>
+// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4<br>
+global char *p4;<br>
+<br>
+// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4<br>
+generic char *p5;<br>
+<br>
+// Test default initialization of sturcture.<br>
+<br>
+// CHECK: @S1 = weak local_unnamed_addr addrspace(1) global %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4<br>
+StructTy1 S1;<br>
+<br>
+// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 4<br>
+StructTy2 S2;<br>
+<br>
+// Test default initialization of array.<br>
+// CHECK: @A1 = weak local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, %struct.StructTy1 { i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }], align 4<br>
+StructTy1 A1[2];<br>
+<br>
+// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 4<br>
+StructTy2 A2[2];<br>
+<br>
+// Test comparison with 0.<br>
+<br>
+// CHECK-LABEL: cmp_private<br>
+// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)<br>
+void cmp_private(private char* p) {<br>
+ if (p != 0)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_local<br>
+// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)<br>
+void cmp_local(local char* p) {<br>
+ if (p != 0)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_global<br>
+// CHECK: icmp eq i8 addrspace(1)* %p, null<br>
+void cmp_global(global char* p) {<br>
+ if (p != 0)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_constant<br>
+// CHECK: icmp eq i8 addrspace(2)* %p, null<br>
+char cmp_constant(constant char* p) {<br>
+ if (p != 0)<br>
+ return *p;<br>
+ else<br>
+ return 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_generic<br>
+// CHECK: icmp eq i8 addrspace(4)* %p, null<br>
+void cmp_generic(generic char* p) {<br>
+ if (p != 0)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// Test comparison with NULL.<br>
+<br>
+// CHECK-LABEL: cmp_NULL_private<br>
+// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)<br>
+void cmp_NULL_private(private char* p) {<br>
+ if (p != NULL)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_NULL_local<br>
+// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)<br>
+void cmp_NULL_local(local char* p) {<br>
+ if (p != NULL)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_NULL_global<br>
+// CHECK: icmp eq i8 addrspace(1)* %p, null<br>
+void cmp_NULL_global(global char* p) {<br>
+ if (p != NULL)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_NULL_constant<br>
+// CHECK: icmp eq i8 addrspace(2)* %p, null<br>
+char cmp_NULL_constant(constant char* p) {<br>
+ if (p != NULL)<br>
+ return *p;<br>
+ else<br>
+ return 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cmp_NULL_generic<br>
+// CHECK: icmp eq i8 addrspace(4)* %p, null<br>
+void cmp_NULL_generic(generic char* p) {<br>
+ if (p != NULL)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// Test storage 0 as null pointer.<br>
+// CHECK-LABEL: test_storage_null_pointer<br>
+// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8* addrspace(4)* %arg_private<br>
+// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local<br>
+// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)* %arg_global<br>
+// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)* %arg_constant<br>
+// CHECK: store i8 addrspace(4)* null, i8 addrspace(4)* addrspace(4)* %arg_generic<br>
+void test_storage_null_pointer(<wbr>private char** arg_private,<br>
+ local char** arg_local,<br>
+ global char** arg_global,<br>
+ constant char** arg_constant,<br>
+ generic char** arg_generic) {<br>
+ *arg_private = 0;<br>
+ *arg_local = 0;<br>
+ *arg_global = 0;<br>
+ *arg_constant = 0;<br>
+ *arg_generic = 0;<br>
+}<br>
+<br>
+// Test storage NULL as null pointer.<br>
+// CHECK-LABEL: test_storage_null_pointer_NULL<br>
+// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8* addrspace(4)* %arg_private<br>
+// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local<br>
+// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)* %arg_global<br>
+// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)* %arg_constant<br>
+// CHECK: store i8 addrspace(4)* null, i8 addrspace(4)* addrspace(4)* %arg_generic<br>
+void test_storage_null_pointer_<wbr>NULL(private char** arg_private,<br>
+ local char** arg_local,<br>
+ global char** arg_global,<br>
+ constant char** arg_constant,<br>
+ generic char** arg_generic) {<br>
+ *arg_private = NULL;<br>
+ *arg_local = NULL;<br>
+ *arg_global = NULL;<br>
+ *arg_constant = NULL;<br>
+ *arg_generic = NULL;<br>
+}<br>
+<br>
+// Test pass null pointer to function as argument.<br>
+void test_pass_null_pointer_arg_<wbr>calee(private char* arg_private,<br>
+ local char* arg_local,<br>
+ global char* arg_global,<br>
+ constant char* arg_constant,<br>
+ generic char* arg_generic);<br>
+<br>
+// CHECK-LABEL: test_pass_null_pointer_arg<br>
+// CHECK: call void @test_pass_null_pointer_arg_<wbr>calee(i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)<br>
+// CHECK: call void @test_pass_null_pointer_arg_<wbr>calee(i8* addrspacecast (i8 addrspace(4)* null to i8*), i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(1)* null, i8 addrspace(2)* null, i8 addrspace(4)* null)<br>
+void test_pass_null_pointer_arg(<wbr>void) {<br>
+ test_pass_null_pointer_arg_<wbr>calee(0, 0, 0, 0, 0);<br>
+ test_pass_null_pointer_arg_<wbr>calee(NULL, NULL, NULL, NULL, NULL);<br>
+}<br>
+<br>
+// Test cast null pointer to size_t.<br>
+void test_cast_null_pointer_to_<wbr>sizet_calee(size_t arg_private,<br>
+ size_t arg_local,<br>
+ size_t arg_global,<br>
+ size_t arg_constant,<br>
+ size_t arg_generic);<br>
+<br>
+// CHECK-LABEL: test_cast_null_pointer_to_<wbr>sizet<br>
+// CHECK: call void @test_cast_null_pointer_to_<wbr>sizet_calee(i64 ptrtoint (i8* addrspacecast (i8 addrspace(4)* null to i8*) to i64), i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)<br>
+// CHECK: call void @test_cast_null_pointer_to_<wbr>sizet_calee(i64 ptrtoint (i8* addrspacecast (i8 addrspace(4)* null to i8*) to i64), i64 ptrtoint (i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*) to i64), i64 0, i64 0, i64 0)<br>
+void test_cast_null_pointer_to_<wbr>sizet(void) {<br>
+ test_cast_null_pointer_to_<wbr>sizet_calee((size_t)((private char*)0),<br>
+ (size_t)((local char*)0),<br>
+ (size_t)((global char*)0),<br>
+ (size_t)((constant char*)0),<br>
+ (size_t)((generic char*)0));<br>
+ test_cast_null_pointer_to_<wbr>sizet_calee((size_t)((private char*)NULL),<br>
+ (size_t)((local char*)NULL),<br>
+ (size_t)((global char*)NULL),<br>
+ (size_t)((constant char*)0), // NULL cannot be casted to constant pointer since it is defined as a generic pointer<br>
+ (size_t)((generic char*)NULL));<br>
+}<br>
+<br>
+// Test comparision between null pointers.<br>
+#define TEST_EQ00(addr1, addr2) int test_eq00_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 == (addr2 char*)0; }<br>
+#define TEST_EQ0N(addr1, addr2) int test_eq0N_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 == (addr2 char*)NULL; }<br>
+#define TEST_EQN0(addr1, addr2) int test_eqN0_##addr1##_##addr2(<wbr>void) { return (addr1 char*)NULL == (addr2 char*)0; }<br>
+#define TEST_EQNN(addr1, addr2) int test_eqNN_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 == (addr2 char*)NULL; }<br>
+#define TEST_NE00(addr1, addr2) int test_ne00_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 != (addr2 char*)0; }<br>
+#define TEST_NE0N(addr1, addr2) int test_ne0N_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 != (addr2 char*)NULL; }<br>
+#define TEST_NEN0(addr1, addr2) int test_neN0_##addr1##_##addr2(<wbr>void) { return (addr1 char*)NULL != (addr2 char*)0; }<br>
+#define TEST_NENN(addr1, addr2) int test_neNN_##addr1##_##addr2(<wbr>void) { return (addr1 char*)0 != (addr2 char*)NULL; }<br>
+#define TEST(addr1, addr2) \<br>
+ TEST_EQ00(addr1, addr2) \<br>
+ TEST_EQ0N(addr1, addr2) \<br>
+ TEST_EQN0(addr1, addr2) \<br>
+ TEST_EQNN(addr1, addr2) \<br>
+ TEST_NE00(addr1, addr2) \<br>
+ TEST_NE0N(addr1, addr2) \<br>
+ TEST_NEN0(addr1, addr2) \<br>
+ TEST_NENN(addr1, addr2)<br>
+<br>
+// CHECK-LABEL: test_eq00_generic_private<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eq0N_generic_private<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqN0_generic_private<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqNN_generic_private<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_ne00_generic_private<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_ne0N_generic_private<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neN0_generic_private<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neNN_generic_private<br>
+// CHECK: ret i32 0<br>
+TEST(generic, private)<br>
+<br>
+// CHECK-LABEL: test_eq00_generic_local<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eq0N_generic_local<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqN0_generic_local<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqNN_generic_local<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_ne00_generic_local<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_ne0N_generic_local<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neN0_generic_local<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neNN_generic_local<br>
+// CHECK: ret i32 0<br>
+TEST(generic, local)<br>
+<br>
+// CHECK-LABEL: test_eq00_generic_global<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eq0N_generic_global<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqN0_generic_global<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqNN_generic_global<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_ne00_generic_global<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_ne0N_generic_global<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neN0_generic_global<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neNN_generic_global<br>
+// CHECK: ret i32 0<br>
+TEST(generic, global)<br>
+<br>
+// CHECK-LABEL: test_eq00_generic_generic<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eq0N_generic_generic<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqN0_generic_generic<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_eqNN_generic_generic<br>
+// CHECK: ret i32 1<br>
+// CHECK-LABEL: test_ne00_generic_generic<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_ne0N_generic_generic<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neN0_generic_generic<br>
+// CHECK: ret i32 0<br>
+// CHECK-LABEL: test_neNN_generic_generic<br>
+// CHECK: ret i32 0<br>
+TEST(generic, generic)<br>
+<br>
+// CHECK-LABEL: test_eq00_constant_constant<br>
+// CHECK: ret i32 1<br>
+TEST_EQ00(constant, constant)<br>
+<br>
+// Test cast to bool.<br>
+<br>
+// CHECK-LABEL: cast_bool_private<br>
+// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)<br>
+void cast_bool_private(private char* p) {<br>
+ if (p)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cast_bool_local<br>
+// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)<br>
+void cast_bool_local(local char* p) {<br>
+ if (p)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cast_bool_global<br>
+// CHECK: icmp eq i8 addrspace(1)* %p, null<br>
+void cast_bool_global(global char* p) {<br>
+ if (p)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cast_bool_constant<br>
+// CHECK: icmp eq i8 addrspace(2)* %p, null<br>
+char cast_bool_constant(constant char* p) {<br>
+ if (p)<br>
+ return *p;<br>
+ else<br>
+ return 0;<br>
+}<br>
+<br>
+// CHECK-LABEL: cast_bool_generic<br>
+// CHECK: icmp eq i8 addrspace(4)* %p, null<br>
+void cast_bool_generic(generic char* p) {<br>
+ if (p)<br>
+ *p = 0;<br>
+}<br>
+<br>
+// Test initialize a struct using memset.<br>
+// For large structures which is mostly zero, clang generats llvm.memset for<br>
+// the zero part and store for non-zero members.<br>
+typedef struct {<br>
+ long a, b, c, d;<br>
+ private char *p;<br>
+} StructTy3;<br>
+<br>
+// CHECK-LABEL: test_memset<br>
+// CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 32, i32 8, i1 false)<br>
+// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8** {{.*}}<br>
+StructTy3 test_memset(void) {<br>
+ StructTy3 S3 = {0, 0, 0, 0, 0};<br>
+ return S3;<br>
+}<br>
+<br>
+// Test casting literal 0 to pointer.<br>
+// A 0 literal casted to pointer should become a null pointer.<br>
+<br>
+// CHECK-LABEL: test_cast_0_to_ptr<br>
+// CHECK: ret i32* addrspacecast (i32 addrspace(4)* null to i32*)<br>
+private int* test_cast_0_to_ptr(void) {<br>
+ return (private int*)0;<br>
+}<br>
+<br>
+// Test casting non-literal integer with 0 value to pointer.<br>
+// A non-literal integer expression with 0 value is casted to a pointer with<br>
+// zero value.<br>
+<br>
+// CHECK-LABEL: test_cast_int_to_ptr1<br>
+// CHECK: ret i32* null<br>
+private int* test_cast_int_to_ptr1(void) {<br>
+ return (private int*)((void)0, 0);<br>
+}<br>
+<br>
+// CHECK-LABEL: test_cast_int_to_ptr2<br>
+// CHECK: ret i32* null<br>
+private int* test_cast_int_to_ptr2(void) {<br>
+ int x = 0;<br>
+ return (private int*)x;<br>
+}<br>
+<br>
+// Test logical operations.<br>
+// CHECK-LABEL: test_not_nullptr<br>
+// CHECK: ret i32 1<br>
+int test_not_nullptr(void) {<br>
+ return !(private char*)NULL;<br>
+}<br>
+<br>
+// CHECK-LABEL: test_and_nullptr<br>
+// CHECK: ret i32 0<br>
+int test_and_nullptr(int a) {<br>
+ return a && ((private char*)NULL);<br>
+}<br>
+<br>
+// CHECK-LABEL: test_not_ptr<br>
+// CHECK: %[[lnot:.*]] = icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)<br>
+// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32<br>
+// CHECK: ret i32 %[[lnot_ext]]<br>
+int test_not_ptr(private char* p) {<br>
+ return !p;<br>
+}<br>
+// CHECK-LABEL: test_and_ptr<br>
+// CHECK: %[[tobool:.*]] = icmp ne i8* %p1, addrspacecast (i8 addrspace(4)* null to i8*)<br>
+// CHECK: %[[tobool1:.*]] = icmp ne i8 addrspace(3)* %p2, addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*)<br>
+// CHECK: %[[res:.*]] = and i1 %[[tobool]], %[[tobool1]]<br>
+// CHECK: %[[land_ext:.*]] = zext i1 %[[res]] to i32<br>
+// CHECK: ret i32 %[[land_ext]]<br>
+int test_and_ptr(private char* p1, local char* p2) {<br>
+ return p1 && p2;<br>
+}<br>
+<br>
+// Test folding of null pointer in function scope.<br>
+// NOOPT-LABEL: test_fold<br>
+// NOOPT: call void @test_fold_callee<br>
+// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4<br>
+// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0<br>
+// NOOPT: call void @test_fold_callee<br>
+// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, sext (i32 ptrtoint (i32* addrspacecast (i32 addrspace(4)* null to i32*) to i32) to i64)<br>
+// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1<br>
+void test_fold_callee(void);<br>
+void test_fold(void) {<br>
+ global int* glob = (test_fold_callee(), (global int*)(generic char*)0);<br>
+ long x = glob - (global int*)(generic char*)0;<br>
+ x = x + (int)(test_fold_callee(), (private int*)(generic char*)(global short*)0);<br>
+ x = x - (int)((private int*)0 == (private int*)(generic char*)0);<br>
+}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>