mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-15 06:29:05 +00:00
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:
@@ -2091,6 +2091,7 @@ Classifications</a> </div>
|
|||||||
instruction</a>.</dd>
|
instruction</a>.</dd>
|
||||||
|
|
||||||
<dt><b><tt>getelementptr ( CSTPTR, IDX0, IDX1, ... )</tt></b></dt>
|
<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
|
<dd>Perform the <a href="#i_getelementptr">getelementptr operation</a> on
|
||||||
constants. As with the <a href="#i_getelementptr">getelementptr</a>
|
constants. As with the <a href="#i_getelementptr">getelementptr</a>
|
||||||
instruction, the index list may have zero or more indexes, which are
|
instruction, the index list may have zero or more indexes, which are
|
||||||
@@ -3902,6 +3903,7 @@ Instruction</a> </div>
|
|||||||
<h5>Syntax:</h5>
|
<h5>Syntax:</h5>
|
||||||
<pre>
|
<pre>
|
||||||
<result> = getelementptr <pty>* <ptrval>{, <ty> <idx>}*
|
<result> = getelementptr <pty>* <ptrval>{, <ty> <idx>}*
|
||||||
|
<result> = getelementptr inbounds <pty>* <ptrval>{, <ty> <idx>}*
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h5>Overview:</h5>
|
<h5>Overview:</h5>
|
||||||
@@ -3990,6 +3992,20 @@ entry:
|
|||||||
}
|
}
|
||||||
</pre>
|
</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
|
<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>
|
how it works, see <a href="GetElementPtr.html">the getelementptr FAQ</a>.</p>
|
||||||
|
|
||||||
|
@@ -132,7 +132,8 @@ namespace bitc {
|
|||||||
CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval]
|
CST_CODE_CE_SHUFFLEVEC = 16, // CE_SHUFFLEVEC: [opval, opval, opval]
|
||||||
CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred]
|
CST_CODE_CE_CMP = 17, // CE_CMP: [opty, opval, opval, pred]
|
||||||
CST_CODE_INLINEASM = 18, // INLINEASM: [sideeffect,asmstr,conststr]
|
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
|
/// CastOpcodes - These are values used in the bitcode files to encode which
|
||||||
@@ -229,7 +230,8 @@ namespace bitc {
|
|||||||
// support legacy vicmp/vfcmp instructions.
|
// support legacy vicmp/vfcmp instructions.
|
||||||
FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred]
|
FUNC_CODE_INST_CMP2 = 28, // CMP2: [opty, opval, opval, pred]
|
||||||
// new select on i1 or [N x i1]
|
// 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 bitc namespace
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
@@ -181,6 +181,15 @@ public:
|
|||||||
|
|
||||||
class GEPOperator : public Operator {
|
class GEPOperator : public Operator {
|
||||||
public:
|
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 op_iterator idx_begin() { return op_begin()+1; }
|
||||||
inline const_op_iterator idx_begin() const { return op_begin()+1; }
|
inline const_op_iterator idx_begin() const { return op_begin()+1; }
|
||||||
inline op_iterator idx_end() { return op_end(); }
|
inline op_iterator idx_end() { return op_end(); }
|
||||||
|
@@ -504,6 +504,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
|||||||
KEYWORD(nuw);
|
KEYWORD(nuw);
|
||||||
KEYWORD(nsw);
|
KEYWORD(nsw);
|
||||||
KEYWORD(exact);
|
KEYWORD(exact);
|
||||||
|
KEYWORD(inbounds);
|
||||||
KEYWORD(align);
|
KEYWORD(align);
|
||||||
KEYWORD(addrspace);
|
KEYWORD(addrspace);
|
||||||
KEYWORD(section);
|
KEYWORD(section);
|
||||||
|
@@ -457,7 +457,7 @@ bool LLParser::ParseStandaloneMetadata() {
|
|||||||
/// Aliasee
|
/// Aliasee
|
||||||
/// ::= TypeAndValue
|
/// ::= TypeAndValue
|
||||||
/// ::= 'bitcast' '(' TypeAndValue 'to' Type ')'
|
/// ::= 'bitcast' '(' TypeAndValue 'to' Type ')'
|
||||||
/// ::= 'getelementptr' '(' ... ')'
|
/// ::= 'getelementptr' 'inbounds'? '(' ... ')'
|
||||||
///
|
///
|
||||||
/// Everything through visibility has already been parsed.
|
/// Everything through visibility has already been parsed.
|
||||||
///
|
///
|
||||||
@@ -2039,7 +2039,11 @@ bool LLParser::ParseValID(ValID &ID) {
|
|||||||
case lltok::kw_select: {
|
case lltok::kw_select: {
|
||||||
unsigned Opc = Lex.getUIntVal();
|
unsigned Opc = Lex.getUIntVal();
|
||||||
SmallVector<Constant*, 16> Elts;
|
SmallVector<Constant*, 16> Elts;
|
||||||
|
bool InBounds = false;
|
||||||
Lex.Lex();
|
Lex.Lex();
|
||||||
|
if (Opc == Instruction::GetElementPtr)
|
||||||
|
if (EatIfPresent(lltok::kw_inbounds))
|
||||||
|
InBounds = true;
|
||||||
if (ParseToken(lltok::lparen, "expected '(' in constantexpr") ||
|
if (ParseToken(lltok::lparen, "expected '(' in constantexpr") ||
|
||||||
ParseGlobalValueVector(Elts) ||
|
ParseGlobalValueVector(Elts) ||
|
||||||
ParseToken(lltok::rparen, "expected ')' in constantexpr"))
|
ParseToken(lltok::rparen, "expected ')' in constantexpr"))
|
||||||
@@ -2055,6 +2059,8 @@ bool LLParser::ParseValID(ValID &ID) {
|
|||||||
return Error(ID.Loc, "invalid indices for getelementptr");
|
return Error(ID.Loc, "invalid indices for getelementptr");
|
||||||
ID.ConstantVal = Context.getConstantExprGetElementPtr(Elts[0],
|
ID.ConstantVal = Context.getConstantExprGetElementPtr(Elts[0],
|
||||||
Elts.data() + 1, Elts.size() - 1);
|
Elts.data() + 1, Elts.size() - 1);
|
||||||
|
if (InBounds)
|
||||||
|
cast<GEPOperator>(ID.ConstantVal)->setIsInBounds(true);
|
||||||
} else if (Opc == Instruction::Select) {
|
} else if (Opc == Instruction::Select) {
|
||||||
if (Elts.size() != 3)
|
if (Elts.size() != 3)
|
||||||
return Error(ID.Loc, "expected three operands to select");
|
return Error(ID.Loc, "expected three operands to select");
|
||||||
@@ -3368,9 +3374,14 @@ bool LLParser::ParseGetResult(Instruction *&Inst, PerFunctionState &PFS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// ParseGetElementPtr
|
/// ParseGetElementPtr
|
||||||
/// ::= 'getelementptr' TypeAndValue (',' TypeAndValue)*
|
/// ::= 'getelementptr' 'inbounds'? TypeAndValue (',' TypeAndValue)*
|
||||||
bool LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
bool LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
||||||
Value *Ptr, *Val; LocTy Loc, EltLoc;
|
Value *Ptr, *Val; LocTy Loc, EltLoc;
|
||||||
|
bool InBounds = false;
|
||||||
|
|
||||||
|
if (EatIfPresent(lltok::kw_inbounds))
|
||||||
|
InBounds = true;
|
||||||
|
|
||||||
if (ParseTypeAndValue(Ptr, Loc, PFS)) return true;
|
if (ParseTypeAndValue(Ptr, Loc, PFS)) return true;
|
||||||
|
|
||||||
if (!isa<PointerType>(Ptr->getType()))
|
if (!isa<PointerType>(Ptr->getType()))
|
||||||
@@ -3388,6 +3399,8 @@ bool LLParser::ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS) {
|
|||||||
Indices.begin(), Indices.end()))
|
Indices.begin(), Indices.end()))
|
||||||
return Error(Loc, "invalid getelementptr indices");
|
return Error(Loc, "invalid getelementptr indices");
|
||||||
Inst = GetElementPtrInst::Create(Ptr, Indices.begin(), Indices.end());
|
Inst = GetElementPtrInst::Create(Ptr, Indices.begin(), Indices.end());
|
||||||
|
if (InBounds)
|
||||||
|
cast<GEPOperator>(Inst)->setIsInBounds(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -54,6 +54,7 @@ namespace lltok {
|
|||||||
kw_nuw,
|
kw_nuw,
|
||||||
kw_nsw,
|
kw_nsw,
|
||||||
kw_exact,
|
kw_exact,
|
||||||
|
kw_inbounds,
|
||||||
kw_align,
|
kw_align,
|
||||||
kw_addrspace,
|
kw_addrspace,
|
||||||
kw_section,
|
kw_section,
|
||||||
|
@@ -997,6 +997,7 @@ bool BitcodeReader::ParseConstants() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case bitc::CST_CODE_CE_INBOUNDS_GEP:
|
||||||
case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands]
|
case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands]
|
||||||
if (Record.size() & 1) return Error("Invalid CE_GEP record");
|
if (Record.size() & 1) return Error("Invalid CE_GEP record");
|
||||||
SmallVector<Constant*, 16> Elts;
|
SmallVector<Constant*, 16> Elts;
|
||||||
@@ -1007,6 +1008,8 @@ bool BitcodeReader::ParseConstants() {
|
|||||||
}
|
}
|
||||||
V = Context.getConstantExprGetElementPtr(Elts[0], &Elts[1],
|
V = Context.getConstantExprGetElementPtr(Elts[0], &Elts[1],
|
||||||
Elts.size()-1);
|
Elts.size()-1);
|
||||||
|
if (BitCode == bitc::CST_CODE_CE_INBOUNDS_GEP)
|
||||||
|
cast<GEPOperator>(V)->setIsInBounds(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#]
|
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);
|
I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case bitc::FUNC_CODE_INST_INBOUNDS_GEP:
|
||||||
case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands]
|
case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands]
|
||||||
unsigned OpNum = 0;
|
unsigned OpNum = 0;
|
||||||
Value *BasePtr;
|
Value *BasePtr;
|
||||||
@@ -1571,6 +1575,8 @@ bool BitcodeReader::ParseFunctionBody(Function *F) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
I = GetElementPtrInst::Create(BasePtr, GEPIdx.begin(), GEPIdx.end());
|
I = GetElementPtrInst::Create(BasePtr, GEPIdx.begin(), GEPIdx.end());
|
||||||
|
if (BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP)
|
||||||
|
cast<GEPOperator>(I)->setIsInBounds(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -706,6 +706,8 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal,
|
|||||||
break;
|
break;
|
||||||
case Instruction::GetElementPtr:
|
case Instruction::GetElementPtr:
|
||||||
Code = bitc::CST_CODE_CE_GEP;
|
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) {
|
for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) {
|
||||||
Record.push_back(VE.getTypeID(C->getOperand(i)->getType()));
|
Record.push_back(VE.getTypeID(C->getOperand(i)->getType()));
|
||||||
Record.push_back(VE.getValueID(C->getOperand(i)));
|
Record.push_back(VE.getValueID(C->getOperand(i)));
|
||||||
@@ -829,6 +831,8 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
|
|||||||
|
|
||||||
case Instruction::GetElementPtr:
|
case Instruction::GetElementPtr:
|
||||||
Code = bitc::FUNC_CODE_INST_GEP;
|
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)
|
for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i)
|
||||||
PushValueAndType(I.getOperand(i), InstID, Vals, VE);
|
PushValueAndType(I.getOperand(i), InstID, Vals, VE);
|
||||||
break;
|
break;
|
||||||
|
@@ -854,6 +854,9 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
|
|||||||
} else if (const SDivOperator *Div = dyn_cast<SDivOperator>(U)) {
|
} else if (const SDivOperator *Div = dyn_cast<SDivOperator>(U)) {
|
||||||
if (Div->isExact())
|
if (Div->isExact())
|
||||||
Out << " exact";
|
Out << " exact";
|
||||||
|
} else if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
|
||||||
|
if (GEP->isInBounds())
|
||||||
|
Out << " inbounds";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,3 +21,8 @@ define i64 @sdiv_plain_ce() {
|
|||||||
; CHECK: ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
|
; CHECK: ret i64 sdiv (i64 ptrtoint (i64* @addr to i64), i64 91)
|
||||||
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)
|
||||||
|
}
|
||||||
|
@@ -104,6 +104,18 @@ define i64 @sdiv_plain(i64 %x, i64 %y) {
|
|||||||
ret i64 %z
|
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() {
|
define i64 @add_both_ce() {
|
||||||
; CHECK: ret i64 add nuw nsw (i64 ptrtoint (i64* @addr to i64), i64 91)
|
; 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)
|
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)
|
; 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)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user