r289787 - Re-commit r289252 and r289285, and fix PR31374
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 30 17:09:07 PST 2017
On 15 December 2016 at 00:09, Yaxun Liu via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: yaxunl
> Date: Thu Dec 15 02:09:08 2016
> New Revision: 289787
>
> URL: http://llvm.org/viewvc/llvm-project?rev=289787&view=rev
> Log:
> Re-commit r289252 and r289285, and fix PR31374
>
> Added:
> cfe/trunk/test/CodeGenOpenCL/amdgpu-nullptr.cl
> Modified:
> cfe/trunk/include/clang/AST/APValue.h
> cfe/trunk/include/clang/AST/ASTContext.h
> cfe/trunk/include/clang/Basic/TargetInfo.h
> cfe/trunk/lib/AST/APValue.cpp
> cfe/trunk/lib/AST/ASTContext.cpp
> cfe/trunk/lib/AST/ExprConstant.cpp
> cfe/trunk/lib/Basic/Targets.cpp
> cfe/trunk/lib/CodeGen/CGDecl.cpp
> cfe/trunk/lib/CodeGen/CGExprAgg.cpp
> cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> cfe/trunk/lib/CodeGen/CGExprScalar.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.h
> cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
> cfe/trunk/lib/CodeGen/CodeGenTypes.h
> cfe/trunk/lib/CodeGen/TargetInfo.cpp
> cfe/trunk/lib/CodeGen/TargetInfo.h
>
> Modified: cfe/trunk/include/clang/AST/APValue.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/AST/APValue.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/AST/APValue.h (original)
> +++ cfe/trunk/include/clang/AST/APValue.h Thu Dec 15 02:09:08 2016
> @@ -135,14 +135,15 @@ public:
> }
> 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)
>
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.
> : 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);
> @@ -254,6 +255,7 @@ public:
> bool hasLValuePath() const;
> ArrayRef<LValuePathEntry> getLValuePath() const;
> unsigned getLValueCallIndex() const;
> + bool isNullPointer() const;
>
> APValue &getVectorElt(unsigned I) {
> assert(isVector() && "Invalid accessor");
> @@ -374,10 +376,10 @@ public:
> ((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;
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/AST/ASTContext.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Thu Dec 15 02:09:08 2016
> @@ -2299,6 +2299,10 @@ public:
> 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 ||
>
> Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/
> clang/Basic/TargetInfo.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
> +++ cfe/trunk/include/clang/Basic/TargetInfo.h Thu Dec 15 02:09:08 2016
> @@ -42,6 +42,7 @@ class DiagnosticsEngine;
> class LangOptions;
> class CodeGenOptions;
> class MacroBuilder;
> +class QualType;
> class SourceLocation;
> class SourceManager;
>
> @@ -300,6 +301,12 @@ public:
> 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; }
>
>
> Modified: cfe/trunk/lib/AST/APValue.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/
> APValue.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/AST/APValue.cpp (original)
> +++ cfe/trunk/lib/AST/APValue.cpp Thu Dec 15 02:09:08 2016
> @@ -27,6 +27,7 @@ namespace {
> CharUnits Offset;
> unsigned PathLength;
> unsigned CallIndex;
> + bool IsNullPtr;
> };
> }
>
> @@ -149,10 +150,11 @@ APValue::APValue(const APValue &RHS) : K
> 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());
> @@ -579,8 +581,13 @@ unsigned APValue::getLValueCallIndex() c
> 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);
> @@ -588,11 +595,12 @@ void APValue::setLValue(LValueBase B, co
> 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);
> @@ -601,6 +609,7 @@ void APValue::setLValue(LValueBase B, co
> LVal.CallIndex = CallIndex;
> LVal.resizePath(Path.size());
> memcpy(LVal.getPath(), Path.data(), Path.size() *
> sizeof(LValuePathEntry));
> + LVal.IsNullPtr = IsNullPtr;
> }
>
> const ValueDecl *APValue::getMemberPointerDecl() const {
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/
> ASTContext.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Dec 15 02:09:08 2016
> @@ -9434,6 +9434,16 @@ ASTContext::ObjCMethodsAreEqual(const Ob
>
> }
>
> +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
>
> Modified: cfe/trunk/lib/AST/ExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/
> ExprConstant.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Dec 15 02:09:08 2016
> @@ -1088,6 +1088,7 @@ namespace {
> unsigned InvalidBase : 1;
> unsigned CallIndex : 31;
> SubobjectDesignator Designator;
> + bool IsNullPtr;
>
> const APValue::LValueBase getLValueBase() const { return Base; }
> CharUnits &getLValueOffset() { return Offset; }
> @@ -1095,13 +1096,15 @@ namespace {
> 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());
> @@ -1110,14 +1113,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) {
> @@ -1130,7 +1136,7 @@ namespace {
> CheckSubobjectKind CSK) {
> if (Designator.Invalid)
> return false;
> - if (!Base) {
> + if (IsNullPtr) {
> Info.CCEDiag(E, diag::note_constexpr_null_subobject)
> << CSK;
> Designator.setInvalid();
> @@ -1159,9 +1165,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();
>
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.
+ }
> + void adjustOffset(CharUnits N) {
> + Offset += N;
> + if (N.getQuantity())
> + clearIsNullPointer();
> }
> };
>
> @@ -2036,7 +2055,7 @@ static bool HandleLValueMember(EvalInfo
> }
>
> 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;
> }
> @@ -2090,9 +2109,7 @@ static bool HandleLValueArrayAdjustment(
> 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;
> }
>
> @@ -5081,7 +5098,9 @@ public:
> 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);
> @@ -5180,6 +5199,8 @@ bool PointerExprEvaluator::VisitCastExpr
> else
> CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
> }
> + if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
> + ZeroInitialization(E);
> return true;
>
> case CK_DerivedToBase:
> @@ -5221,6 +5242,7 @@ bool PointerExprEvaluator::VisitCastExpr
> 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.
> @@ -8395,8 +8417,13 @@ bool IntExprEvaluator::VisitCastExpr(con
> 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);
> }
>
>
> Modified: cfe/trunk/lib/Basic/Targets.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/
> Targets.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Basic/Targets.cpp (original)
> +++ cfe/trunk/lib/Basic/Targets.cpp Thu Dec 15 02:09:08 2016
> @@ -2245,6 +2245,13 @@ public:
> 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[] = {
>
> Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGDecl.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Thu Dec 15 02:09:08 2016
> @@ -708,7 +708,7 @@ void CodeGenFunction::EmitScalarInit(con
> }
>
> 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)
>
> Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGExprAgg.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Thu Dec 15 02:09:08 2016
> @@ -1052,7 +1052,8 @@ static bool isSimpleZero(const Expr *E,
> 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;
>
> Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGExprConstant.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Dec 15 02:09:08 2016
> @@ -16,6 +16,7 @@
> #include "CGObjCRuntime.h"
> #include "CGRecordLayout.h"
> #include "CodeGenModule.h"
> +#include "TargetInfo.h"
> #include "clang/AST/APValue.h"
> #include "clang/AST/ASTContext.h"
> #include "clang/AST/RecordLayout.h"
> @@ -1262,6 +1263,10 @@ llvm::Constant *CodeGenModule::EmitConst
> return C;
> }
>
> +llvm::Constant *CodeGenModule::getNullPointer(llvm::PointerType *T,
> QualType QT) {
> + return getTargetCodeGenInfo().getNullPointer(*this, T, QT);
> +}
> +
> llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
> QualType DestType,
> CodeGenFunction *CGF) {
> @@ -1293,6 +1298,7 @@ llvm::Constant *CodeGenModule::EmitConst
> llvm::ConstantInt::get(Int64Ty, Value.getLValueOffset().
> getQuantity());
>
> llvm::Constant *C = nullptr;
> +
> if (APValue::LValueBase LVBase = Value.getLValueBase()) {
> // An array can be represented as an lvalue referring to the base.
> if (isa<llvm::ArrayType>(DestTy)) {
> @@ -1323,7 +1329,9 @@ llvm::Constant *CodeGenModule::EmitConst
>
> // Convert to the appropriate type; this could be an lvalue for
> // an integer.
> - if (isa<llvm::PointerType>(DestTy)) {
> + if (auto PT = dyn_cast<llvm::PointerType>(DestTy)) {
> + if (Value.isNullPointer())
> + return getNullPointer(PT, DestType);
> // Convert the integer to a pointer-sized integer before
> converting it
> // to a pointer.
> C = llvm::ConstantExpr::getIntegerCast(
> @@ -1510,7 +1518,7 @@ static llvm::Constant *EmitNullConstantF
> const CXXRecordDecl *base);
>
> static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
> - const CXXRecordDecl *record,
> + const RecordDecl *record,
> bool asCompleteObject) {
> const CGRecordLayout &layout = CGM.getTypes().
> getCGRecordLayout(record);
> llvm::StructType *structure =
> @@ -1520,25 +1528,29 @@ static llvm::Constant *EmitNullConstant(
> unsigned numElements = structure->getNumElements();
> std::vector<llvm::Constant *> elements(numElements);
>
> + auto CXXR = dyn_cast<CXXRecordDecl>(record);
> // Fill in all the bases.
> - for (const auto &I : record->bases()) {
> - if (I.isVirtual()) {
> - // Ignore virtual bases; if we're laying out for a complete
> - // object, we'll lay these out later.
> - continue;
> - }
> + if (CXXR) {
> + for (const auto &I : CXXR->bases()) {
> + if (I.isVirtual()) {
> + // Ignore virtual bases; if we're laying out for a complete
> + // object, we'll lay these out later.
> + continue;
> + }
>
> - const CXXRecordDecl *base =
> - cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
> + const CXXRecordDecl *base =
> + cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->
> getDecl());
>
> - // Ignore empty bases.
> - if (base->isEmpty() ||
> - CGM.getContext().getASTRecordLayout(base).
> getNonVirtualSize().isZero())
> - continue;
> -
> - unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
> - llvm::Type *baseType = structure->getElementType(fieldIndex);
> - elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
> + // Ignore empty bases.
> + if (base->isEmpty() ||
> + CGM.getContext().getASTRecordLayout(base).getNonVirtualSize()
> + .isZero())
> + continue;
> +
> + unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
> + llvm::Type *baseType = structure->getElementType(fieldIndex);
> + elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
> + }
> }
>
> // Fill in all the fields.
> @@ -1562,8 +1574,8 @@ static llvm::Constant *EmitNullConstant(
> }
>
> // Fill in the virtual bases, if we're working with the complete object.
> - if (asCompleteObject) {
> - for (const auto &I : record->vbases()) {
> + if (CXXR && asCompleteObject) {
> + for (const auto &I : CXXR->vbases()) {
> const CXXRecordDecl *base =
> cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->
> getDecl());
>
> @@ -1605,6 +1617,10 @@ static llvm::Constant *EmitNullConstantF
> }
>
> llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
> + if (T->getAs<PointerType>())
> + return getNullPointer(
> + cast<llvm::PointerType>(getTypes().ConvertTypeForMem(T)), T);
> +
> if (getTypes().isZeroInitializable(T))
> return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
>
> @@ -1620,10 +1636,8 @@ llvm::Constant *CodeGenModule::EmitNullC
> return llvm::ConstantArray::get(ATy, Array);
> }
>
> - if (const RecordType *RT = T->getAs<RecordType>()) {
> - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> - return ::EmitNullConstant(*this, RD, /*complete object*/ true);
> - }
> + if (const RecordType *RT = T->getAs<RecordType>())
> + return ::EmitNullConstant(*this, RT->getDecl(), /*complete object*/
> true);
>
> assert(T->isMemberDataPointerType() &&
> "Should only see pointers to data members here!");
>
> Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CGExprScalar.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Thu Dec 15 02:09:08 2016
> @@ -19,6 +19,7 @@
> #include "TargetInfo.h"
> #include "clang/AST/ASTContext.h"
> #include "clang/AST/DeclObjC.h"
> +#include "clang/AST/Expr.h"
> #include "clang/AST/RecordLayout.h"
> #include "clang/AST/StmtVisitor.h"
> #include "clang/Basic/TargetInfo.h"
> @@ -171,9 +172,9 @@ public:
> }
>
> /// EmitPointerToBoolConversion - Perform a pointer to boolean
> conversion.
> - Value *EmitPointerToBoolConversion(Value *V) {
> - Value *Zero = llvm::ConstantPointerNull::get(
> - cast<llvm::PointerType>(V->
> getType()));
> + Value *EmitPointerToBoolConversion(Value *V, QualType QT) {
> + Value *Zero = CGF.CGM.getNullPointer(cast<
> llvm::PointerType>(V->getType()), QT);
> +
> return Builder.CreateICmpNE(V, Zero, "tobool");
> }
>
> @@ -597,7 +598,7 @@ Value *ScalarExprEmitter::EmitConversion
> return EmitIntToBoolConversion(Src);
>
> assert(isa<llvm::PointerType>(Src->getType()));
> - return EmitPointerToBoolConversion(Src);
> + return EmitPointerToBoolConversion(Src, SrcType);
> }
>
> void ScalarExprEmitter::EmitFloatConversionCheck(
> @@ -1400,11 +1401,23 @@ Value *ScalarExprEmitter::VisitCastExpr(
> return Builder.CreateBitCast(Src, DstTy);
> }
> case CK_AddressSpaceConversion: {
> - Value *Src = Visit(const_cast<Expr*>(E));
> + Expr::EvalResult Result;
> + if (E->EvaluateAsRValue(Result, CGF.getContext()) &&
> + Result.Val.isNullPointer()) {
> + // If E has side effect, it is emitted even if its final result is a
> + // null pointer. In that case, a DCE pass should be able to
> + // eliminate the useless instructions emitted during translating E.
> + if (Result.HasSideEffects)
> + Visit(E);
> + return CGF.CGM.getNullPointer(cast<llvm::PointerType>(
> + ConvertType(DestTy)), DestTy);
> + }
> // Since target may map different address spaces in AST to the same
> address
> // space, an address space conversion may end up as a bitcast.
> - return Builder.CreatePointerBitCastOrAddrSpaceCast(Src,
> -
> ConvertType(DestTy));
> + auto *Src = Visit(E);
> + return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGF, Src,
> +
> E->getType(),
> + DestTy);
> }
> case CK_AtomicToNonAtomic:
> case CK_NonAtomicToAtomic:
> @@ -1459,8 +1472,8 @@ Value *ScalarExprEmitter::VisitCastExpr(
> if (MustVisitNullValue(E))
> (void) Visit(E);
>
> - return llvm::ConstantPointerNull::get(
> - cast<llvm::PointerType>(
> ConvertType(DestTy)));
> + return CGF.CGM.getNullPointer(cast<llvm::PointerType>(
> ConvertType(DestTy)),
> + DestTy);
>
> case CK_NullToMemberPointer: {
> if (MustVisitNullValue(E))
> @@ -1553,7 +1566,7 @@ Value *ScalarExprEmitter::VisitCastExpr(
> case CK_IntegralToBoolean:
> return EmitIntToBoolConversion(Visit(E));
> case CK_PointerToBoolean:
> - return EmitPointerToBoolConversion(Visit(E));
> + return EmitPointerToBoolConversion(Visit(E), E->getType());
> case CK_FloatingToBoolean:
> return EmitFloatToBoolConversion(Visit(E));
> case CK_MemberPointerToBoolean: {
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CodeGenModule.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Dec 15 02:09:08 2016
> @@ -2663,9 +2663,16 @@ void CodeGenModule::EmitGlobalVarDefinit
> else
> GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
>
> - if (Linkage == llvm::GlobalVariable::CommonLinkage)
> + if (Linkage == llvm::GlobalVariable::CommonLinkage) {
> // common vars aren't constant even if declared const.
> GV->setConstant(false);
> + // Tentative definition of global variables may be initialized with
> + // non-zero null pointers. In this case they should have weak linkage
> + // since common linkage must have zero initializer and must not have
> + // explicit section therefore cannot have non-zero initial value.
> + if (!GV->getInitializer()->isNullValue())
> + GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
> + }
>
> setNonAliasAttributes(D, GV);
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CodeGenModule.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Dec 15 02:09:08 2016
> @@ -1156,6 +1156,11 @@ public:
> llvm::Value *
> createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction
> &CGF);
>
> + /// Get target specific null pointer.
> + /// \param T is the LLVM type of the null pointer.
> + /// \param QT is the clang QualType of the null pointer.
> + llvm::Constant *getNullPointer(llvm::PointerType *T, QualType QT);
> +
> private:
> llvm::Constant *
> GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty,
> GlobalDecl D,
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CodeGenTypes.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Thu Dec 15 02:09:08 2016
> @@ -736,10 +736,14 @@ CodeGenTypes::getCGRecordLayout(const Re
> return *Layout;
> }
>
> +bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
> + assert (T->isAnyPointerType() && "Invalid type");
> + return isZeroInitializable(T);
> +}
> +
> bool CodeGenTypes::isZeroInitializable(QualType T) {
> - // No need to check for member pointers when not compiling C++.
> - if (!Context.getLangOpts().CPlusPlus)
> - return true;
> + if (T->getAs<PointerType>())
> + return Context.getTargetNullPointerValue(T) == 0;
>
> if (const auto *AT = Context.getAsArrayType(T)) {
> if (isa<IncompleteArrayType>(AT))
> @@ -753,7 +757,7 @@ bool CodeGenTypes::isZeroInitializable(Q
> // Records are non-zero-initializable if they contain any
> // non-zero-initializable subobjects.
> if (const RecordType *RT = T->getAs<RecordType>()) {
> - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> + auto RD = cast<RecordDecl>(RT->getDecl());
> return isZeroInitializable(RD);
> }
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> CodeGenTypes.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Thu Dec 15 02:09:08 2016
> @@ -352,6 +352,10 @@ public: // These are internal details o
> /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
> bool isZeroInitializable(QualType T);
>
> + /// Check if the pointer type can be zero-initialized (in the C++ sense)
> + /// with an LLVM zeroinitializer.
> + bool isPointerZeroInitializable(QualType T);
> +
> /// IsZeroInitializable - Return whether a record type can be
> /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
> bool isZeroInitializable(const RecordDecl *RD);
>
> Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> TargetInfo.cpp?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
> +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Thu Dec 15 02:09:08 2016
> @@ -401,6 +401,20 @@ unsigned TargetCodeGenInfo::getOpenCLKer
> return llvm::CallingConv::C;
> }
>
> +llvm::Constant *TargetCodeGenInfo::getNullPointer(const
> CodeGen::CodeGenModule &CGM,
> + llvm::PointerType *T, QualType QT) const {
> + return llvm::ConstantPointerNull::get(T);
> +}
> +
> +llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
> + CodeGen::CodeGenFunction &CGF, llvm::Value *Src, QualType SrcTy,
> + QualType DestTy) const {
> + // Since target may map different address spaces in AST to the same
> address
> + // space, an address space conversion may end up as a bitcast.
> + return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src,
> + CGF.ConvertType(DestTy));
> +}
> +
> static bool isEmptyRecord(ASTContext &Context, QualType T, bool
> AllowArrays);
>
> /// isEmptyField - Return true iff a the field is "empty", that is it
> @@ -7075,8 +7089,10 @@ public:
> void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
> CodeGen::CodeGenModule &M) const override;
> unsigned getOpenCLKernelCallingConv() const override;
> -};
>
> + llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
> + llvm::PointerType *T, QualType QT) const override;
> +};
> }
>
> static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM);
> @@ -7140,6 +7156,24 @@ unsigned AMDGPUTargetCodeGenInfo::getOpe
> return llvm::CallingConv::AMDGPU_KERNEL;
> }
>
> +// Currently LLVM assumes null pointers always have value 0,
> +// which results in incorrectly transformed IR. Therefore, instead of
> +// emitting null pointers in private and local address spaces, a null
> +// pointer in generic address space is emitted which is casted to a
> +// pointer in local or private address space.
> +llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer(
> + const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT,
> + QualType QT) const {
> + if (CGM.getContext().getTargetNullPointerValue(QT) == 0)
> + return llvm::ConstantPointerNull::get(PT);
> +
> + auto &Ctx = CGM.getContext();
> + auto NPT = llvm::PointerType::get(PT->getElementType(),
> + Ctx.getTargetAddressSpace(LangAS::opencl_generic));
> + return llvm::ConstantExpr::getAddrSpaceCast(
> + llvm::ConstantPointerNull::get(NPT), PT);
> +}
> +
> //===-------------------------------------------------------
> ---------------===//
> // SPARC v8 ABI Implementation.
> // Based on the SPARC Compliance Definition version 2.4.1.
>
> Modified: cfe/trunk/lib/CodeGen/TargetInfo.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/
> TargetInfo.h?rev=289787&r1=289786&r2=289787&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/CodeGen/TargetInfo.h (original)
> +++ cfe/trunk/lib/CodeGen/TargetInfo.h Thu Dec 15 02:09:08 2016
> @@ -220,6 +220,22 @@ public:
>
> /// Get LLVM calling convention for OpenCL kernel.
> virtual unsigned getOpenCLKernelCallingConv() const;
> +
> + /// Get target specific null pointer.
> + /// \param T is the LLVM type of the null pointer.
> + /// \param QT is the clang QualType of the null pointer.
> + /// \return ConstantPointerNull with the given type \p T.
> + /// Each target can override it to return its own desired constant
> value.
> + virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule
> &CGM,
> + llvm::PointerType *T, QualType QT) const;
> +
> + /// Perform address space cast of an expression of pointer type.
> + /// \param V is the LLVM value to be casted to another address space.
> + /// \param SrcTy is the QualType of \p V.
> + /// \param DestTy is the destination QualType.
> + virtual llvm::Value *performAddrSpaceCast(CodeGen::CodeGenFunction
> &CGF,
> + llvm::Value *V, QualType SrcTy, QualType DestTy) const;
> +
> };
>
> } // namespace CodeGen
>
> Added: cfe/trunk/test/CodeGenOpenCL/amdgpu-nullptr.cl
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> CodeGenOpenCL/amdgpu-nullptr.cl?rev=289787&view=auto
> ============================================================
> ==================
> --- cfe/trunk/test/CodeGenOpenCL/amdgpu-nullptr.cl (added)
> +++ cfe/trunk/test/CodeGenOpenCL/amdgpu-nullptr.cl Thu Dec 15 02:09:08
> 2016
> @@ -0,0 +1,534 @@
> +// RUN: %clang_cc1 %s -cl-std=CL2.0 -include opencl-c.h -triple amdgcn
> -emit-llvm -o - | FileCheck %s
> +// RUN: %clang_cc1 %s -O0 -cl-std=CL2.0 -include opencl-c.h -triple
> amdgcn -emit-llvm -o - | FileCheck --check-prefix=NOOPT %s
> +
> +typedef struct {
> + private char *p1;
> + local char *p2;
> + constant char *p3;
> + global char *p4;
> + generic char *p5;
> +} StructTy1;
> +
> +typedef struct {
> + constant char *p3;
> + global char *p4;
> + generic char *p5;
> +} StructTy2;
> +
> +// LLVM requests global variable with common linkage to be initialized
> with zeroinitializer, therefore use -fno-common
> +// to suppress common linkage for tentative definition.
> +
> +// Test 0 as initializer.
> +
> +// CHECK: @private_p = local_unnamed_addr addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +private char *private_p = 0;
> +
> +// CHECK: @local_p = local_unnamed_addr addrspace(1) global i8
> addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*),
> align 4
> +local char *local_p = 0;
> +
> +// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8
> addrspace(1)* null, align 4
> +global char *global_p = 0;
> +
> +// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8
> addrspace(2)* null, align 4
> +constant char *constant_p = 0;
> +
> +// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8
> addrspace(4)* null, align 4
> +generic char *generic_p = 0;
> +
> +// Test NULL as initializer.
> +
> +// CHECK: @private_p_NULL = local_unnamed_addr addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +private char *private_p_NULL = NULL;
> +
> +// CHECK: @local_p_NULL = local_unnamed_addr addrspace(1) global i8
> addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*),
> align 4
> +local char *local_p_NULL = NULL;
> +
> +// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8
> addrspace(1)* null, align 4
> +global char *global_p_NULL = NULL;
> +
> +// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8
> addrspace(2)* null, align 4
> +constant char *constant_p_NULL = NULL;
> +
> +// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8
> addrspace(4)* null, align 4
> +generic char *generic_p_NULL = NULL;
> +
> +// Test constant folding of null pointer.
> +// A null pointer should be folded to a null pointer in the target
> address space.
> +
> +// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32
> addrspace(4)* null, align 4
> +generic int *fold_generic = (global int*)(generic float*)(private char*)0;
> +
> +// CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16*
> addrspacecast (i16 addrspace(4)* null to i16*), align 4
> +private short *fold_priv = (private short*)(generic int*)(global void*)0;
> +
> +// CHECK: @fold_priv_arith = local_unnamed_addr addrspace(1) global i8*
> inttoptr (i32 9 to i8*), align 4
> +private char *fold_priv_arith = (private char*)0 + 10;
> +
> +// CHECK: @fold_int = local_unnamed_addr addrspace(1) global i32 13,
> align 4
> +int fold_int = (int)(private void*)(generic char*)(global int*)0 + 14;
> +
> +// CHECK: @fold_int2 = local_unnamed_addr addrspace(1) global i32 12,
> align 4
> +int fold_int2 = (int) ((private void*)0 + 13);
> +
> +// CHECK: @fold_int3 = local_unnamed_addr addrspace(1) global i32 -1,
> align 4
> +int fold_int3 = (int) ((private int*)0);
> +
> +// CHECK: @fold_int4 = local_unnamed_addr addrspace(1) global i32 7,
> align 4
> +int fold_int4 = (int) &((private int*)0)[2];
> +
> +// CHECK: @fold_int5 = local_unnamed_addr addrspace(1) global i32 3,
> align 4
> +int fold_int5 = (int) &((private StructTy1*)0)->p2;
> +
> +// Test static variable initialization.
> +
> +// NOOPT: @test_static_var.sp1 = internal addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +// NOOPT: @test_static_var.sp2 = internal addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +// NOOPT: @test_static_var.sp3 = internal addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +// NOOPT: @test_static_var.sp4 = internal addrspace(1) global i8* null,
> align 4
> +// NOOPT: @test_static_var.sp5 = internal addrspace(1) global i8* null,
> align 4
> +// 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
> +// NOOPT: @test_static_var.SS2 = internal addrspace(1) global
> %struct.StructTy2 zeroinitializer, align 4
> +
> +void test_static_var(void) {
> + static private char *sp1 = 0;
> + static private char *sp2 = NULL;
> + static private char *sp3;
> + static private char *sp4 = (private char*)((void)0, 0);
> + const int x = 0;
> + static private char *sp5 = (private char*)x;
> + static StructTy1 SS1;
> + static StructTy2 SS2;
> +}
> +
> +// Test function-scope variable initialization.
> +// NOOPT-LABEL: test_func_scope_var
> +// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8**
> %sp1, align 4
> +// NOOPT: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8**
> %sp2, align 4
> +// NOOPT: store i8* null, i8** %sp3, align 4
> +// NOOPT: store i8* null, i8** %sp4, align 4
> +// NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8*
> +// 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)
> +// NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8*
> +// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32
> 4, i1 false)
> +
> +void test_func_scope_var(void) {
> + private char *sp1 = 0;
> + private char *sp2 = NULL;
> + private char *sp3 = (private char*)((void)0, 0);
> + const int x = 0;
> + private char *sp4 = (private char*)x;
> + StructTy1 SS1 = {0, 0, 0, 0, 0};
> + StructTy2 SS2 = {0, 0, 0};
> +}
> +
> +// Test default initialization of pointers.
> +
> +// Tentative definition of global variables with non-zero initializer
> +// cannot have common linkage since common linkage requires zero
> initialization
> +// and does not have explicit section.
> +
> +// CHECK: @p1 = weak local_unnamed_addr addrspace(1) global i8*
> addrspacecast (i8 addrspace(4)* null to i8*), align 4
> +private char *p1;
> +
> +// CHECK: @p2 = weak local_unnamed_addr addrspace(1) global i8
> addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*),
> align 4
> +local char *p2;
> +
> +// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8
> addrspace(2)* null, align 4
> +constant char *p3;
> +
> +// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8
> addrspace(1)* null, align 4
> +global char *p4;
> +
> +// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8
> addrspace(4)* null, align 4
> +generic char *p5;
> +
> +// Test default initialization of sturcture.
> +
> +// 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
> +StructTy1 S1;
> +
> +// CHECK: @S2 = common local_unnamed_addr addrspace(1) global
> %struct.StructTy2 zeroinitializer, align 4
> +StructTy2 S2;
> +
> +// Test default initialization of array.
> +// 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
> +StructTy1 A1[2];
> +
> +// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x
> %struct.StructTy2] zeroinitializer, align 4
> +StructTy2 A2[2];
> +
> +// Test comparison with 0.
> +
> +// CHECK-LABEL: cmp_private
> +// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
> +void cmp_private(private char* p) {
> + if (p != 0)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_local
> +// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)*
> null to i8 addrspace(3)*)
> +void cmp_local(local char* p) {
> + if (p != 0)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_global
> +// CHECK: icmp eq i8 addrspace(1)* %p, null
> +void cmp_global(global char* p) {
> + if (p != 0)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_constant
> +// CHECK: icmp eq i8 addrspace(2)* %p, null
> +char cmp_constant(constant char* p) {
> + if (p != 0)
> + return *p;
> + else
> + return 0;
> +}
> +
> +// CHECK-LABEL: cmp_generic
> +// CHECK: icmp eq i8 addrspace(4)* %p, null
> +void cmp_generic(generic char* p) {
> + if (p != 0)
> + *p = 0;
> +}
> +
> +// Test comparison with NULL.
> +
> +// CHECK-LABEL: cmp_NULL_private
> +// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
> +void cmp_NULL_private(private char* p) {
> + if (p != NULL)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_NULL_local
> +// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)*
> null to i8 addrspace(3)*)
> +void cmp_NULL_local(local char* p) {
> + if (p != NULL)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_NULL_global
> +// CHECK: icmp eq i8 addrspace(1)* %p, null
> +void cmp_NULL_global(global char* p) {
> + if (p != NULL)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cmp_NULL_constant
> +// CHECK: icmp eq i8 addrspace(2)* %p, null
> +char cmp_NULL_constant(constant char* p) {
> + if (p != NULL)
> + return *p;
> + else
> + return 0;
> +}
> +
> +// CHECK-LABEL: cmp_NULL_generic
> +// CHECK: icmp eq i8 addrspace(4)* %p, null
> +void cmp_NULL_generic(generic char* p) {
> + if (p != NULL)
> + *p = 0;
> +}
> +
> +// Test storage 0 as null pointer.
> +// CHECK-LABEL: test_storage_null_pointer
> +// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8*
> addrspace(4)* %arg_private
> +// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to
> i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local
> +// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)*
> %arg_global
> +// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)*
> %arg_constant
> +// CHECK: store i8 addrspace(4)* null, i8 addrspace(4)* addrspace(4)*
> %arg_generic
> +void test_storage_null_pointer(private char** arg_private,
> + local char** arg_local,
> + global char** arg_global,
> + constant char** arg_constant,
> + generic char** arg_generic) {
> + *arg_private = 0;
> + *arg_local = 0;
> + *arg_global = 0;
> + *arg_constant = 0;
> + *arg_generic = 0;
> +}
> +
> +// Test storage NULL as null pointer.
> +// CHECK-LABEL: test_storage_null_pointer_NULL
> +// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8*
> addrspace(4)* %arg_private
> +// CHECK: store i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to
> i8 addrspace(3)*), i8 addrspace(3)* addrspace(4)* %arg_local
> +// CHECK: store i8 addrspace(1)* null, i8 addrspace(1)* addrspace(4)*
> %arg_global
> +// CHECK: store i8 addrspace(2)* null, i8 addrspace(2)* addrspace(4)*
> %arg_constant
> +// CHECK: store i8 addrspace(4)* null, i8 addrspace(4)* addrspace(4)*
> %arg_generic
> +void test_storage_null_pointer_NULL(private char** arg_private,
> + local char** arg_local,
> + global char** arg_global,
> + constant char** arg_constant,
> + generic char** arg_generic) {
> + *arg_private = NULL;
> + *arg_local = NULL;
> + *arg_global = NULL;
> + *arg_constant = NULL;
> + *arg_generic = NULL;
> +}
> +
> +// Test pass null pointer to function as argument.
> +void test_pass_null_pointer_arg_calee(private char* arg_private,
> + local char* arg_local,
> + global char* arg_global,
> + constant char* arg_constant,
> + generic char* arg_generic);
> +
> +// CHECK-LABEL: test_pass_null_pointer_arg
> +// CHECK: call void @test_pass_null_pointer_arg_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)
> +// CHECK: call void @test_pass_null_pointer_arg_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)
> +void test_pass_null_pointer_arg(void) {
> + test_pass_null_pointer_arg_calee(0, 0, 0, 0, 0);
> + test_pass_null_pointer_arg_calee(NULL, NULL, NULL, NULL, NULL);
> +}
> +
> +// Test cast null pointer to size_t.
> +void test_cast_null_pointer_to_sizet_calee(size_t arg_private,
> + size_t arg_local,
> + size_t arg_global,
> + size_t arg_constant,
> + size_t arg_generic);
> +
> +// CHECK-LABEL: test_cast_null_pointer_to_sizet
> +// CHECK: call void @test_cast_null_pointer_to_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)
> +// CHECK: call void @test_cast_null_pointer_to_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)
> +void test_cast_null_pointer_to_sizet(void) {
> + test_cast_null_pointer_to_sizet_calee((size_t)((private char*)0),
> + (size_t)((local char*)0),
> + (size_t)((global char*)0),
> + (size_t)((constant char*)0),
> + (size_t)((generic char*)0));
> + test_cast_null_pointer_to_sizet_calee((size_t)((private char*)NULL),
> + (size_t)((local char*)NULL),
> + (size_t)((global char*)NULL),
> + (size_t)((constant char*)0), //
> NULL cannot be casted to constant pointer since it is defined as a generic
> pointer
> + (size_t)((generic char*)NULL));
> +}
> +
> +// Test comparision between null pointers.
> +#define TEST_EQ00(addr1, addr2) int test_eq00_##addr1##_##addr2(void) {
> return (addr1 char*)0 == (addr2 char*)0; }
> +#define TEST_EQ0N(addr1, addr2) int test_eq0N_##addr1##_##addr2(void) {
> return (addr1 char*)0 == (addr2 char*)NULL; }
> +#define TEST_EQN0(addr1, addr2) int test_eqN0_##addr1##_##addr2(void) {
> return (addr1 char*)NULL == (addr2 char*)0; }
> +#define TEST_EQNN(addr1, addr2) int test_eqNN_##addr1##_##addr2(void) {
> return (addr1 char*)0 == (addr2 char*)NULL; }
> +#define TEST_NE00(addr1, addr2) int test_ne00_##addr1##_##addr2(void) {
> return (addr1 char*)0 != (addr2 char*)0; }
> +#define TEST_NE0N(addr1, addr2) int test_ne0N_##addr1##_##addr2(void) {
> return (addr1 char*)0 != (addr2 char*)NULL; }
> +#define TEST_NEN0(addr1, addr2) int test_neN0_##addr1##_##addr2(void) {
> return (addr1 char*)NULL != (addr2 char*)0; }
> +#define TEST_NENN(addr1, addr2) int test_neNN_##addr1##_##addr2(void) {
> return (addr1 char*)0 != (addr2 char*)NULL; }
> +#define TEST(addr1, addr2) \
> + TEST_EQ00(addr1, addr2) \
> + TEST_EQ0N(addr1, addr2) \
> + TEST_EQN0(addr1, addr2) \
> + TEST_EQNN(addr1, addr2) \
> + TEST_NE00(addr1, addr2) \
> + TEST_NE0N(addr1, addr2) \
> + TEST_NEN0(addr1, addr2) \
> + TEST_NENN(addr1, addr2)
> +
> +// CHECK-LABEL: test_eq00_generic_private
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eq0N_generic_private
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqN0_generic_private
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqNN_generic_private
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_ne00_generic_private
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_ne0N_generic_private
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neN0_generic_private
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neNN_generic_private
> +// CHECK: ret i32 0
> +TEST(generic, private)
> +
> +// CHECK-LABEL: test_eq00_generic_local
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eq0N_generic_local
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqN0_generic_local
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqNN_generic_local
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_ne00_generic_local
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_ne0N_generic_local
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neN0_generic_local
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neNN_generic_local
> +// CHECK: ret i32 0
> +TEST(generic, local)
> +
> +// CHECK-LABEL: test_eq00_generic_global
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eq0N_generic_global
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqN0_generic_global
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqNN_generic_global
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_ne00_generic_global
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_ne0N_generic_global
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neN0_generic_global
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neNN_generic_global
> +// CHECK: ret i32 0
> +TEST(generic, global)
> +
> +// CHECK-LABEL: test_eq00_generic_generic
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eq0N_generic_generic
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqN0_generic_generic
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_eqNN_generic_generic
> +// CHECK: ret i32 1
> +// CHECK-LABEL: test_ne00_generic_generic
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_ne0N_generic_generic
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neN0_generic_generic
> +// CHECK: ret i32 0
> +// CHECK-LABEL: test_neNN_generic_generic
> +// CHECK: ret i32 0
> +TEST(generic, generic)
> +
> +// CHECK-LABEL: test_eq00_constant_constant
> +// CHECK: ret i32 1
> +TEST_EQ00(constant, constant)
> +
> +// Test cast to bool.
> +
> +// CHECK-LABEL: cast_bool_private
> +// CHECK: icmp eq i8* %p, addrspacecast (i8 addrspace(4)* null to i8*)
> +void cast_bool_private(private char* p) {
> + if (p)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cast_bool_local
> +// CHECK: icmp eq i8 addrspace(3)* %p, addrspacecast (i8 addrspace(4)*
> null to i8 addrspace(3)*)
> +void cast_bool_local(local char* p) {
> + if (p)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cast_bool_global
> +// CHECK: icmp eq i8 addrspace(1)* %p, null
> +void cast_bool_global(global char* p) {
> + if (p)
> + *p = 0;
> +}
> +
> +// CHECK-LABEL: cast_bool_constant
> +// CHECK: icmp eq i8 addrspace(2)* %p, null
> +char cast_bool_constant(constant char* p) {
> + if (p)
> + return *p;
> + else
> + return 0;
> +}
> +
> +// CHECK-LABEL: cast_bool_generic
> +// CHECK: icmp eq i8 addrspace(4)* %p, null
> +void cast_bool_generic(generic char* p) {
> + if (p)
> + *p = 0;
> +}
> +
> +// Test initialize a struct using memset.
> +// For large structures which is mostly zero, clang generats llvm.memset
> for
> +// the zero part and store for non-zero members.
> +typedef struct {
> + long a, b, c, d;
> + private char *p;
> +} StructTy3;
> +
> +// CHECK-LABEL: test_memset
> +// CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 32, i32
> 8, i1 false)
> +// CHECK: store i8* addrspacecast (i8 addrspace(4)* null to i8*), i8**
> {{.*}}
> +StructTy3 test_memset(void) {
> + StructTy3 S3 = {0, 0, 0, 0, 0};
> + return S3;
> +}
> +
> +// Test casting literal 0 to pointer.
> +// A 0 literal casted to pointer should become a null pointer.
> +
> +// CHECK-LABEL: test_cast_0_to_ptr
> +// CHECK: ret i32* addrspacecast (i32 addrspace(4)* null to i32*)
> +private int* test_cast_0_to_ptr(void) {
> + return (private int*)0;
> +}
> +
> +// Test casting non-literal integer with 0 value to pointer.
> +// A non-literal integer expression with 0 value is casted to a pointer
> with
> +// zero value.
> +
> +// CHECK-LABEL: test_cast_int_to_ptr1
> +// CHECK: ret i32* null
> +private int* test_cast_int_to_ptr1(void) {
> + return (private int*)((void)0, 0);
> +}
> +
> +// CHECK-LABEL: test_cast_int_to_ptr2
> +// CHECK: ret i32* null
> +private int* test_cast_int_to_ptr2(void) {
> + int x = 0;
> + return (private int*)x;
> +}
> +
> +// Test logical operations.
> +// CHECK-LABEL: test_not_nullptr
> +// CHECK: ret i32 1
> +int test_not_nullptr(void) {
> + return !(private char*)NULL;
> +}
> +
> +// CHECK-LABEL: test_and_nullptr
> +// CHECK: ret i32 0
> +int test_and_nullptr(int a) {
> + return a && ((private char*)NULL);
> +}
> +
> +// CHECK-LABEL: test_not_ptr
> +// CHECK: %[[lnot:.*]] = icmp eq i8* %p, addrspacecast (i8 addrspace(4)*
> null to i8*)
> +// CHECK: %[[lnot_ext:.*]] = zext i1 %[[lnot]] to i32
> +// CHECK: ret i32 %[[lnot_ext]]
> +int test_not_ptr(private char* p) {
> + return !p;
> +}
> +// CHECK-LABEL: test_and_ptr
> +// CHECK: %[[tobool:.*]] = icmp ne i8* %p1, addrspacecast (i8
> addrspace(4)* null to i8*)
> +// CHECK: %[[tobool1:.*]] = icmp ne i8 addrspace(3)* %p2, addrspacecast
> (i8 addrspace(4)* null to i8 addrspace(3)*)
> +// CHECK: %[[res:.*]] = and i1 %[[tobool]], %[[tobool1]]
> +// CHECK: %[[land_ext:.*]] = zext i1 %[[res]] to i32
> +// CHECK: ret i32 %[[land_ext]]
> +int test_and_ptr(private char* p1, local char* p2) {
> + return p1 && p2;
> +}
> +
> +// Test folding of null pointer in function scope.
> +// NOOPT-LABEL: test_fold
> +// NOOPT: call void @test_fold_callee
> +// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4
> +// NOOPT: %{{.*}} = sub i64 %{{.*}}, 0
> +// NOOPT: call void @test_fold_callee
> +// NOOPT: %{{.*}} = add nsw i64 %{{.*}}, sext (i32 ptrtoint (i32*
> addrspacecast (i32 addrspace(4)* null to i32*) to i32) to i64)
> +// NOOPT: %{{.*}} = sub nsw i64 %{{.*}}, 1
> +void test_fold_callee(void);
> +void test_fold(void) {
> + global int* glob = (test_fold_callee(), (global int*)(generic char*)0);
> + long x = glob - (global int*)(generic char*)0;
> + x = x + (int)(test_fold_callee(), (private int*)(generic char*)(global
> short*)0);
> + x = x - (int)((private int*)0 == (private int*)(generic char*)0);
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170130/befa0491/attachment-0001.html>
More information about the cfe-commits
mailing list