Skip to content

Commit 6b5afda

Browse files
committed
[clang][Interp] Add ArrayElemPtr{,Pop} opcode
We usually access array elements in the same pattern, which uses narrow(). Add an extra opcode for this. This saves us quite some instructions and makes the bytecode easier to read. Differential Revision: https://reviews.llvm.org/D140805
1 parent e0bc779 commit 6b5afda

File tree

3 files changed

+42
-30
lines changed

3 files changed

+42
-30
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -413,18 +413,15 @@ bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
413413
const Expr *Index = E->getIdx();
414414
PrimType IndexT = classifyPrim(Index->getType());
415415

416-
// Take pointer of LHS, add offset from RHS, narrow result.
416+
// Take pointer of LHS, add offset from RHS.
417417
// What's left on the stack after this is a pointer.
418418
if (!this->visit(Base))
419419
return false;
420420

421421
if (!this->visit(Index))
422422
return false;
423423

424-
if (!this->emitAddOffset(IndexT, E))
425-
return false;
426-
427-
if (!this->emitNarrowPtr(E))
424+
if (!this->emitArrayElemPtrPop(IndexT, E))
428425
return false;
429426

430427
if (DiscardResult)
@@ -1214,16 +1211,11 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
12141211
return false;
12151212
} else {
12161213
// Advance the pointer currently on the stack to the given
1217-
// dimension and narrow().
1218-
if (!this->emitDupPtr(Init))
1219-
return false;
1214+
// dimension.
12201215
if (!this->emitConstUint32(ElementIndex, Init))
12211216
return false;
1222-
if (!this->emitAddOffsetUint32(Init))
1217+
if (!this->emitArrayElemPtrUint32(Init))
12231218
return false;
1224-
if (!this->emitNarrowPtr(Init))
1225-
return false;
1226-
12271219
if (!visitInitializer(Init))
12281220
return false;
12291221
if (!this->emitPopPtr(Init))
@@ -1249,31 +1241,22 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
12491241
for (size_t I = 0; I != Size; ++I) {
12501242
ArrayIndexScope<Emitter> IndexScope(this, I);
12511243

1252-
if (!this->emitDupPtr(SubExpr)) // LHS
1253-
return false;
1254-
12551244
if (ElemT) {
12561245
if (!this->visit(SubExpr))
12571246
return false;
12581247
if (!this->emitInitElem(*ElemT, I, Initializer))
12591248
return false;
12601249
} else {
1261-
// Narrow to our array element and recurse into visitInitializer()
1250+
// Get to our array element and recurse into visitInitializer()
12621251
if (!this->emitConstUint64(I, SubExpr))
12631252
return false;
1264-
1265-
if (!this->emitAddOffsetUint64(SubExpr))
1266-
return false;
1267-
1268-
if (!this->emitNarrowPtr(SubExpr))
1253+
if (!this->emitArrayElemPtrUint64(SubExpr))
12691254
return false;
1270-
12711255
if (!visitInitializer(SubExpr))
12721256
return false;
1257+
if (!this->emitPopPtr(Initializer))
1258+
return false;
12731259
}
1274-
1275-
if (!this->emitPopPtr(Initializer))
1276-
return false;
12771260
}
12781261
return true;
12791262
} else if (const auto *IVIE = dyn_cast<ImplicitValueInitExpr>(Initializer)) {
@@ -1309,13 +1292,9 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
13091292
// FIXME(perf): We're calling the constructor once per array element here,
13101293
// in the old intepreter we had a special-case for trivial constructors.
13111294
for (size_t I = 0; I != NumElems; ++I) {
1312-
if (!this->emitDupPtr(Initializer))
1313-
return false;
13141295
if (!this->emitConstUint64(I, Initializer))
13151296
return false;
1316-
if (!this->emitAddOffsetUint64(Initializer))
1317-
return false;
1318-
if (!this->emitNarrowPtr(Initializer))
1297+
if (!this->emitArrayElemPtrUint64(Initializer))
13191298
return false;
13201299

13211300
// Constructor arguments.

clang/lib/AST/Interp/Interp.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,36 @@ inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
14551455
return true;
14561456
}
14571457

1458+
// 1) Pops an integral value from the stack
1459+
// 2) Peeks a pointer
1460+
// 3) Pushes a new pointer that's a narrowed array
1461+
// element of the peeked pointer with the value
1462+
// from 1) added as offset.
1463+
//
1464+
// This leaves the original pointer on the stack and pushes a new one
1465+
// with the offset applied and narrowed.
1466+
template <PrimType Name, class T = typename PrimConv<Name>::T>
1467+
inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1468+
const T &Offset = S.Stk.pop<T>();
1469+
const Pointer &Ptr = S.Stk.peek<Pointer>();
1470+
1471+
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1472+
return false;
1473+
1474+
return NarrowPtr(S, OpPC);
1475+
}
1476+
1477+
template <PrimType Name, class T = typename PrimConv<Name>::T>
1478+
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1479+
const T &Offset = S.Stk.pop<T>();
1480+
const Pointer &Ptr = S.Stk.pop<Pointer>();
1481+
1482+
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1483+
return false;
1484+
1485+
return NarrowPtr(S, OpPC);
1486+
}
1487+
14581488
inline bool CheckGlobalCtor(InterpState &S, CodePtr &PC) {
14591489
const Pointer &Obj = S.Stk.peek<Pointer>();
14601490
return CheckCtorCall(S, PC, Obj);

clang/lib/AST/Interp/Opcodes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ def RVOPtr : Opcode;
306306
def NarrowPtr : Opcode;
307307
// [Pointer] -> [Pointer]
308308
def ExpandPtr : Opcode;
309+
// [Pointer, Offset] -> [Pointer]
310+
def ArrayElemPtr : AluOpcode;
311+
def ArrayElemPtrPop : AluOpcode;
309312

310313
//===----------------------------------------------------------------------===//
311314
// Direct field accessors

0 commit comments

Comments
 (0)