From: Dan Gohman Date: Mon, 27 Jul 2009 21:53:46 +0000 (+0000) Subject: Add a new keyword 'inbounds' for use with getelementptr. See the X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=dd8004dc73d091ccb3927dbbc3b41639a3738ae3;p=oota-llvm.git Add a new keyword 'inbounds' for use with getelementptr. See the LangRef.html changes for details. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@77259 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LangRef.html b/docs/LangRef.html index 1f9f80d6d43..adc5d9a143f 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -2091,6 +2091,7 @@ Classifications instruction.
getelementptr ( CSTPTR, IDX0, IDX1, ... )
+
getelementptr inbounds ( CSTPTR, IDX0, IDX1, ... )
Perform the getelementptr operation on constants. As with the getelementptr instruction, the index list may have zero or more indexes, which are @@ -3902,6 +3903,7 @@ Instruction
Syntax:
   <result> = getelementptr <pty>* <ptrval>{, <ty> <idx>}*
+  <result> = getelementptr inbounds <pty>* <ptrval>{, <ty> <idx>}*
 
Overview:
@@ -3990,6 +3992,20 @@ entry: } +

If the inbounds keyword is present, the result value of the + getelementptr is undefined if the base pointer is not pointing + into an allocated object, or if any of the addresses formed by successive + addition of the offsets implied by the indices to the base address is + outside of the allocated object into which the base pointer points.

+ +

If the inbounds keyword is not present, the offsets are added to + the base address with silently-wrapping two's complement arithmetic, and + the result value of the getelementptr may be outside the object + pointed to by the base pointer. The result value may not necessarily be + used to access memory though, even if it happens to point into allocated + storage. See the Pointer Aliasing Rules + section for more information.

+

The getelementptr instruction is often confusing. For some more insight into how it works, see the getelementptr FAQ.

diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 3d8c2469147..38f152dcce3 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -132,7 +132,8 @@ namespace bitc { CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval] CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred] CST_CODE_INLINEASM = 18, // INLINEASM: [sideeffect,asmstr,conststr] - CST_CODE_CE_SHUFVEC_EX = 19 // SHUFVEC_EX: [opty, opval, opval, opval] + CST_CODE_CE_SHUFVEC_EX = 19, // SHUFVEC_EX: [opty, opval, opval, opval] + CST_CODE_CE_INBOUNDS_GEP = 20 // INBOUNDS_GEP: [n x operands] }; /// CastOpcodes - These are values used in the bitcode files to encode which @@ -229,7 +230,8 @@ namespace bitc { // support legacy vicmp/vfcmp instructions. FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred] // new select on i1 or [N x i1] - FUNC_CODE_INST_VSELECT = 29 // VSELECT: [ty,opval,opval,predty,pred] + FUNC_CODE_INST_VSELECT = 29, // VSELECT: [ty,opval,opval,predty,pred] + FUNC_CODE_INST_INBOUNDS_GEP = 30 // INBOUNDS_GEP: [n x operands] }; } // End bitc namespace } // End llvm namespace diff --git a/include/llvm/Operator.h b/include/llvm/Operator.h index 932c2ace8c4..c62164bcbce 100644 --- a/include/llvm/Operator.h +++ b/include/llvm/Operator.h @@ -181,6 +181,15 @@ public: class GEPOperator : public Operator { public: + /// isInBounds - Test whether this is an inbounds GEP, as defined + /// by LangRef.html. + bool isInBounds() const { + return SubclassOptionalData & (1 << 0); + } + void setIsInBounds(bool B) { + SubclassOptionalData = (SubclassOptionalData & ~(1 << 0)) | (B << 0); + } + 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/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index e047002c138..c9b28212435 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -504,6 +504,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(nuw); KEYWORD(nsw); KEYWORD(exact); + KEYWORD(inbounds); KEYWORD(align); KEYWORD(addrspace); KEYWORD(section); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index f9db40915ae..adcd79f40a3 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -457,7 +457,7 @@ bool LLParser::ParseStandaloneMetadata() { /// Aliasee /// ::= TypeAndValue /// ::= 'bitcast' '(' TypeAndValue 'to' Type ')' -/// ::= 'getelementptr' '(' ... ')' +/// ::= 'getelementptr' 'inbounds'? '(' ... ')' /// /// Everything through visibility has already been parsed. /// @@ -2039,7 +2039,11 @@ bool LLParser::ParseValID(ValID &ID) { case lltok::kw_select: { unsigned Opc = Lex.getUIntVal(); SmallVector Elts; + bool InBounds = false; Lex.Lex(); + if (Opc == Instruction::GetElementPtr) + if (EatIfPresent(lltok::kw_inbounds)) + InBounds = true; if (ParseToken(lltok::lparen, "expected '(' in constantexpr") || ParseGlobalValueVector(Elts) || ParseToken(lltok::rparen, "expected ')' in constantexpr")) @@ -2055,6 +2059,8 @@ bool LLParser::ParseValID(ValID &ID) { return Error(ID.Loc, "invalid indices for getelementptr"); ID.ConstantVal = Context.getConstantExprGetElementPtr(Elts[0], Elts.data() + 1, Elts.size() - 1); + if (InBounds) + cast(ID.ConstantVal)->setIsInBounds(true); } else if (Opc == Instruction::Select) { if (Elts.size() != 3) return Error(ID.Loc, "expected three operands to select"); @@ -3368,9 +3374,14 @@ bool LLParser::ParseGetResult(Instruction *&Inst, PerFunctionState &PFS) { } /// ParseGetElementPtr -/// ::= 'getelementptr' TypeAndValue (',' TypeAndValue)* +/// ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)* bool LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) { Value *Ptr, *Val; LocTy Loc, EltLoc; + bool InBounds = false; + + if (EatIfPresent(lltok::kw_inbounds)) + InBounds = true; + if (ParseTypeAndValue(Ptr, Loc, PFS)) return true; if (!isa(Ptr->getType())) @@ -3388,6 +3399,8 @@ bool LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) { Indices.begin(), Indices.end())) return Error(Loc, "invalid getelementptr indices"); Inst = GetElementPtrInst::Create(Ptr, Indices.begin(), Indices.end()); + if (InBounds) + cast(Inst)->setIsInBounds(true); return false; } diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index c8cdff6bf61..75cc1db8ad9 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -54,6 +54,7 @@ namespace lltok { kw_nuw, kw_nsw, kw_exact, + kw_inbounds, kw_align, kw_addrspace, kw_section, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 687cae9ecf6..e1cc1a3afba 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -997,6 +997,7 @@ bool BitcodeReader::ParseConstants() { } break; } + case bitc::CST_CODE_CE_INBOUNDS_GEP: case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands] if (Record.size() & 1) return Error("Invalid CE_GEP record"); SmallVector Elts; @@ -1007,6 +1008,8 @@ bool BitcodeReader::ParseConstants() { } V = Context.getConstantExprGetElementPtr(Elts[0], &Elts[1], Elts.size()-1); + if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP) + cast(V)->setIsInBounds(true); break; } case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#] @@ -1556,6 +1559,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy); break; } + case bitc::FUNC_CODE_INST_INBOUNDS_GEP: case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands] unsigned OpNum = 0; Value *BasePtr; @@ -1571,6 +1575,8 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } I = GetElementPtrInst::Create(BasePtr, GEPIdx.begin(), GEPIdx.end()); + if (BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP) + cast(I)->setIsInBounds(true); break; } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index b3124204903..fd09edec942 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -706,6 +706,8 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, break; case Instruction::GetElementPtr: Code = bitc::CST_CODE_CE_GEP; + if (cast(C)->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))); @@ -829,6 +831,8 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, case Instruction::GetElementPtr: Code = bitc::FUNC_CODE_INST_GEP; + if (cast(&I)->isInBounds()) + Code = bitc::FUNC_CODE_INST_INBOUNDS_GEP; for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) PushValueAndType(I.getOperand(i), InstID, Vals, VE); break; diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 11d238eba25..8242d8155b1 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -854,6 +854,9 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { } else if (const SDivOperator *Div = dyn_cast(U)) { if (Div->isExact()) Out << " exact"; + } else if (const GEPOperator *GEP = dyn_cast(U)) { + if (GEP->isInBounds()) + Out << " inbounds"; } } diff --git a/test/Assembler/flags-plain.ll b/test/Assembler/flags-plain.ll index 148d02fc062..bf3d5d891f5 100644 --- a/test/Assembler/flags-plain.ll +++ b/test/Assembler/flags-plain.ll @@ -21,3 +21,8 @@ define i64 @sdiv_plain_ce() { ; CHECK: ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91) ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91) } + +define i64* @gep_plain_ce() { +; CHECK: ret i64* getelementptr (i64* @addr, i64 171) + ret i64* getelementptr (i64* @addr, i64 171) +} diff --git a/test/Assembler/flags.ll b/test/Assembler/flags.ll index 4efb1cdb238..981a4e592ce 100644 --- a/test/Assembler/flags.ll +++ b/test/Assembler/flags.ll @@ -104,6 +104,18 @@ define i64 @sdiv_plain(i64 %x, i64 %y) { ret i64 %z } +define i64* @gep_nw(i64* %p, i64 %x) { +; CHECK: %z = getelementptr inbounds i64* %p, i64 %x + %z = getelementptr inbounds i64* %p, i64 %x + ret i64* %z +} + +define i64* @gep_plain(i64* %p, i64 %x) { +; CHECK: %z = getelementptr i64* %p, i64 %x + %z = getelementptr i64* %p, i64 %x + ret i64* %z +} + define i64 @add_both_ce() { ; CHECK: ret i64 add nuw nsw (i64 ptrtoint (i64* @addr to i64), i64 91) ret i64 add nsw nuw (i64 ptrtoint (i64* @addr to i64), i64 91) @@ -123,3 +135,10 @@ define i64 @sdiv_exact_ce() { ; CHECK: ret i64 sdiv exact (i64 ptrtoint (i64* @addr to i64), i64 91) ret i64 sdiv exact (i64 ptrtoint (i64* @addr to i64), i64 91) } + +define i64* @gep_nw_ce() { +; CHECK: ret i64* getelementptr inbounds (i64* @addr, i64 171) + ret i64* getelementptr inbounds (i64* @addr, i64 171) +} + +