Thanks! The test now also includes a regression test for PR31374, yes? On Thu, Dec 15, 2016 at 3:09 AM, Yaxun Liu via cfe-commits < cfe-commits@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) > : 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(); > + } > + 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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits