[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