[llvm] r286514 - IR: Introduce inrange attribute on getelementptr indices.
Nuno Lopes via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 13 15:11:41 PST 2016
Ok, I got it now :)
The motivation was to make it possible to look at a constant GEP and be able
to assert which element it will access without looking at the GEP's users.
It seems inrange implies inbounds for GEPs with just 1 index (but obviously
not the other way around).
Make sense; sorry for the noise!
Nuno
-----Original Message-----
From: Mehdi Amini
Sent: Saturday, November 12, 2016 11:30 PM
Subject: Re: [llvm] r286514 - IR: Introduce inrange attribute on
getelementptr indices.
Maybe this explanation from Peter can help:
https://reviews.llvm.org/D22793?id=65651#inline-208740
If you think that LangRef isn’t clear enough, feel free to propose to amend
the wording!
—
Mehdi
> On Nov 12, 2016, at 2:58 PM, Nuno Lopes <nunoplopes at sapo.pt> wrote:
>
> Ah, sorry, my bad. I read it as GEP would trigger UB, no the subsequent
> load/store.
> OK, but now I'm confused. What's the difference to inbounds? load/store
> from a poison pointer is UB, so it seems inrange is essentially the same?
> (don't they both return poison if the ptr computation either overflows or
> produces a ptr out of bounds?)
>
> Thanks,
> Nuno
>
> -----Original Message----- From: Mehdi Amini
> Sent: Saturday, November 12, 2016 9:27 PM
> Subject: Re: [llvm] r286514 - IR: Introduce inrange attribute on
> getelementptr indices.
>
> Hi Nuno,
>
> Can you clarify why these GEP should be treated as division? This isn’t
> clear to me. The UB applies to load/store, not to the GEP itself.
>
> Also note the inrange is allowed only on constant GEP expression right
> now.
>
> —
> Mehdi
>
>> On Nov 12, 2016, at 10:08 AM, Nuno Lopes via llvm-commits
>> <llvm-commits at lists.llvm.org> wrote:
>>
>> Hi Peter,
>>
>> Sorry for the very late review. I missed the whole discussion for the
>> motivation for this new attribute, so I'll comment just on this patch.
>> Are you sure there are no optimizations that may hoist GEPs? If there
>> are, all of these must be fixed to block 'GEP inrange' from being
>> hoisted. Basically, 'GEP inrange' has to be treated like division.
>> This fact that hoisting is not allowed probably precludes clang from
>> using this attribute altogether?
>>
>> Nuno
>>
>> -----Original Message----- From: Peter Collingbourne via llvm-commits
>> Sent: Thursday, November 10, 2016 10:34 PM
>> To: llvm-commits at lists.llvm.org
>> Subject: [llvm] r286514 - IR: Introduce inrange attribute on
>> getelementptr indices.
>>
>> Author: pcc
>> Date: Thu Nov 10 16:34:55 2016
>> New Revision: 286514
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=286514&view=rev
>> Log:
>> IR: Introduce inrange attribute on getelementptr indices.
>>
>> If the inrange keyword is present before any index, loading from or
>> storing to any pointer derived from the getelementptr has undefined
>> behavior if the load or store would access memory outside of the bounds
>> of
>> the element selected by the index marked as inrange.
>>
>> This can be used, e.g. for alias analysis or to split globals at element
>> boundaries where beneficial.
>>
>> As previously proposed on llvm-dev:
>> http://lists.llvm.org/pipermail/llvm-dev/2016-July/102472.html
>>
>> Differential Revision: https://reviews.llvm.org/D22793
>>
>> Added:
>> llvm/trunk/test/Analysis/ConstantFolding/
>> llvm/trunk/test/Analysis/ConstantFolding/gep.ll
>> Modified:
>> llvm/trunk/docs/LangRef.rst
>> llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>> llvm/trunk/include/llvm/IR/Constants.h
>> llvm/trunk/include/llvm/IR/Operator.h
>> llvm/trunk/lib/Analysis/ConstantFolding.cpp
>> llvm/trunk/lib/AsmParser/LLLexer.cpp
>> llvm/trunk/lib/AsmParser/LLParser.cpp
>> llvm/trunk/lib/AsmParser/LLParser.h
>> llvm/trunk/lib/AsmParser/LLToken.h
>> llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>> llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>> llvm/trunk/lib/IR/AsmWriter.cpp
>> llvm/trunk/lib/IR/ConstantFold.cpp
>> llvm/trunk/lib/IR/ConstantFold.h
>> llvm/trunk/lib/IR/Constants.cpp
>> llvm/trunk/test/Assembler/getelementptr.ll
>> llvm/trunk/test/Bitcode/compatibility.ll
>>
>> Modified: llvm/trunk/docs/LangRef.rst
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/docs/LangRef.rst (original)
>> +++ llvm/trunk/docs/LangRef.rst Thu Nov 10 16:34:55 2016
>> @@ -7450,9 +7450,9 @@ Syntax:
>>
>> ::
>>
>> - <result> = getelementptr <ty>, <ty>* <ptrval>{, <ty> <idx>}*
>> - <result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, <ty>
>> <idx>}*
>> - <result> = getelementptr <ty>, <ptr vector> <ptrval>, <vector
>> index type> <idx>
>> + <result> = getelementptr <ty>, <ty>* <ptrval>{, [inrange] <ty>
>> <idx>}*
>> + <result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, [inrange]
>> <ty> <idx>}*
>> + <result> = getelementptr <ty>, <ptr vector> <ptrval>, [inrange]
>> <vector index type> <idx>
>>
>> Overview:
>> """""""""
>> @@ -7569,6 +7569,18 @@ though, even if it happens to point into
>> :ref:`Pointer Aliasing Rules <pointeraliasing>` section for more
>> information.
>>
>> +If the ``inrange`` keyword is present before any index, loading from or
>> +storing to any pointer derived from the ``getelementptr`` has undefined
>> +behavior if the load or store would access memory outside of the bounds
>> of
>> +the element selected by the index marked as ``inrange``. The result of a
>> +pointer comparison or ``ptrtoint`` (including ``ptrtoint``-like
>> operations
>> +involving memory) involving a pointer derived from a ``getelementptr``
>> with
>> +the ``inrange`` keyword is undefined, with the exception of comparisons
>> +in the case where both operands are in the range of the element selected
>> +by the ``inrange`` keyword, inclusive of the address one past the end of
>> +that element. Note that the ``inrange`` keyword is currently only
>> allowed
>> +in constant ``getelementptr`` expressions.
>> +
>> The getelementptr instruction is often confusing. For some more insight
>> into how it works, see :doc:`the getelementptr FAQ <GetElementPtr>`.
>>
>>
>> Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
>> +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Nov 10 16:34:55
>> 2016
>> @@ -280,8 +280,9 @@ enum ConstantsCodes {
>> CST_CODE_CE_INBOUNDS_GEP = 20, // INBOUNDS_GEP: [n x operands]
>> CST_CODE_BLOCKADDRESS = 21, // CST_CODE_BLOCKADDRESS [fnty, fnval,
>> bb#]
>> CST_CODE_DATA = 22, // DATA: [n x elements]
>> - CST_CODE_INLINEASM = 23 // INLINEASM: [sideeffect|alignstack|
>> + CST_CODE_INLINEASM = 23, // INLINEASM: [sideeffect|alignstack|
>> // asmdialect,asmstr,conststr]
>> + CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x
>> operands]
>> };
>>
>> /// CastOpcodes - These are values used in the bitcode files to encode
>> which
>>
>> Modified: llvm/trunk/include/llvm/IR/Constants.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Constants.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/IR/Constants.h (original)
>> +++ llvm/trunk/include/llvm/IR/Constants.h Thu Nov 10 16:34:55 2016
>> @@ -24,6 +24,7 @@
>> #include "llvm/ADT/APFloat.h"
>> #include "llvm/ADT/APInt.h"
>> #include "llvm/ADT/ArrayRef.h"
>> +#include "llvm/ADT/Optional.h"
>> #include "llvm/IR/Constant.h"
>> #include "llvm/IR/DerivedTypes.h"
>> #include "llvm/IR/OperandTraits.h"
>> @@ -1071,26 +1072,31 @@ public:
>> /// Getelementptr form. Value* is only accepted for convenience;
>> /// all elements must be Constants.
>> ///
>> + /// \param InRangeIndex the inrange index if present or None.
>> /// \param OnlyIfReducedTy see \a getWithOperands() docs.
>> static Constant *getGetElementPtr(Type *Ty, Constant *C,
>> ArrayRef<Constant *> IdxList,
>> bool InBounds = false,
>> + Optional<unsigned> InRangeIndex =
>> None,
>> Type *OnlyIfReducedTy = nullptr) {
>> return getGetElementPtr(
>> Ty, C, makeArrayRef((Value * const *)IdxList.data(),
>> IdxList.size()),
>> - InBounds, OnlyIfReducedTy);
>> + InBounds, InRangeIndex, OnlyIfReducedTy);
>> }
>> static Constant *getGetElementPtr(Type *Ty, Constant *C, Constant *Idx,
>> bool InBounds = false,
>> + Optional<unsigned> InRangeIndex =
>> None,
>> Type *OnlyIfReducedTy = nullptr) {
>> // This form of the function only exists to avoid ambiguous overload
>> // warnings about whether to convert Idx to ArrayRef<Constant *> or
>> // ArrayRef<Value *>.
>> - return getGetElementPtr(Ty, C, cast<Value>(Idx), InBounds,
>> OnlyIfReducedTy);
>> + return getGetElementPtr(Ty, C, cast<Value>(Idx), InBounds,
>> InRangeIndex,
>> + OnlyIfReducedTy);
>> }
>> static Constant *getGetElementPtr(Type *Ty, Constant *C,
>> ArrayRef<Value *> IdxList,
>> bool InBounds = false,
>> + Optional<unsigned> InRangeIndex =
>> None,
>> Type *OnlyIfReducedTy = nullptr);
>>
>> /// Create an "inbounds" getelementptr. See the documentation for the
>>
>> Modified: llvm/trunk/include/llvm/IR/Operator.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Operator.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/IR/Operator.h (original)
>> +++ llvm/trunk/include/llvm/IR/Operator.h Thu Nov 10 16:34:55 2016
>> @@ -364,7 +364,8 @@ class ZExtOperator : public ConcreteOper
>> class GEPOperator
>> : public ConcreteOperator<Operator, Instruction::GetElementPtr> {
>> enum {
>> - IsInBounds = (1 << 0)
>> + IsInBounds = (1 << 0),
>> + // InRangeIndex: bits 1-6
>> };
>>
>> friend class GetElementPtrInst;
>> @@ -379,6 +380,12 @@ public:
>> bool isInBounds() const {
>> return SubclassOptionalData & IsInBounds;
>> }
>> + /// Returns the offset of the index with an inrange attachment, or
>> None if
>> + /// none.
>> + Optional<unsigned> getInRangeIndex() const {
>> + if (SubclassOptionalData >> 1 == 0) return None;
>> + return (SubclassOptionalData >> 1) - 1;
>> + }
>>
>> inline op_iterator idx_begin() { return op_begin()+1; }
>> inline const_op_iterator idx_begin() const { return op_begin()+1; }
>>
>> Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
>> +++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Thu Nov 10 16:34:55 2016
>> @@ -718,8 +718,8 @@ Constant *SymbolicallyEvaluateBinop(unsi
>> /// If array indices are not pointer-sized integers, explicitly cast them
>> so
>> /// that they aren't implicitly casted by the getelementptr.
>> Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
>> - Type *ResultTy, const DataLayout &DL,
>> - const TargetLibraryInfo *TLI) {
>> + Type *ResultTy, Optional<unsigned>
>> InRangeIndex,
>> + const DataLayout &DL, const TargetLibraryInfo
>> *TLI) {
>> Type *IntPtrTy = DL.getIntPtrType(ResultTy);
>>
>> bool Any = false;
>> @@ -742,7 +742,8 @@ Constant *CastGEPIndices(Type *SrcElemTy
>> if (!Any)
>> return nullptr;
>>
>> - Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ops[0],
>> NewIdxs);
>> + Constant *C = ConstantExpr::getGetElementPtr(
>> + SrcElemTy, Ops[0], NewIdxs, /*InBounds=*/false, InRangeIndex);
>> if (Constant *Folded = ConstantFoldConstant(C, DL, TLI))
>> C = Folded;
>>
>> @@ -771,13 +772,16 @@ Constant *SymbolicallyEvaluateGEP(const
>> ArrayRef<Constant *> Ops,
>> const DataLayout &DL,
>> const TargetLibraryInfo *TLI) {
>> + const GEPOperator *InnermostGEP = GEP;
>> +
>> Type *SrcElemTy = GEP->getSourceElementType();
>> Type *ResElemTy = GEP->getResultElementType();
>> Type *ResTy = GEP->getType();
>> if (!SrcElemTy->isSized())
>> return nullptr;
>>
>> - if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy, DL, TLI))
>> + if (Constant *C = CastGEPIndices(SrcElemTy, Ops, ResTy,
>> + GEP->getInRangeIndex(), DL, TLI))
>> return C;
>>
>> Constant *Ptr = Ops[0];
>> @@ -820,6 +824,8 @@ Constant *SymbolicallyEvaluateGEP(const
>>
>> // If this is a GEP of a GEP, fold it all into a single GEP.
>> while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
>> + InnermostGEP = GEP;
>> +
>> SmallVector<Value *, 4> NestedOps(GEP->op_begin() + 1, GEP->op_end());
>>
>> // Do not try the incorporate the sub-GEP if some index is not a
>> number.
>> @@ -925,8 +931,23 @@ Constant *SymbolicallyEvaluateGEP(const
>> if (Offset != 0)
>> return nullptr;
>>
>> + // Preserve the inrange index from the innermost GEP if possible. We
>> must
>> + // have calculated the same indices up to and including the inrange
>> index.
>> + Optional<unsigned> InRangeIndex;
>> + if (Optional<unsigned> LastIRIndex = InnermostGEP->getInRangeIndex())
>> + if (SrcElemTy == InnermostGEP->getSourceElementType() &&
>> + NewIdxs.size() > *LastIRIndex) {
>> + InRangeIndex = LastIRIndex;
>> + for (unsigned I = 0; I <= *LastIRIndex; ++I)
>> + if (NewIdxs[I] != InnermostGEP->getOperand(I + 1)) {
>> + InRangeIndex = None;
>> + break;
>> + }
>> + }
>> +
>> // Create a GEP.
>> - Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ptr, NewIdxs);
>> + Constant *C = ConstantExpr::getGetElementPtr(
>> + SrcElemTy, Ptr, NewIdxs, /*InBounds=*/false, InRangeIndex);
>> assert(C->getType()->getPointerElementType() == Ty &&
>> "Computed GetElementPtr has unexpected type!");
>>
>> @@ -944,8 +965,8 @@ Constant *SymbolicallyEvaluateGEP(const
>> /// attempting to fold instructions like loads and stores, which have no
>> /// constant expression form.
>> ///
>> -/// TODO: This function neither utilizes nor preserves
>> nsw/nuw/inbounds/etc
>> -/// information, due to only being passed an opcode and operands.
>> Constant
>> +/// TODO: This function neither utilizes nor preserves
>> nsw/nuw/inbounds/inrange
>> +/// etc information, due to only being passed an opcode and operands.
>> Constant
>> /// folding using this function strips this information.
>> ///
>> Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned
>> Opcode,
>> @@ -965,8 +986,9 @@ Constant *ConstantFoldInstOperandsImpl(c
>> if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI))
>> return C;
>>
>> - return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(),
>> - Ops[0], Ops.slice(1));
>> + return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(),
>> Ops[0],
>> + Ops.slice(1),
>> GEP->isInBounds(),
>> + GEP->getInRangeIndex());
>> }
>>
>> if (auto *CE = dyn_cast<ConstantExpr>(InstOrCE))
>>
>> Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
>> +++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Nov 10 16:34:55 2016
>> @@ -551,6 +551,7 @@ lltok::Kind LLLexer::LexIdentifier() {
>> KEYWORD(nsw);
>> KEYWORD(exact);
>> KEYWORD(inbounds);
>> + KEYWORD(inrange);
>> KEYWORD(align);
>> KEYWORD(addrspace);
>> KEYWORD(section);
>>
>> Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
>> +++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Nov 10 16:34:55 2016
>> @@ -3175,7 +3175,9 @@ bool LLParser::ParseValID(ValID &ID, Per
>> return true;
>> }
>>
>> - if (ParseGlobalValueVector(Elts) ||
>> + Optional<unsigned> InRangeOp;
>> + if (ParseGlobalValueVector(
>> + Elts, Opc == Instruction::GetElementPtr ? &InRangeOp :
>> nullptr) ||
>> ParseToken(lltok::rparen, "expected ')' in constantexpr"))
>> return true;
>>
>> @@ -3214,8 +3216,16 @@ bool LLParser::ParseValID(ValID &ID, Per
>>
>> if (!GetElementPtrInst::getIndexedType(Ty, Indices))
>> return Error(ID.Loc, "invalid getelementptr indices");
>> - ID.ConstantVal =
>> - ConstantExpr::getGetElementPtr(Ty, Elts[0], Indices,
>> InBounds);
>> +
>> + if (InRangeOp) {
>> + if (*InRangeOp == 0)
>> + return Error(ID.Loc,
>> + "inrange keyword may not appear on pointer
>> operand");
>> + --*InRangeOp;
>> + }
>> +
>> + ID.ConstantVal = ConstantExpr::getGetElementPtr(Ty, Elts[0],
>> Indices,
>> + InBounds,
>> InRangeOp);
>> } else if (Opc == Instruction::Select) {
>> if (Elts.size() != 3)
>> return Error(ID.Loc, "expected three operands to select");
>> @@ -3298,8 +3308,9 @@ bool LLParser::parseOptionalComdat(Strin
>>
>> /// ParseGlobalValueVector
>> /// ::= /*empty*/
>> -/// ::= TypeAndValue (',' TypeAndValue)*
>> -bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts)
>> {
>> +/// ::= [inrange] TypeAndValue (',' [inrange] TypeAndValue)*
>> +bool LLParser::ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts,
>> + Optional<unsigned> *InRangeOp) {
>> // Empty list.
>> if (Lex.getKind() == lltok::rbrace ||
>> Lex.getKind() == lltok::rsquare ||
>> @@ -3307,14 +3318,14 @@ bool LLParser::ParseGlobalValueVector(Sm
>> Lex.getKind() == lltok::rparen)
>> return false;
>>
>> - Constant *C;
>> - if (ParseGlobalTypeAndValue(C)) return true;
>> - Elts.push_back(C);
>> + do {
>> + if (InRangeOp && !*InRangeOp && EatIfPresent(lltok::kw_inrange))
>> + *InRangeOp = Elts.size();
>>
>> - while (EatIfPresent(lltok::comma)) {
>> + Constant *C;
>> if (ParseGlobalTypeAndValue(C)) return true;
>> Elts.push_back(C);
>> - }
>> + } while (EatIfPresent(lltok::comma));
>>
>> return false;
>> }
>>
>> Modified: llvm/trunk/lib/AsmParser/LLParser.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/AsmParser/LLParser.h (original)
>> +++ llvm/trunk/lib/AsmParser/LLParser.h Thu Nov 10 16:34:55 2016
>> @@ -411,7 +411,8 @@ namespace llvm {
>> bool ParseValID(ValID &ID, PerFunctionState *PFS = nullptr);
>> bool ParseGlobalValue(Type *Ty, Constant *&V);
>> bool ParseGlobalTypeAndValue(Constant *&V);
>> - bool ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts);
>> + bool ParseGlobalValueVector(SmallVectorImpl<Constant *> &Elts,
>> + Optional<unsigned> *InRangeOp =
>> nullptr);
>> bool parseOptionalComdat(StringRef GlobalName, Comdat *&C);
>> bool ParseMetadataAsValue(Value *&V, PerFunctionState &PFS);
>> bool ParseValueAsMetadata(Metadata *&MD, const Twine &TypeMsg,
>>
>> Modified: llvm/trunk/lib/AsmParser/LLToken.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/AsmParser/LLToken.h (original)
>> +++ llvm/trunk/lib/AsmParser/LLToken.h Thu Nov 10 16:34:55 2016
>> @@ -103,6 +103,7 @@ enum Kind {
>> kw_nsw,
>> kw_exact,
>> kw_inbounds,
>> + kw_inrange,
>> kw_align,
>> kw_addrspace,
>> kw_section,
>>
>> Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
>> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Nov 10 16:34:55
>> 2016
>> @@ -3268,12 +3268,25 @@ Error BitcodeReader::parseConstants() {
>> }
>> break;
>> }
>> - case bitc::CST_CODE_CE_INBOUNDS_GEP:
>> - case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands]
>> + case bitc::CST_CODE_CE_INBOUNDS_GEP: // [ty, n x operands]
>> + case bitc::CST_CODE_CE_GEP: // [ty, n x operands]
>> + case bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX: { // [ty, flags, n x
>> + // operands]
>> unsigned OpNum = 0;
>> Type *PointeeType = nullptr;
>> - if (Record.size() % 2)
>> + if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX ||
>> + Record.size() % 2)
>> PointeeType = getTypeByID(Record[OpNum++]);
>> +
>> + bool InBounds = false;
>> + Optional<unsigned> InRangeIndex;
>> + if (BitCode == bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX) {
>> + uint64_t Op = Record[OpNum++];
>> + InBounds = Op & 1;
>> + InRangeIndex = Op >> 1;
>> + } else if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP)
>> + InBounds = true;
>> +
>> SmallVector<Constant*, 16> Elts;
>> while (OpNum != Record.size()) {
>> Type *ElTy = getTypeByID(Record[OpNum++]);
>> @@ -3294,8 +3307,7 @@ Error BitcodeReader::parseConstants() {
>>
>> ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end());
>> V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices,
>> - BitCode ==
>> - bitc::CST_CODE_CE_INBOUNDS_GEP);
>> + InBounds, InRangeIndex);
>> break;
>> }
>> case bitc::CST_CODE_CE_SELECT: { // CE_SELECT: [opval#, opval#,
>> opval#]
>>
>> Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
>> +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Nov 10 16:34:55
>> 2016
>> @@ -2217,9 +2217,12 @@ void ModuleBitcodeWriter::writeConstants
>> case Instruction::GetElementPtr: {
>> Code = bitc::CST_CODE_CE_GEP;
>> const auto *GO = cast<GEPOperator>(C);
>> - if (GO->isInBounds())
>> - Code = bitc::CST_CODE_CE_INBOUNDS_GEP;
>> Record.push_back(VE.getTypeID(GO->getSourceElementType()));
>> + if (Optional<unsigned> Idx = GO->getInRangeIndex()) {
>> + Code = bitc::CST_CODE_CE_GEP_WITH_INRANGE_INDEX;
>> + Record.push_back((*Idx << 1) | GO->isInBounds());
>> + } else if (GO->isInBounds())
>> + Code = bitc::CST_CODE_CE_INBOUNDS_GEP;
>> for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) {
>> Record.push_back(VE.getTypeID(C->getOperand(i)->getType()));
>> Record.push_back(VE.getValueID(C->getOperand(i)));
>>
>> Modified: llvm/trunk/lib/IR/AsmWriter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AsmWriter.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/IR/AsmWriter.cpp (original)
>> +++ llvm/trunk/lib/IR/AsmWriter.cpp Thu Nov 10 16:34:55 2016
>> @@ -1320,12 +1320,18 @@ static void WriteConstantInternal(raw_os
>> static_cast<CmpInst::Predicate>(CE->getPredicate()));
>> Out << " (";
>>
>> + Optional<unsigned> InRangeOp;
>> if (const GEPOperator *GEP = dyn_cast<GEPOperator>(CE)) {
>> TypePrinter.print(GEP->getSourceElementType(), Out);
>> Out << ", ";
>> + InRangeOp = GEP->getInRangeIndex();
>> + if (InRangeOp)
>> + ++*InRangeOp;
>> }
>>
>> for (User::const_op_iterator OI=CE->op_begin(); OI != CE->op_end();
>> ++OI) {
>> + if (InRangeOp && (OI - CE->op_begin()) == *InRangeOp)
>> + Out << "inrange ";
>> TypePrinter.print((*OI)->getType(), Out);
>> Out << ' ';
>> WriteAsOperandInternal(Out, *OI, &TypePrinter, Machine, Context);
>>
>> Modified: llvm/trunk/lib/IR/ConstantFold.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ConstantFold.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/IR/ConstantFold.cpp (original)
>> +++ llvm/trunk/lib/IR/ConstantFold.cpp Thu Nov 10 16:34:55 2016
>> @@ -545,7 +545,10 @@ Constant *llvm::ConstantFoldCastInstruct
>> } else if (CE->getOpcode() == Instruction::GetElementPtr &&
>> // Do not fold addrspacecast (gep 0, .., 0). It might make
>> the
>> // addrspacecast uncanonicalized.
>> - opc != Instruction::AddrSpaceCast) {
>> + opc != Instruction::AddrSpaceCast &&
>> + // Do not fold bitcast (gep) with inrange index, as this
>> loses
>> + // information.
>> + !cast<GEPOperator>(CE)->getInRangeIndex().hasValue()) {
>> // If all of the indexes in the GEP are null values, there is no
>> pointer
>> // adjustment going on. We might as well cast the source pointer.
>> bool isAllNull = true;
>> @@ -2046,10 +2049,10 @@ static bool isIndexInRangeOfSequentialTy
>> return true;
>> }
>>
>> -template<typename IndexTy>
>> -static Constant *ConstantFoldGetElementPtrImpl(Type *PointeeTy, Constant
>> *C,
>> - bool inBounds,
>> - ArrayRef<IndexTy> Idxs) {
>> +Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
>> + bool InBounds,
>> + Optional<unsigned>
>> InRangeIndex,
>> + ArrayRef<Value *> Idxs) {
>> if (Idxs.empty()) return C;
>> Constant *Idx0 = cast<Constant>(Idxs[0]);
>> if ((Idxs.size() == 1 && Idx0->isNullValue()))
>> @@ -2146,9 +2149,18 @@ static Constant *ConstantFoldGetElementP
>>
>> NewIndices.push_back(Combined);
>> NewIndices.append(Idxs.begin() + 1, Idxs.end());
>> +
>> + // The combined GEP normally inherits its index inrange
>> attribute from
>> + // the inner GEP, but if the inner GEP's last index was adjusted
>> by the
>> + // outer GEP, any inbounds attribute on that index is
>> invalidated.
>> + Optional<unsigned> IRIndex =
>> cast<GEPOperator>(CE)->getInRangeIndex();
>> + if (IRIndex && *IRIndex == CE->getNumOperands() - 2 &&
>> !Idx0->isNullValue())
>> + IRIndex = None;
>> +
>> return ConstantExpr::getGetElementPtr(
>> cast<GEPOperator>(CE)->getSourceElementType(),
>> CE->getOperand(0),
>> - NewIndices, inBounds &&
>> cast<GEPOperator>(CE)->isInBounds());
>> + NewIndices, InBounds && cast<GEPOperator>(CE)->isInBounds(),
>> + IRIndex);
>> }
>> }
>>
>> @@ -2173,8 +2185,9 @@ static Constant *ConstantFoldGetElementP
>> if (SrcArrayTy && DstArrayTy
>> && SrcArrayTy->getElementType() == DstArrayTy->getElementType()
>> && SrcPtrTy->getAddressSpace() == DstPtrTy->getAddressSpace())
>> - return ConstantExpr::getGetElementPtr(
>> - SrcArrayTy, (Constant *)CE->getOperand(0), Idxs,
>> inBounds);
>> + return ConstantExpr::getGetElementPtr(SrcArrayTy,
>> + (Constant
>> *)CE->getOperand(0),
>> + Idxs, InBounds,
>> InRangeIndex);
>> }
>> }
>> }
>> @@ -2194,6 +2207,12 @@ static Constant *ConstantFoldGetElementP
>> Unknown = true;
>> continue;
>> }
>> + if (InRangeIndex && i == *InRangeIndex + 1) {
>> + // If an index is marked inrange, we cannot apply this
>> canonicalization to
>> + // the following index, as that will cause the inrange index to
>> point to
>> + // the wrong element.
>> + continue;
>> + }
>> if (isa<StructType>(Ty)) {
>> // The verify makes sure that GEPs into a struct are in range.
>> continue;
>> @@ -2256,27 +2275,17 @@ static Constant *ConstantFoldGetElementP
>> if (!NewIdxs.empty()) {
>> for (unsigned i = 0, e = Idxs.size(); i != e; ++i)
>> if (!NewIdxs[i]) NewIdxs[i] = cast<Constant>(Idxs[i]);
>> - return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs,
>> inBounds);
>> + return ConstantExpr::getGetElementPtr(PointeeTy, C, NewIdxs,
>> InBounds,
>> + InRangeIndex);
>> }
>>
>> // If all indices are known integers and normalized, we can do a simple
>> // check for the "inbounds" property.
>> - if (!Unknown && !inBounds)
>> + if (!Unknown && !InBounds)
>> if (auto *GV = dyn_cast<GlobalVariable>(C))
>> if (!GV->hasExternalWeakLinkage() && isInBoundsIndices(Idxs))
>> - return ConstantExpr::getInBoundsGetElementPtr(PointeeTy, C,
>> Idxs);
>> + return ConstantExpr::getGetElementPtr(PointeeTy, C, Idxs,
>> + /*InBounds=*/true,
>> InRangeIndex);
>>
>> return nullptr;
>> }
>> -
>> -Constant *llvm::ConstantFoldGetElementPtr(Type *Ty, Constant *C,
>> - bool inBounds,
>> - ArrayRef<Constant *> Idxs) {
>> - return ConstantFoldGetElementPtrImpl(Ty, C, inBounds, Idxs);
>> -}
>> -
>> -Constant *llvm::ConstantFoldGetElementPtr(Type *Ty, Constant *C,
>> - bool inBounds,
>> - ArrayRef<Value *> Idxs) {
>> - return ConstantFoldGetElementPtrImpl(Ty, C, inBounds, Idxs);
>> -}
>>
>> Modified: llvm/trunk/lib/IR/ConstantFold.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ConstantFold.h?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/IR/ConstantFold.h (original)
>> +++ llvm/trunk/lib/IR/ConstantFold.h Thu Nov 10 16:34:55 2016
>> @@ -19,6 +19,8 @@
>> #ifndef LLVM_LIB_IR_CONSTANTFOLD_H
>> #define LLVM_LIB_IR_CONSTANTFOLD_H
>>
>> +#include "llvm/ADT/Optional.h"
>> +
>> namespace llvm {
>> template <typename T> class ArrayRef;
>> class Value;
>> @@ -46,9 +48,8 @@ template <typename T> class ArrayRef;
>> Constant *V2);
>> Constant *ConstantFoldCompareInstruction(unsigned short predicate,
>> Constant *C1, Constant *C2);
>> - Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool
>> inBounds,
>> - ArrayRef<Constant *> Idxs);
>> - Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool
>> inBounds,
>> + Constant *ConstantFoldGetElementPtr(Type *Ty, Constant *C, bool
>> InBounds,
>> + Optional<unsigned> InRangeIndex,
>> ArrayRef<Value *> Idxs);
>> } // End llvm namespace
>>
>>
>> Modified: llvm/trunk/lib/IR/Constants.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Constants.cpp?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/IR/Constants.cpp (original)
>> +++ llvm/trunk/lib/IR/Constants.cpp Thu Nov 10 16:34:55 2016
>> @@ -1167,7 +1167,7 @@ Constant *ConstantExpr::getWithOperands(
>> assert(SrcTy || (Ops[0]->getType() == getOperand(0)->getType()));
>> return ConstantExpr::getGetElementPtr(
>> SrcTy ? SrcTy : GEPO->getSourceElementType(), Ops[0], Ops.slice(1),
>> - GEPO->isInBounds(), OnlyIfReducedTy);
>> + GEPO->isInBounds(), GEPO->getInRangeIndex(), OnlyIfReducedTy);
>> }
>> case Instruction::ICmp:
>> case Instruction::FCmp:
>> @@ -1893,6 +1893,7 @@ Constant *ConstantExpr::getSelect(Consta
>>
>> Constant *ConstantExpr::getGetElementPtr(Type *Ty, Constant *C,
>> ArrayRef<Value *> Idxs, bool
>> InBounds,
>> + Optional<unsigned>
>> InRangeIndex,
>> Type *OnlyIfReducedTy) {
>> if (!Ty)
>> Ty =
>> cast<PointerType>(C->getType()->getScalarType())->getElementType();
>> @@ -1901,7 +1902,8 @@ Constant *ConstantExpr::getGetElementPtr
>> Ty ==
>> cast<PointerType>(C->getType()->getScalarType())->getContainedType(0u));
>>
>> - if (Constant *FC = ConstantFoldGetElementPtr(Ty, C, InBounds, Idxs))
>> + if (Constant *FC =
>> + ConstantFoldGetElementPtr(Ty, C, InBounds, InRangeIndex,
>> Idxs))
>> return FC; // Fold a few common cases.
>>
>> // Get the result type of the getelementptr!
>> @@ -1937,9 +1939,12 @@ Constant *ConstantExpr::getGetElementPtr
>> Idx = ConstantVector::getSplat(NumVecElts, Idx);
>> ArgVec.push_back(Idx);
>> }
>> +
>> + unsigned SubClassOptionalData = InBounds ? GEPOperator::IsInBounds :
>> 0;
>> + if (InRangeIndex && *InRangeIndex < 63)
>> + SubClassOptionalData |= (*InRangeIndex + 1) << 1;
>> const ConstantExprKeyType Key(Instruction::GetElementPtr, ArgVec, 0,
>> - InBounds ? GEPOperator::IsInBounds : 0,
>> None,
>> - Ty);
>> + SubClassOptionalData, None, Ty);
>>
>> LLVMContextImpl *pImpl = C->getContext().pImpl;
>> return pImpl->ExprConstants.getOrCreate(ReqTy, Key);
>>
>> Added: llvm/trunk/test/Analysis/ConstantFolding/gep.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ConstantFolding/gep.ll?rev=286514&view=auto
>> ==============================================================================
>> --- llvm/trunk/test/Analysis/ConstantFolding/gep.ll (added)
>> +++ llvm/trunk/test/Analysis/ConstantFolding/gep.ll Thu Nov 10 16:34:55
>> 2016
>> @@ -0,0 +1,30 @@
>> +; RUN: opt -instcombine -S -o - %s | FileCheck %s
>> +; Tests that we preserve the inrange attribute on indices where
>> possible.
>> +
>> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
>> +target triple = "x86_64-unknown-linux-gnu"
>> +
>> +%struct.A = type { i32 (...)** }
>> +
>> + at vt = external global [3 x i8*]
>> +
>> +; CHECK: define i32 (...)* @f0()
>> +define i32 (...)* @f0() {
>> + ; CHECK-NEXT: load i32 (...)*, i32 (...)** bitcast (i8** getelementptr
>> inbounds ([3 x i8*], [3 x i8*]* @vt, inrange i64 0, i64 2) to i32
>> (...)**)
>> + %load = load i32 (...)*, i32 (...)** getelementptr (i32 (...)*, i32
>> (...)** bitcast (i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @vt,
>> inrange i64 0, i64 1) to i32 (...)**), i64 1)
>> + ret i32 (...)* %load
>> +}
>> +
>> +; CHECK: define i32 (...)* @f1()
>> +define i32 (...)* @f1() {
>> + ; CHECK-NEXT: load i32 (...)*, i32 (...)** bitcast (i8** getelementptr
>> inbounds ([3 x i8*], [3 x i8*]* @vt, i64 0, i64 2) to i32 (...)**)
>> + %load = load i32 (...)*, i32 (...)** getelementptr (i32 (...)*, i32
>> (...)** bitcast (i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @vt,
>> i64 0, inrange i64 1) to i32 (...)**), i64 1)
>> + ret i32 (...)* %load
>> +}
>> +
>> +; CHECK: define i32 (...)* @f2()
>> +define i32 (...)* @f2() {
>> + ; CHECK-NEXT: load i32 (...)*, i32 (...)** bitcast (i8** getelementptr
>> ([3 x i8*], [3 x i8*]* @vt, i64 1, i64 1) to i32 (...)**)
>> + %load = load i32 (...)*, i32 (...)** getelementptr (i32 (...)*, i32
>> (...)** bitcast (i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @vt,
>> i64 0, inrange i64 1) to i32 (...)**), i64 3)
>> + ret i32 (...)* %load
>> +}
>>
>> Modified: llvm/trunk/test/Assembler/getelementptr.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/getelementptr.ll?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/test/Assembler/getelementptr.ll (original)
>> +++ llvm/trunk/test/Assembler/getelementptr.ll Thu Nov 10 16:34:55 2016
>> @@ -23,6 +23,25 @@
>> @PR23753_b = global i8* getelementptr (i8, i8* @PR23753_a, i64 ptrtoint
>> (i8* @PR23753_a to i64))
>> ; CHECK: @PR23753_b = global i8* getelementptr (i8, i8* @PR23753_a, i64
>> ptrtoint (i8* @PR23753_a to i64))
>>
>> +; Verify that inrange on an index inhibits over-indexed getelementptr
>> folding.
>> +
>> + at nestedarray = global [2 x [4 x i8*]] zeroinitializer
>> +
>> +; CHECK: @nestedarray.1 = alias i8*, getelementptr inbounds ([2 x [4 x
>> i8*]], [2 x [4 x i8*]]* @nestedarray, inrange i32 0, i64 1, i32 0)
>> + at nestedarray.1 = alias i8*, getelementptr inbounds ([2 x [4 x i8*]], [2
>> x [4 x i8*]]* @nestedarray, inrange i32 0, i32 0, i32 4)
>> +
>> +; CHECK: @nestedarray.2 = alias i8*, getelementptr inbounds ([2 x [4 x
>> i8*]], [2 x [4 x i8*]]* @nestedarray, i32 0, inrange i32 0, i32 4)
>> + at nestedarray.2 = alias i8*, getelementptr inbounds ([2 x [4 x i8*]], [2
>> x [4 x i8*]]* @nestedarray, i32 0, inrange i32 0, i32 4)
>> +
>> +; CHECK: @nestedarray.3 = alias i8*, getelementptr inbounds ([2 x [4 x
>> i8*]], [2 x [4 x i8*]]* @nestedarray, i32 0, inrange i32 0, i32 0)
>> + at nestedarray.3 = alias i8*, getelementptr inbounds ([4 x i8*], [4 x
>> i8*]* getelementptr inbounds ([2 x [4 x i8*]], [2 x [4 x i8*]]*
>> @nestedarray, i32 0, inrange i32 0), i32 0, i32 0)
>> +
>> +; CHECK: @nestedarray.4 = alias i8*, getelementptr inbounds ([2 x [4 x
>> i8*]], [2 x [4 x i8*]]* @nestedarray, i32 0, i32 1, i32 0)
>> + at nestedarray.4 = alias i8*, getelementptr inbounds ([4 x i8*], [4 x
>> i8*]* getelementptr inbounds ([2 x [4 x i8*]], [2 x [4 x i8*]]*
>> @nestedarray, i32 0, inrange i32 0), i32 1, i32 0)
>> +
>> +; CHECK: @nestedarray.5 = alias i8*, getelementptr inbounds ([2 x [4 x
>> i8*]], [2 x [4 x i8*]]* @nestedarray, inrange i32 0, i32 1, i32 0)
>> + at nestedarray.5 = alias i8*, getelementptr inbounds ([4 x i8*], [4 x
>> i8*]* getelementptr inbounds ([2 x [4 x i8*]], [2 x [4 x i8*]]*
>> @nestedarray, inrange i32 0, i32 0), i32 1, i32 0)
>> +
>> ; See if i92 indices work too.
>> define i32 *@test({i32, i32}* %t, i92 %n) {
>> ; CHECK: @test
>>
>> Modified: llvm/trunk/test/Bitcode/compatibility.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/compatibility.ll?rev=286514&r1=286513&r2=286514&view=diff
>> ==============================================================================
>> --- llvm/trunk/test/Bitcode/compatibility.ll (original)
>> +++ llvm/trunk/test/Bitcode/compatibility.ll Thu Nov 10 16:34:55 2016
>> @@ -1611,6 +1611,13 @@ normal:
>> declare void @f.writeonly() writeonly
>> ; CHECK: declare void @f.writeonly() #39
>>
>> +;; Constant Expressions
>> +
>> +define i8** @constexpr() {
>> + ; CHECK: ret i8** getelementptr inbounds ({ [4 x i8*], [4 x i8*] },
>> { [4 x i8*], [4 x i8*] }* null, i32 0, inrange i32 1, i32 2)
>> + ret i8** getelementptr inbounds ({ [4 x i8*], [4 x i8*] }, { [4 x
>> i8*], [4 x i8*] }* null, i32 0, inrange i32 1, i32 2)
>> +}
>> +
>> ; CHECK: attributes #0 = { alignstack=4 }
>> ; CHECK: attributes #1 = { alignstack=8 }
>> ; CHECK: attributes #2 = { alwaysinline }
More information about the llvm-commits
mailing list