llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> Add PreInc and PreDec ops for this purpose and ignore the overflow if UnaryOperator::canOverflow() returns false. --- Full diff: https://github.com/llvm/llvm-project/pull/132557.diff 4 Files Affected: - (modified) clang/lib/AST/ByteCode/Compiler.cpp (+9-19) - (modified) clang/lib/AST/ByteCode/Interp.h (+33-12) - (modified) clang/lib/AST/ByteCode/Opcodes.td (+12-4) - (modified) clang/test/AST/ByteCode/literals.cpp (+26) ``````````diff diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index b30c669df6825..943e4302a0398 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3518,7 +3518,7 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { // ++Iter; if (!this->emitGetPtrLocal(Iter, E)) return false; - if (!this->emitIncPop(SizeT, E)) + if (!this->emitIncPop(SizeT, false, E)) return false; if (!this->jump(StartLabel)) @@ -5957,7 +5957,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { : this->emitIncf(getFPOptions(E), E); } - return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E); + return DiscardResult ? this->emitIncPop(*T, E->canOverflow(), E) + : this->emitInc(*T, E->canOverflow(), E); } case UO_PostDec: { // x-- if (!Ctx.getLangOpts().CPlusPlus14) @@ -5980,7 +5981,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { : this->emitDecf(getFPOptions(E), E); } - return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E); + return DiscardResult ? this->emitDecPop(*T, E->canOverflow(), E) + : this->emitDec(*T, E->canOverflow(), E); } case UO_PreInc: { // ++x if (!Ctx.getLangOpts().CPlusPlus14) @@ -6005,7 +6007,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { if (DiscardResult) { if (T == PT_Float) return this->emitIncfPop(getFPOptions(E), E); - return this->emitIncPop(*T, E); + return this->emitIncPop(*T, E->canOverflow(), E); } if (T == PT_Float) { @@ -6020,13 +6022,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { return false; } else { assert(isIntegralType(*T)); - if (!this->emitLoad(*T, E)) - return false; - if (!this->emitConst(1, E)) - return false; - if (!this->emitAdd(*T, E)) - return false; - if (!this->emitStore(*T, E)) + if (!this->emitPreInc(*T, E->canOverflow(), E)) return false; } return E->isGLValue() || this->emitLoadPop(*T, E); @@ -6054,7 +6050,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { if (DiscardResult) { if (T == PT_Float) return this->emitDecfPop(getFPOptions(E), E); - return this->emitDecPop(*T, E); + return this->emitDecPop(*T, E->canOverflow(), E); } if (T == PT_Float) { @@ -6069,13 +6065,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { return false; } else { assert(isIntegralType(*T)); - if (!this->emitLoad(*T, E)) - return false; - if (!this->emitConst(1, E)) - return false; - if (!this->emitSub(*T, E)) - return false; - if (!this->emitStore(*T, E)) + if (!this->emitPreDec(*T, E->canOverflow(), E)) return false; } return E->isGLValue() || this->emitLoadPop(*T, E); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 8ec4d95871702..ee4139fbc9530 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -765,7 +765,8 @@ enum class IncDecOp { }; template <typename T, IncDecOp Op, PushVal DoPush> -bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { +bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + bool CanOverflow) { assert(!Ptr.isDummy()); if constexpr (std::is_same_v<T, Boolean>) { @@ -780,16 +781,17 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { S.Stk.push<T>(Value); if constexpr (Op == IncDecOp::Inc) { - if (!T::increment(Value, &Result)) { + if (!T::increment(Value, &Result) || !CanOverflow) { Ptr.deref<T>() = Result; return true; } } else { - if (!T::decrement(Value, &Result)) { + if (!T::decrement(Value, &Result) || !CanOverflow) { Ptr.deref<T>() = Result; return true; } } + assert(CanOverflow); // Something went wrong with the previous operation. Compute the // result with another bit of precision. @@ -812,7 +814,6 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { << Trunc << Type << E->getSourceRange(); return true; } - return handleOverflow(S, OpPC, APResult); } @@ -821,24 +822,34 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { /// 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) { +bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; - return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr); + return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, + CanOverflow); } /// 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) { +bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) return false; - return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr); + return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow); +} + +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) { + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) + return false; + + return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow); } /// 1) Pops a pointer from the stack @@ -846,24 +857,34 @@ bool IncPop(InterpState &S, CodePtr OpPC) { /// 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) { +bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; - return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr); + return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, + CanOverflow); } /// 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) { +bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) return false; - return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr); + return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow); +} + +template <PrimType Name, class T = typename PrimConv<Name>::T> +bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) { + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) + return false; + + return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow); } template <IncDecOp Op, PushVal DoPush> diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index c29793ec886e5..798771bf91f05 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -593,10 +593,18 @@ def Shr : Opcode { def Inv: Opcode; // Increment and decrement. -def Inc: AluOpcode; -def IncPop : AluOpcode; -def Dec: AluOpcode; -def DecPop: AluOpcode; +class OverflowOpcode : Opcode { + let Types = [AluTypeClass]; + let Args = [ArgBool]; + let HasGroup = 1; +} + +def Inc : OverflowOpcode; +def IncPop : OverflowOpcode; +def PreInc : OverflowOpcode; +def Dec : OverflowOpcode; +def DecPop : OverflowOpcode; +def PreDec : OverflowOpcode; // Float increment and decrement. def Incf: FloatOpcode; diff --git a/clang/test/AST/ByteCode/literals.cpp b/clang/test/AST/ByteCode/literals.cpp index 73fcb0f1f2dc3..68d400bc31dd7 100644 --- a/clang/test/AST/ByteCode/literals.cpp +++ b/clang/test/AST/ByteCode/literals.cpp @@ -598,6 +598,32 @@ namespace IncDec { static_assert(UnderFlow() == -1, ""); // both-error {{not an integral constant expression}} \ // both-note {{in call to 'UnderFlow()'}} + /// This UnaryOperator can't overflow, so we shouldn't diagnose any overflow. + constexpr int CanOverflow() { + char c = 127; + char p; + ++c; + c++; + p = ++c; + p = c++; + + c = -128; + --c; + c--; + p = --c; + p = ++c; + + return 0; + } + static_assert(CanOverflow() == 0, ""); + + constexpr char OverflownChar() { + char c = 127; + c++; + return c; + } + static_assert(OverflownChar() == -128, ""); + constexpr int getTwo() { int i = 1; return (i += 1); `````````` </details> https://github.com/llvm/llvm-project/pull/132557 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits