From: Nico Weber Date: Wed, 14 Dec 2016 21:38:18 +0000 (+0000) Subject: Revert 289252 (and follow-up 289285), it caused PR31374 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e9976eea59817bcc96b0ba5abedda906745a910f;p=clang Revert 289252 (and follow-up 289285), it caused PR31374 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289713 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h index 7c431f3be8..e58c21923f 100644 --- a/include/clang/AST/APValue.h +++ b/include/clang/AST/APValue.h @@ -135,15 +135,14 @@ public: } APValue(const APValue &RHS); APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); } - APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex, - bool IsNullPtr = false) + APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex) : Kind(Uninitialized) { - MakeLValue(); setLValue(B, O, N, CallIndex, IsNullPtr); + MakeLValue(); setLValue(B, O, N, CallIndex); } APValue(LValueBase B, const CharUnits &O, ArrayRef Path, - bool OnePastTheEnd, unsigned CallIndex, bool IsNullPtr = false) + bool OnePastTheEnd, unsigned CallIndex) : Kind(Uninitialized) { - MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex, IsNullPtr); + MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex); } APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) { MakeArray(InitElts, Size); @@ -255,7 +254,6 @@ public: bool hasLValuePath() const; ArrayRef getLValuePath() const; unsigned getLValueCallIndex() const; - bool isNullPointer() const; APValue &getVectorElt(unsigned I) { assert(isVector() && "Invalid accessor"); @@ -376,10 +374,10 @@ public: ((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I); } void setLValue(LValueBase B, const CharUnits &O, NoLValuePath, - unsigned CallIndex, bool IsNullPtr); + unsigned CallIndex); void setLValue(LValueBase B, const CharUnits &O, ArrayRef Path, bool OnePastTheEnd, - unsigned CallIndex, bool IsNullPtr); + unsigned CallIndex); void setUnion(const FieldDecl *Field, const APValue &Value) { assert(isUnion() && "Invalid accessor"); ((UnionData*)(char*)Data.buffer)->Field = Field; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 4e35ae833d..4f35508eba 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -2295,10 +2295,6 @@ 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 || diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index ec566f0642..b6b9aea690 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -42,7 +42,6 @@ class DiagnosticsEngine; class LangOptions; class CodeGenOptions; class MacroBuilder; -class QualType; class SourceLocation; class SourceManager; @@ -301,12 +300,6 @@ 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; } diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 488ad3373c..8923159972 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -27,7 +27,6 @@ namespace { CharUnits Offset; unsigned PathLength; unsigned CallIndex; - bool IsNullPtr; }; } @@ -150,11 +149,10 @@ APValue::APValue(const APValue &RHS) : Kind(Uninitialized) { MakeLValue(); if (RHS.hasLValuePath()) setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(), - RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(), - RHS.isNullPointer()); + RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex()); else setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(), - RHS.getLValueCallIndex(), RHS.isNullPointer()); + RHS.getLValueCallIndex()); break; case Array: MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize()); @@ -581,13 +579,8 @@ unsigned APValue::getLValueCallIndex() const { return ((const LV*)(const char*)Data.buffer)->CallIndex; } -bool APValue::isNullPointer() const { - assert(isLValue() && "Invalid usage"); - return ((const LV*)(const char*)Data.buffer)->IsNullPtr; -} - void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, - unsigned CallIndex, bool IsNullPtr) { + unsigned CallIndex) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); LVal.BaseAndIsOnePastTheEnd.setPointer(B); @@ -595,12 +588,11 @@ void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath, LVal.Offset = O; LVal.CallIndex = CallIndex; LVal.resizePath((unsigned)-1); - LVal.IsNullPtr = IsNullPtr; } void APValue::setLValue(LValueBase B, const CharUnits &O, ArrayRef Path, bool IsOnePastTheEnd, - unsigned CallIndex, bool IsNullPtr) { + unsigned CallIndex) { assert(isLValue() && "Invalid accessor"); LV &LVal = *((LV*)(char*)Data.buffer); LVal.BaseAndIsOnePastTheEnd.setPointer(B); @@ -609,7 +601,6 @@ void APValue::setLValue(LValueBase B, const CharUnits &O, LVal.CallIndex = CallIndex; LVal.resizePath(Path.size()); memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry)); - LVal.IsNullPtr = IsNullPtr; } const ValueDecl *APValue::getMemberPointerDecl() const { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a4861d982e..22be71a727 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -9426,16 +9426,6 @@ ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, } -uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const { - unsigned AS; - if (QT->getUnqualifiedDesugaredType()->isNullPtrType()) - AS = 0; - else - AS = QT->getPointeeType().getAddressSpace(); - - return getTargetInfo().getNullPointerValue(AS); -} - // Explicitly instantiate this in case a Redeclarable is used from a TU that // doesn't include ASTContext.h template diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c57b782632..5dd493cfff 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1088,7 +1088,6 @@ namespace { unsigned InvalidBase : 1; unsigned CallIndex : 31; SubobjectDesignator Designator; - bool IsNullPtr; const APValue::LValueBase getLValueBase() const { return Base; } CharUnits &getLValueOffset() { return Offset; } @@ -1096,15 +1095,13 @@ 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, - IsNullPtr); + V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex); else V = APValue(Base, Offset, Designator.Entries, - Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); + Designator.IsOnePastTheEnd, CallIndex); } void setFrom(ASTContext &Ctx, const APValue &V) { assert(V.isLValue()); @@ -1113,17 +1110,14 @@ namespace { InvalidBase = false; CallIndex = V.getLValueCallIndex(); Designator = SubobjectDesignator(Ctx, V); - IsNullPtr = V.isNullPointer(); } - void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false, - bool IsNullPtr_ = false, uint64_t Offset_ = 0) { + void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) { Base = B; - Offset = CharUnits::fromQuantity(Offset_); + Offset = CharUnits::Zero(); InvalidBase = BInvalid; CallIndex = I; Designator = SubobjectDesignator(getType(B)); - IsNullPtr = IsNullPtr_; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { @@ -1136,7 +1130,7 @@ namespace { CheckSubobjectKind CSK) { if (Designator.Invalid) return false; - if (IsNullPtr) { + if (!Base) { Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK; Designator.setInvalid(); @@ -1165,22 +1159,9 @@ namespace { if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real)) Designator.addComplexUnchecked(EltTy, Imag); } - 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(); + void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) { + if (N && checkNullPointer(Info, E, CSK_ArrayIndex)) + Designator.adjustIndex(Info, E, N); } }; @@ -2055,7 +2036,7 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal, } unsigned I = FD->getFieldIndex(); - LVal.adjustOffset(Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I))); + LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I)); LVal.addDecl(Info, E, FD); return true; } @@ -2109,7 +2090,9 @@ static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E, if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfPointee)) return false; - LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee); + // Compute the new offset in the appropriate width. + LVal.Offset += Adjustment * SizeOfPointee; + LVal.adjustIndex(Info, E, Adjustment); return true; } @@ -5095,9 +5078,7 @@ public: return true; } bool ZeroInitialization(const Expr *E) { - auto Offset = Info.Ctx.getTargetNullPointerValue(E->getType()); - Result.set((Expr*)nullptr, 0, false, true, Offset); - return true; + return Success((Expr*)nullptr); } bool VisitBinaryOperator(const BinaryOperator *E); @@ -5196,8 +5177,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { else CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; } - if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr) - ZeroInitialization(E); return true; case CK_DerivedToBase: @@ -5239,7 +5218,6 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Result.Offset = CharUnits::fromQuantity(N); Result.CallIndex = 0; Result.Designator.setInvalid(); - Result.IsNullPtr = false; return true; } else { // Cast is of an lvalue, no need to change value. @@ -8414,13 +8392,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return true; } - uint64_t V; - if (LV.isNullPointer()) - V = Info.Ctx.getTargetNullPointerValue(SrcType); - else - V = LV.getLValueOffset().getQuantity(); - - APSInt AsInt = Info.Ctx.MakeIntValue(V, SrcType); + APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(), + SrcType); return Success(HandleIntToIntCast(Info, E, DestType, SrcType, AsInt), E); } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index ee84089835..91eabb36bd 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -2245,13 +2245,6 @@ 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[] = { diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 4657347758..695e92ea1d 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -708,7 +708,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, } auto ty = cast(tempLV.getAddress().getElementType()); - llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType()); + llvm::Value *zero = llvm::ConstantPointerNull::get(ty); // If __weak, we want to use a barrier under certain conditions. if (lifetime == Qualifiers::OCL_Weak) diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 35148bea00..e24a0853c8 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -1052,8 +1052,7 @@ static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) { return true; // (int*)0 - Null pointer expressions. if (const CastExpr *ICE = dyn_cast(E)) - return ICE->getCastKind() == CK_NullToPointer && - CGF.getTypes().isPointerZeroInitializable(E->getType()); + return ICE->getCastKind() == CK_NullToPointer; // '\0' if (const CharacterLiteral *CL = dyn_cast(E)) return CL->getValue() == 0; diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 752f419f64..345e0a9216 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -16,7 +16,6 @@ #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" @@ -1263,10 +1262,6 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, 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) { @@ -1298,7 +1293,6 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, 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(DestTy)) { @@ -1329,9 +1323,7 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value, // Convert to the appropriate type; this could be an lvalue for // an integer. - if (auto PT = dyn_cast(DestTy)) { - if (Value.isNullPointer()) - return getNullPointer(PT, DestType); + if (isa(DestTy)) { // Convert the integer to a pointer-sized integer before converting it // to a pointer. C = llvm::ConstantExpr::getIntegerCast( @@ -1518,7 +1510,7 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, const CXXRecordDecl *base); static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, - const RecordDecl *record, + const CXXRecordDecl *record, bool asCompleteObject) { const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record); llvm::StructType *structure = @@ -1528,29 +1520,25 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, unsigned numElements = structure->getNumElements(); std::vector elements(numElements); - auto CXXR = dyn_cast(record); // Fill in all the bases. - 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; - } + 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; + } - const CXXRecordDecl *base = - cast(I.getType()->castAs()->getDecl()); + const CXXRecordDecl *base = + cast(I.getType()->castAs()->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. @@ -1574,8 +1562,8 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, } // Fill in the virtual bases, if we're working with the complete object. - if (CXXR && asCompleteObject) { - for (const auto &I : CXXR->vbases()) { + if (asCompleteObject) { + for (const auto &I : record->vbases()) { const CXXRecordDecl *base = cast(I.getType()->castAs()->getDecl()); @@ -1617,10 +1605,6 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM, } llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { - if (T->getAs()) - return getNullPointer( - cast(getTypes().ConvertTypeForMem(T)), T); - if (getTypes().isZeroInitializable(T)) return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); @@ -1636,8 +1620,10 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { return llvm::ConstantArray::get(ATy, Array); } - if (const RecordType *RT = T->getAs()) - return ::EmitNullConstant(*this, RT->getDecl(), /*complete object*/ true); + if (const RecordType *RT = T->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + return ::EmitNullConstant(*this, RD, /*complete object*/ true); + } assert(T->isMemberDataPointerType() && "Should only see pointers to data members here!"); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index e9bdbda34a..e763e6ab02 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -19,7 +19,6 @@ #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" @@ -172,9 +171,9 @@ public: } /// EmitPointerToBoolConversion - Perform a pointer to boolean conversion. - Value *EmitPointerToBoolConversion(Value *V, QualType QT) { - Value *Zero = CGF.CGM.getNullPointer(cast(V->getType()), QT); - + Value *EmitPointerToBoolConversion(Value *V) { + Value *Zero = llvm::ConstantPointerNull::get( + cast(V->getType())); return Builder.CreateICmpNE(V, Zero, "tobool"); } @@ -598,7 +597,7 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { return EmitIntToBoolConversion(Src); assert(isa(Src->getType())); - return EmitPointerToBoolConversion(Src, SrcType); + return EmitPointerToBoolConversion(Src); } void ScalarExprEmitter::EmitFloatConversionCheck( @@ -1401,23 +1400,11 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return Builder.CreateBitCast(Src, DstTy); } case CK_AddressSpaceConversion: { - 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( - ConvertType(DestTy)), DestTy); - } + Value *Src = Visit(const_cast(E)); // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. - auto *Src = Visit(E); - return CGF.CGM.getTargetCodeGenInfo().performAddrSpaceCast(CGF, Src, - E->getType(), - DestTy); + return Builder.CreatePointerBitCastOrAddrSpaceCast(Src, + ConvertType(DestTy)); } case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: @@ -1472,8 +1459,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { if (MustVisitNullValue(E)) (void) Visit(E); - return CGF.CGM.getNullPointer(cast(ConvertType(DestTy)), - DestTy); + return llvm::ConstantPointerNull::get( + cast(ConvertType(DestTy))); case CK_NullToMemberPointer: { if (MustVisitNullValue(E)) @@ -1566,7 +1553,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: - return EmitPointerToBoolConversion(Visit(E), E->getType()); + return EmitPointerToBoolConversion(Visit(E)); case CK_FloatingToBoolean: return EmitFloatToBoolConversion(Visit(E)); case CK_MemberPointerToBoolean: { diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 98b6215d0b..78f43bdef9 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2611,16 +2611,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, 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); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index f014be9557..be45bb8ea4 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1155,11 +1155,6 @@ 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, diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 357bff27a3..c92095bbbe 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -736,14 +736,10 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) { return *Layout; } -bool CodeGenTypes::isPointerZeroInitializable(QualType T) { - assert (T->getAs() && "Invalid type"); - return isZeroInitializable(T); -} - bool CodeGenTypes::isZeroInitializable(QualType T) { - if (T->getAs()) - return Context.getTargetNullPointerValue(T) == 0; + // No need to check for member pointers when not compiling C++. + if (!Context.getLangOpts().CPlusPlus) + return true; if (const auto *AT = Context.getAsArrayType(T)) { if (isa(AT)) @@ -757,7 +753,7 @@ bool CodeGenTypes::isZeroInitializable(QualType T) { // Records are non-zero-initializable if they contain any // non-zero-initializable subobjects. if (const RecordType *RT = T->getAs()) { - auto RD = cast(RT->getDecl()); + const CXXRecordDecl *RD = cast(RT->getDecl()); return isZeroInitializable(RD); } diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 2ce6591e4e..00df10dd13 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -352,10 +352,6 @@ public: // These are internal details of CGT that shouldn't be used externally. /// 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); diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 391eb53d25..38b164b113 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -401,20 +401,6 @@ unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { 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 @@ -7089,10 +7075,8 @@ 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); @@ -7156,24 +7140,6 @@ unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const { 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. diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 223d6d047a..e46382596a 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -220,22 +220,6 @@ 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 diff --git a/test/CodeGenOpenCL/amdgpu-nullptr.cl b/test/CodeGenOpenCL/amdgpu-nullptr.cl deleted file mode 100644 index 2d36fa90a6..0000000000 --- a/test/CodeGenOpenCL/amdgpu-nullptr.cl +++ /dev/null @@ -1,534 +0,0 @@ -// 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); -}