forked from OSchip/llvm-project
Revert 289252 (and follow-up 289285), it caused PR31374
llvm-svn: 289713
This commit is contained in:
parent
65aedad628
commit
7849eeb035
|
@ -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<LValuePathEntry> 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<LValuePathEntry> 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<LValuePathEntry> 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;
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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<LValuePathEntry> 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 {
|
||||
|
|
|
@ -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<T> is used from a TU that
|
||||
// doesn't include ASTContext.h
|
||||
template
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -708,7 +708,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
|
|||
}
|
||||
|
||||
auto ty = cast<llvm::PointerType>(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)
|
||||
|
|
|
@ -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<CastExpr>(E))
|
||||
return ICE->getCastKind() == CK_NullToPointer &&
|
||||
CGF.getTypes().isPointerZeroInitializable(E->getType());
|
||||
return ICE->getCastKind() == CK_NullToPointer;
|
||||
// '\0'
|
||||
if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E))
|
||||
return CL->getValue() == 0;
|
||||
|
|
|
@ -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<llvm::ArrayType>(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<llvm::PointerType>(DestTy)) {
|
||||
if (Value.isNullPointer())
|
||||
return getNullPointer(PT, DestType);
|
||||
if (isa<llvm::PointerType>(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<llvm::Constant *> elements(numElements);
|
||||
|
||||
auto CXXR = dyn_cast<CXXRecordDecl>(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;
|
||||
}
|
||||
|
||||
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);
|
||||
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<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);
|
||||
}
|
||||
|
||||
// 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<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
|
||||
|
||||
|
@ -1617,10 +1605,6 @@ static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
|
@ -1636,8 +1620,10 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
|
|||
return llvm::ConstantArray::get(ATy, Array);
|
||||
}
|
||||
|
||||
if (const RecordType *RT = T->getAs<RecordType>())
|
||||
return ::EmitNullConstant(*this, RT->getDecl(), /*complete object*/ true);
|
||||
if (const RecordType *RT = T->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
return ::EmitNullConstant(*this, RD, /*complete object*/ true);
|
||||
}
|
||||
|
||||
assert(T->isMemberDataPointerType() &&
|
||||
"Should only see pointers to data members here!");
|
||||
|
|
|
@ -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<llvm::PointerType>(V->getType()), QT);
|
||||
|
||||
Value *EmitPointerToBoolConversion(Value *V) {
|
||||
Value *Zero = llvm::ConstantPointerNull::get(
|
||||
cast<llvm::PointerType>(V->getType()));
|
||||
return Builder.CreateICmpNE(V, Zero, "tobool");
|
||||
}
|
||||
|
||||
|
@ -598,7 +597,7 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) {
|
|||
return EmitIntToBoolConversion(Src);
|
||||
|
||||
assert(isa<llvm::PointerType>(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<llvm::PointerType>(
|
||||
ConvertType(DestTy)), DestTy);
|
||||
}
|
||||
Value *Src = Visit(const_cast<Expr*>(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<llvm::PointerType>(ConvertType(DestTy)),
|
||||
DestTy);
|
||||
return llvm::ConstantPointerNull::get(
|
||||
cast<llvm::PointerType>(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: {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -736,14 +736,10 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
|
|||
return *Layout;
|
||||
}
|
||||
|
||||
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
|
||||
assert (T->getAs<PointerType>() && "Invalid type");
|
||||
return isZeroInitializable(T);
|
||||
}
|
||||
|
||||
bool CodeGenTypes::isZeroInitializable(QualType T) {
|
||||
if (T->getAs<PointerType>())
|
||||
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<IncompleteArrayType>(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<RecordType>()) {
|
||||
auto RD = cast<RecordDecl>(RT->getDecl());
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
return isZeroInitializable(RD);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue