tbaeder created this revision. tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik. Herald added a project: All. tbaeder requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This only works on integrals for now. Add four new opcodes, `Inc`, `IncPop`, `Dec` and `DecPop`. The `*Pop` variants don't leave anything on the stack and exist because the common case is that the result is unused. There are still a few corner cases left like floating values, pointers, and over/underflow handling. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D136423 Files: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/arrays.cpp clang/test/AST/Interp/literals.cpp
Index: clang/test/AST/Interp/literals.cpp =================================================================== --- clang/test/AST/Interp/literals.cpp +++ clang/test/AST/Interp/literals.cpp @@ -361,3 +361,52 @@ constexpr double db = true; static_assert(db == 1.0, ""); }; + +#if __cplusplus >= 202002L +namespace IncDec { + constexpr int zero() { + int a = 0; + a++; + ++a; + a--; + --a; + return a; + } + static_assert(zero() == 0, ""); + + constexpr int three() { + int a = 0; + return ++a + ++a; // expected-warning {{multiple unsequenced modifications to 'a'}} \ + // ref-warning {{multiple unsequenced modifications to 'a'}} \ + + } + static_assert(three() == 3, ""); + + constexpr bool incBool() { + bool b = false; + return ++b; // expected-error {{ISO C++17 does not allow incrementing expression of type bool}} \ + // ref-error {{ISO C++17 does not allow incrementing expression of type bool}} + } + static_assert(incBool(), ""); + + constexpr int uninit() { + int a; + ++a; // ref-note {{increment of uninitialized}} \ + // FIXME: Should also be rejected by new interpreter + return 1; + } + static_assert(uninit(), ""); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'uninit()'}} + + constexpr int OverUnderFlow() { // ref-error {{never produces a constant expression}} + int a = INT_MAX; + ++a; // ref-note {{is outside the range}} + // FIXME: Overflow + + int b = INT_MIN; + --b; // FIXME: Underflow + + return -1; + } +}; +#endif Index: clang/test/AST/Interp/arrays.cpp =================================================================== --- clang/test/AST/Interp/arrays.cpp +++ clang/test/AST/Interp/arrays.cpp @@ -180,3 +180,18 @@ constexpr int x = arr.a[0]; } }; + +namespace IncDec { + // FIXME: Pointer arithmethic needs to be supported in inc/dec + // unary operators +#if 0 + constexpr int getNextElem(const int *A, int I) { + const int *B = (A + I); + ++B; + return *B; + } + constexpr int E[] = {1,2,3,4}; + + static_assert(getNextElem(E, 1) == 3); +#endfi +}; Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -452,6 +452,11 @@ let HasGroup = 1; } +def Inc: IntegerOpcode; +def IncPop : IntegerOpcode; +def Dec: IntegerOpcode; +def DecPop: IntegerOpcode; + // [Real] -> [Real] def Neg: Opcode { let Types = [NonPtrTypeClass]; Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -328,6 +328,70 @@ return true; } +/// 1) Pops a pointer from the stack +/// 2) Load the value from the pointer +/// 3) Writes the value increased by one back to the pointer +/// 4) Pushes the original (pre-inc) value on the stack. +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool Inc(InterpState &S, CodePtr OpPC) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop<Pointer>(); + T Value = Ptr.deref<T>(); + T Result; + if (T::increment(Value, &Result)) + return false; + Ptr.deref<T>() = Result; + S.Stk.push<T>(Value); + return true; +} + +/// 1) Pops a pointer from the stack +/// 2) Load the value from the pointer +/// 3) Writes the value increased by one back to the pointer +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool IncPop(InterpState &S, CodePtr OpPC) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop<Pointer>(); + T Value = Ptr.deref<T>(); + T Result; + if (T::increment(Value, &Result)) + return false; + Ptr.deref<T>() = Result; + return true; +} + +/// 1) Pops a pointer from the stack +/// 2) Load the value from the pointer +/// 3) Writes the value decreased by one back to the pointer +/// 4) Pushes the original (pre-dec) value on the stack. +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool Dec(InterpState &S, CodePtr OpPC) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop<Pointer>(); + T Value = Ptr.deref<T>(); + T Result; + if (T::decrement(Value, &Result)) + return false; + Ptr.deref<T>() = Result; + S.Stk.push<T>(Value); + return true; +} + +/// 1) Pops a pointer from the stack +/// 2) Load the value from the pointer +/// 3) Writes the value decreased by one back to the pointer +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool DecPop(InterpState &S, CodePtr OpPC) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop<Pointer>(); + T Value = Ptr.deref<T>(); + T Result; + if (T::decrement(Value, &Result)) + return false; + Ptr.deref<T>() = Result; + return true; +} + /// 1) Pops the value from the stack. /// 2) Pushes the bitwise complemented value on the stack (~V). template <PrimType Name, class T = typename PrimConv<Name>::T> Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1226,35 +1226,81 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { - if (DiscardResult) - return true; - const Expr *SubExpr = E->getSubExpr(); + Optional<PrimType> T = classify(SubExpr->getType()); + // TODO: Support pointers for inc/dec operators. switch (E->getOpcode()) { - case UO_PostInc: // x++ - case UO_PostDec: // x-- - case UO_PreInc: // --x - case UO_PreDec: // ++x - return false; + case UO_PostInc: { // x++ + if (!this->visit(SubExpr)) + return false; + + if (DiscardResult) + return this->emitIncPop(*T, E); + + return this->emitInc(*T, E); + } + case UO_PostDec: { // x-- + if (!this->visit(SubExpr)) + return false; + + if (DiscardResult) + return this->emitDecPop(*T, E); + + return this->emitDec(*T, E); + } + case UO_PreInc: { // ++x + if (!this->visit(SubExpr)) + return false; + + // Post-inc and pre-inc are the same if the value is to be discarded. + if (DiscardResult) + return this->emitIncPop(*T, E); + this->emitLoad(*T, E); + this->emitConst(E, 1); + this->emitAdd(*T, E); + return this->emitStore(*T, E); + } + case UO_PreDec: { // --x + if (!this->visit(SubExpr)) + return false; + + // Post-dec and pre-dec are the same if the value is to be discarded. + if (DiscardResult) + return this->emitDecPop(*T, E); + + this->emitLoad(*T, E); + this->emitConst(E, 1); + this->emitSub(*T, E); + return this->emitStore(*T, E); + } case UO_LNot: // !x if (!this->visit(SubExpr)) return false; + // The Inv doesn't change anything, so skip it if we don't need the result. + if (DiscardResult) + return this->emitPop(*T, E); return this->emitInvBool(E); case UO_Minus: // -x if (!this->visit(SubExpr)) return false; - if (Optional<PrimType> T = classify(E->getType())) - return this->emitNeg(*T, E); - return false; + if (DiscardResult) + return this->emitPop(*T, E); + return this->emitNeg(*T, E); case UO_Plus: // +x - return this->visit(SubExpr); // noop - + if (!this->visit(SubExpr)) // noop + return false; + if (DiscardResult) + return this->emitPop(*T, E); + return true; case UO_AddrOf: // &x // We should already have a pointer when we get here. - return this->visit(SubExpr); - + if (!this->visit(SubExpr)) + return false; + if (DiscardResult) + return this->emitPop(*T, E); + return true; case UO_Deref: // *x return dereference( SubExpr, DerefKind::Read, @@ -1268,9 +1314,9 @@ case UO_Not: // ~x if (!this->visit(SubExpr)) return false; - if (Optional<PrimType> T = classify(E->getType())) - return this->emitComp(*T, E); - return false; + if (DiscardResult) + return this->emitPop(*T, E); + return this->emitComp(*T, E); case UO_Real: // __real x case UO_Imag: // __imag x case UO_Extension:
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits