Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1925,6 +1925,11 @@ return DiscardResult ? this->emitPopPtr(E) : true; } + if (T == PT_Float) { + return DiscardResult ? this->emitIncfPop(getRoundingMode(E), E) + : this->emitIncf(getRoundingMode(E), E); + } + return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E); } case UO_PostDec: { // x-- @@ -1938,6 +1943,11 @@ return DiscardResult ? this->emitPopPtr(E) : true; } + if (T == PT_Float) { + return DiscardResult ? this->emitDecfPop(getRoundingMode(E), E) + : this->emitDecf(getRoundingMode(E), E); + } + return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E); } case UO_PreInc: { // ++x @@ -1952,9 +1962,19 @@ } // Post-inc and pre-inc are the same if the value is to be discarded. - if (DiscardResult) + if (DiscardResult) { + if (T == PT_Float) + return this->emitIncfPop(getRoundingMode(E), E); return this->emitIncPop(*T, E); + } + if (T == PT_Float) { + const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); + this->emitLoadFloat(E); + this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E); + this->emitAddf(getRoundingMode(E), E); + return this->emitStoreFloat(E); + } this->emitLoad(*T, E); this->emitConst(1, E); this->emitAdd(*T, E); @@ -1972,9 +1992,19 @@ } // Post-dec and pre-dec are the same if the value is to be discarded. - if (DiscardResult) + if (DiscardResult) { + if (T == PT_Float) + return this->emitDecfPop(getRoundingMode(E), E); return this->emitDecPop(*T, E); + } + if (T == PT_Float) { + const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType()); + this->emitLoadFloat(E); + this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E); + this->emitSubf(getRoundingMode(E), E); + return this->emitStoreFloat(E); + } this->emitLoad(*T, E); this->emitConst(1, E); this->emitSub(*T, E); Index: clang/lib/AST/Interp/Floating.h =================================================================== --- clang/lib/AST/Interp/Floating.h +++ clang/lib/AST/Interp/Floating.h @@ -125,12 +125,27 @@ return R->F.add(B.F, RM); } + static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, + Floating *R) { + APFloat One(A.F.getSemantics(), 1); + *R = Floating(A.F); + + return R->F.add(One, RM); + } + static APFloat::opStatus sub(Floating A, Floating B, llvm::RoundingMode RM, Floating *R) { *R = Floating(A.F); return R->F.subtract(B.F, RM); } + static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, + Floating *R) { + APFloat One(A.F.getSemantics(), 1); + *R = Floating(A.F); + return R->F.subtract(One, RM); + } + static APFloat::opStatus mul(Floating A, Floating B, llvm::RoundingMode RM, Floating *R) { *R = Floating(A.F); Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -552,6 +552,50 @@ return IncDecHelper(S, OpPC, Ptr); } +template +bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, + llvm::RoundingMode RM) { + Floating Value = Ptr.deref(); + Floating Result; + + if constexpr (DoPush == PushVal::Yes) + S.Stk.push(Value); + + llvm::APFloat::opStatus Status; + if constexpr (Op == IncDecOp::Inc) + Status = Floating::increment(Value, RM, &Result); + else + Status = Floating::decrement(Value, RM, &Result); + + Ptr.deref() = Result; + + return CheckFloatResult(S, OpPC, Status); +} + +inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop(); + return IncDecFloatHelper(S, OpPC, Ptr, RM); +} + +inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop(); + return IncDecFloatHelper(S, OpPC, Ptr, RM); +} + +inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop(); + return IncDecFloatHelper(S, OpPC, Ptr, RM); +} + +inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { + // FIXME: Check initialization of Ptr + const Pointer &Ptr = S.Stk.pop(); + return IncDecFloatHelper(S, OpPC, Ptr, RM); +} + /// 1) Pops the value from the stack. /// 2) Pushes the bitwise complemented value on the stack (~V). template ::T> Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -510,11 +510,18 @@ let HasGroup = 1; } +// Increment and decrement. def Inc: IntegerOpcode; def IncPop : IntegerOpcode; def Dec: IntegerOpcode; def DecPop: IntegerOpcode; +// Float increment and decrement. +def Incf: FloatOpcode; +def IncfPop : FloatOpcode; +def Decf: FloatOpcode; +def DecfPop : FloatOpcode; + // [Real] -> [Real] def Neg: Opcode { let Types = [NonPtrTypeClass]; Index: clang/test/AST/Interp/floats.cpp =================================================================== --- clang/test/AST/Interp/floats.cpp +++ clang/test/AST/Interp/floats.cpp @@ -1,6 +1,15 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s // RUN: %clang_cc1 -verify=ref %s + +constexpr void assert(bool C) { + if (C) + return; + // Invalid in constexpr. + (void)(1 / 0); // expected-warning {{undefined}} \ + // ref-warning {{undefined}} +} + constexpr int i = 2; constexpr float f = 1.0f; static_assert(f == 1.0f, ""); @@ -79,6 +88,30 @@ static_assert(f2() == __FLT_MAX__, ""); } +namespace unary { + constexpr float a() { + float f = 0.0; + assert(++f == 1.0); + assert(f == 1.0); + ++f; + f++; + assert(f == 3.0); + --f; + f--; + assert(f == 1.0); + return 1.0; + } + static_assert(a() == 1.0); + + constexpr float b() { + float f = __FLT_MAX__; + f++; + return f; + } + static_assert(b() == __FLT_MAX__); +} + + namespace ZeroInit { template struct A {