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
This commit is contained in:
Dan Gohman 2009-07-27 21:53:46 +00:00
parent 9a7e2ccf57
commit dd8004dc73
11 changed files with 83 additions and 4 deletions

View File

@ -2091,6 +2091,7 @@ Classifications</a> </div>
instruction</a>.</dd>
<dt><b><tt>getelementptr ( CSTPTR, IDX0, IDX1, ... )</tt></b></dt>
<dt><b><tt>getelementptr inbounds ( CSTPTR, IDX0, IDX1, ... )</tt></b></dt>
<dd>Perform the <a href="#i_getelementptr">getelementptr operation</a> on
constants. As with the <a href="#i_getelementptr">getelementptr</a>
instruction, the index list may have zero or more indexes, which are
@ -3902,6 +3903,7 @@ Instruction</a> </div>
<h5>Syntax:</h5>
<pre>
&lt;result&gt; = getelementptr &lt;pty&gt;* &lt;ptrval&gt;{, &lt;ty&gt; &lt;idx&gt;}*
&lt;result&gt; = getelementptr inbounds &lt;pty&gt;* &lt;ptrval&gt;{, &lt;ty&gt; &lt;idx&gt;}*
</pre>
<h5>Overview:</h5>
@ -3990,6 +3992,20 @@ entry:
}
</pre>
<p>If the <tt>inbounds</tt> keyword is present, the result value of the
<tt>getelementptr</tt> 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.</p>
<p>If the <tt>inbounds</tt> 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 <tt>getelementptr</tt> 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 <a href="#pointeraliasing">Pointer Aliasing Rules</a>
section for more information.</p>
<p>The getelementptr instruction is often confusing. For some more insight into
how it works, see <a href="GetElementPtr.html">the getelementptr FAQ</a>.</p>

View File

@ -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

View File

@ -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(); }

View File

@ -504,6 +504,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(nuw);
KEYWORD(nsw);
KEYWORD(exact);
KEYWORD(inbounds);
KEYWORD(align);
KEYWORD(addrspace);
KEYWORD(section);

View File

@ -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<Constant*, 16> 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<GEPOperator>(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<PointerType>(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<GEPOperator>(Inst)->setIsInBounds(true);
return false;
}

View File

@ -54,6 +54,7 @@ namespace lltok {
kw_nuw,
kw_nsw,
kw_exact,
kw_inbounds,
kw_align,
kw_addrspace,
kw_section,

View File

@ -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<Constant*, 16> 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<GEPOperator>(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<GEPOperator>(I)->setIsInBounds(true);
break;
}

View File

@ -706,6 +706,8 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
break;
case Instruction::GetElementPtr:
Code = bitc::CST_CODE_CE_GEP;
if (cast<GEPOperator>(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<GEPOperator>(&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;

View File

@ -854,6 +854,9 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
} else if (const SDivOperator *Div = dyn_cast<SDivOperator>(U)) {
if (Div->isExact())
Out << " exact";
} else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
if (GEP->isInBounds())
Out << " inbounds";
}
}

View File

@ -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)
}

View File

@ -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)
}