const Expr *Index = E->getIdx();
PrimType IndexT = classifyPrim(Index->getType());
- // Take pointer of LHS, add offset from RHS, narrow result.
+ // Take pointer of LHS, add offset from RHS.
// What's left on the stack after this is a pointer.
if (!this->visit(Base))
return false;
if (!this->visit(Index))
return false;
- if (!this->emitAddOffset(IndexT, E))
- return false;
-
- if (!this->emitNarrowPtr(E))
+ if (!this->emitArrayElemPtrPop(IndexT, E))
return false;
if (DiscardResult)
return false;
} else {
// Advance the pointer currently on the stack to the given
- // dimension and narrow().
- if (!this->emitDupPtr(Init))
- return false;
+ // dimension.
if (!this->emitConstUint32(ElementIndex, Init))
return false;
- if (!this->emitAddOffsetUint32(Init))
+ if (!this->emitArrayElemPtrUint32(Init))
return false;
- if (!this->emitNarrowPtr(Init))
- return false;
-
if (!visitInitializer(Init))
return false;
if (!this->emitPopPtr(Init))
for (size_t I = 0; I != Size; ++I) {
ArrayIndexScope<Emitter> IndexScope(this, I);
- if (!this->emitDupPtr(SubExpr)) // LHS
- return false;
-
if (ElemT) {
if (!this->visit(SubExpr))
return false;
if (!this->emitInitElem(*ElemT, I, Initializer))
return false;
} else {
- // Narrow to our array element and recurse into visitInitializer()
+ // Get to our array element and recurse into visitInitializer()
if (!this->emitConstUint64(I, SubExpr))
return false;
-
- if (!this->emitAddOffsetUint64(SubExpr))
- return false;
-
- if (!this->emitNarrowPtr(SubExpr))
+ if (!this->emitArrayElemPtrUint64(SubExpr))
return false;
-
if (!visitInitializer(SubExpr))
return false;
+ if (!this->emitPopPtr(Initializer))
+ return false;
}
-
- if (!this->emitPopPtr(Initializer))
- return false;
}
return true;
} else if (const auto *IVIE = dyn_cast<ImplicitValueInitExpr>(Initializer)) {
// FIXME(perf): We're calling the constructor once per array element here,
// in the old intepreter we had a special-case for trivial constructors.
for (size_t I = 0; I != NumElems; ++I) {
- if (!this->emitDupPtr(Initializer))
- return false;
if (!this->emitConstUint64(I, Initializer))
return false;
- if (!this->emitAddOffsetUint64(Initializer))
- return false;
- if (!this->emitNarrowPtr(Initializer))
+ if (!this->emitArrayElemPtrUint64(Initializer))
return false;
// Constructor arguments.
return true;
}
+// 1) Pops an integral value from the stack
+// 2) Peeks a pointer
+// 3) Pushes a new pointer that's a narrowed array
+// element of the peeked pointer with the value
+// from 1) added as offset.
+//
+// This leaves the original pointer on the stack and pushes a new one
+// with the offset applied and narrowed.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
+ const T &Offset = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+
+ if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
+ return false;
+
+ return NarrowPtr(S, OpPC);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
+ const T &Offset = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
+ return false;
+
+ return NarrowPtr(S, OpPC);
+}
+
inline bool CheckGlobalCtor(InterpState &S, CodePtr &PC) {
const Pointer &Obj = S.Stk.peek<Pointer>();
return CheckCtorCall(S, PC, Obj);