diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -195,11 +195,11 @@ const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - - return Address( - CreateStructGEP(Addr.getElementType(), Addr.getPointer(), Index, Name), - ElTy->getElementType(Index), - Addr.getAlignment().alignmentAtOffset(Offset)); + auto *GEP = + CreateStructGEP(Addr.getElementType(), Addr.getPointer(), Index, Name); + cast(GEP)->setHasNoUnsignedWrap(true); + return Address(GEP, ElTy->getElementType(Index), + Addr.getAlignment().alignmentAtOffset(Offset)); } /// Given diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -5272,6 +5272,8 @@ SourceLocation Loc, const Twine &Name) { llvm::Type *PtrTy = Ptr->getType(); Value *GEPVal = Builder.CreateInBoundsGEP(ElemTy, Ptr, IdxList, Name); + if (!SignedIndices && !IsSubtraction) + cast(GEPVal)->setHasNoUnsignedWrap(true); // If the pointer overflow sanitizer isn't enabled, do nothing. if (!SanOpts.has(SanitizerKind::PointerOverflow)) diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -1119,6 +1119,12 @@ /// Determine whether the GEP has the inbounds flag. bool isInBounds() const; + void setHasNoUnsignedWrap(bool B); + bool hasNoUnsignedWrap() const; + + void setHasNoSignedWrap(bool B); + bool hasNoSignedWrap() const; + /// Accumulate the constant address offset of this GEP if possible. /// /// This routine accepts an APInt into which it will accumulate the constant diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h --- a/llvm/include/llvm/IR/Operator.h +++ b/llvm/include/llvm/IR/Operator.h @@ -381,10 +381,28 @@ IsInBounds = (1 << 0), // InRangeIndex: bits 1-6 }; + enum { + AnyWrap = 0, + HasNoUnsignedWrap = (1 << 0), + HasNoSignedWrap = (1 << 1), + }; void setIsInBounds(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsInBounds) | (B * IsInBounds); + setHasNoSignedWrap(B); + } + + void setHasNoUnsignedWrap(bool B) { + short D = getSubclassDataFromValue(); + D = (D & ~HasNoUnsignedWrap) | (B * HasNoUnsignedWrap); + setValueSubclassData(D); + } + + void setHasNoSignedWrap(bool B) { + short D = getSubclassDataFromValue(); + D = (D & ~HasNoSignedWrap) | (B * HasNoSignedWrap); + setValueSubclassData(D); } public: @@ -400,6 +418,16 @@ return (SubclassOptionalData >> 1) - 1; } + bool hasNoUnsignedWrap() const { + short D = getSubclassDataFromValue(); + return D & HasNoUnsignedWrap; + } + + bool hasNoSignedWrap() const { + short D = getSubclassDataFromValue(); + return D & HasNoSignedWrap; + } + inline op_iterator idx_begin() { return op_begin()+1; } inline const_op_iterator idx_begin() const { return op_begin()+1; } inline op_iterator idx_end() { return op_end(); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -3788,11 +3788,16 @@ unsigned Opc = Lex.getUIntVal(); SmallVector Elts; bool InBounds = false; + bool HasNoUnsignedWrap = false; + bool HasNoSignedWrap = false; Type *Ty; Lex.Lex(); - if (Opc == Instruction::GetElementPtr) + if (Opc == Instruction::GetElementPtr) { InBounds = EatIfPresent(lltok::kw_inbounds); + HasNoUnsignedWrap = EatIfPresent(lltok::kw_nuw); + HasNoSignedWrap = EatIfPresent(lltok::kw_nsw); + } if (parseToken(lltok::lparen, "expected '(' in constantexpr")) return true; @@ -7686,6 +7691,8 @@ LocTy Loc, EltLoc; bool InBounds = EatIfPresent(lltok::kw_inbounds); + bool HasNoUnsignedWrap = EatIfPresent(lltok::kw_nuw); + bool HasNoSignedWrap = EatIfPresent(lltok::kw_nsw); Type *Ty = nullptr; LocTy ExplicitTypeLoc = Lex.getLoc(); @@ -7745,6 +7752,11 @@ Inst = GetElementPtrInst::Create(Ty, Ptr, Indices); if (InBounds) cast(Inst)->setIsInBounds(true); + if (HasNoUnsignedWrap) + cast(Inst)->setHasNoUnsignedWrap(true); + if (HasNoSignedWrap) + cast(Inst)->setHasNoSignedWrap(true); + return AteExtraComma ? InstExtraComma : InstNormal; } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -1333,6 +1333,10 @@ } else if (const GEPOperator *GEP = dyn_cast(U)) { if (GEP->isInBounds()) Out << " inbounds"; + if (GEP->hasNoUnsignedWrap()) + Out << " nuw"; + /* if (GEP->hasNoSignedWrap())*/ + /*Out << " nsw";*/ } } diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -1839,6 +1839,22 @@ return cast(this)->isInBounds(); } +void GetElementPtrInst::setHasNoUnsignedWrap(bool B) { + cast(this)->setHasNoUnsignedWrap(B); +} + +bool GetElementPtrInst::hasNoUnsignedWrap() const { + return cast(this)->hasNoUnsignedWrap(); +} + +void GetElementPtrInst::setHasNoSignedWrap(bool B) { + cast(this)->setHasNoSignedWrap(B); +} + +bool GetElementPtrInst::hasNoSignedWrap() const { + return cast(this)->hasNoSignedWrap(); +} + bool GetElementPtrInst::accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const { // Delegate to the generic GEPOperator implementation. diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -214,7 +214,7 @@ if (DL.getIndexSizeInBits(AS) > 64) return {}; - if (!GEP.isInBounds()) + if (!GEP.hasNoUnsignedWrap() && !GEP.hasNoSignedWrap()) return {{0, nullptr}, {1, &GEP}}; // Handle the (gep (gep ....), C) case by incrementing the constant @@ -236,12 +236,19 @@ addWithOverflow(Result[0].Coefficient, multiplyWithOverflow(Scale, Offset.getSExtValue())); if (Offset.isNegative()) { - // Add pre-condition ensuring the GEP is increasing monotonically and - // can be de-composed. - Preconditions.emplace_back( - CmpInst::ICMP_SGE, InnerGEP->getOperand(1), - ConstantInt::get(InnerGEP->getOperand(1)->getType(), - -1 * Offset.getSExtValue())); + if (InnerGEP->hasNoUnsignedWrap()) { + // Add pre-condition ensuring the GEP is increasing monotonically and + // can be de-composed. + Preconditions.emplace_back( + CmpInst::ICMP_UGE, InnerGEP->getOperand(1), + ConstantInt::get(InnerGEP->getOperand(1)->getType(), + -1 * Offset.getSExtValue())); + } else { + Preconditions.emplace_back( + CmpInst::ICMP_SGE, InnerGEP->getOperand(1), + ConstantInt::get(InnerGEP->getOperand(1)->getType(), + -1 * Offset.getSExtValue())); + } } return Result; } @@ -286,7 +293,8 @@ } // If Op0 is signed non-negative, the GEP is increasing monotonically and // can be de-composed. - if (!isKnownNonNegative(Index, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) + if (!GEP.hasNoUnsignedWrap() && + !isKnownNonNegative(Index, DL, /*Depth=*/MaxAnalysisRecursionDepth - 1)) Preconditions.emplace_back(CmpInst::ICMP_SGE, Index, ConstantInt::get(Index->getType(), 0)); }