-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][bytecode] Ignore overflow in unary operators if requested #132557
Conversation
Add PreInc and PreDec ops for this purpose and ignore the overflow if UnaryOperator::canOverflow() returns false.
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesAdd 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:
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);
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/14754 Here is the relevant piece of the build log for the reference
|
Add PreInc and PreDec ops for this purpose and ignore the overflow if UnaryOperator::canOverflow() returns false.