[clang] [clang][bytecode] Pass FPOptions to floating point ops (PR #107063)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 3 04:08:53 PDT 2024


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/107063

>From f8b31c957fc281bf4c73f3b032099e2de4f58193 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 3 Sep 2024 10:59:22 +0200
Subject: [PATCH] [clang][bytecode] Pass FPOptions to floating point ops

So we don't have to retrieve them from the InterpFrame, which is slow.
---
 clang/lib/AST/ByteCode/Compiler.cpp | 68 +++++++++++------------
 clang/lib/AST/ByteCode/Compiler.h   |  4 ++
 clang/lib/AST/ByteCode/Interp.cpp   | 10 ++--
 clang/lib/AST/ByteCode/Interp.h     | 86 +++++++++++++++++------------
 clang/lib/AST/ByteCode/Opcodes.td   | 10 ++--
 5 files changed, 99 insertions(+), 79 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 554e23e272e41c..a831f196abdcb5 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -298,8 +298,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
       return false;
 
     const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
-    llvm::RoundingMode RM = getRoundingMode(CE);
-    return this->emitCastIntegralFloating(*FromT, TargetSemantics, RM, CE);
+    return this->emitCastIntegralFloating(*FromT, TargetSemantics,
+                                          getFPOptions(CE), CE);
   }
 
   case CK_FloatingToBoolean:
@@ -317,12 +317,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
 
     if (ToT == PT_IntAP)
       return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(CE->getType()),
-                                              CE);
+                                              getFPOptions(CE), CE);
     if (ToT == PT_IntAPS)
       return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(CE->getType()),
-                                               CE);
+                                               getFPOptions(CE), CE);
 
-    return this->emitCastFloatingIntegral(*ToT, CE);
+    return this->emitCastFloatingIntegral(*ToT, getFPOptions(CE), CE);
   }
 
   case CK_NullToPointer:
@@ -810,21 +810,21 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
     return MaybeCastToBool(this->emitGE(*LT, BO));
   case BO_Sub:
     if (BO->getType()->isFloatingType())
-      return Discard(this->emitSubf(getRoundingMode(BO), BO));
+      return Discard(this->emitSubf(getFPOptions(BO), BO));
     return Discard(this->emitSub(*T, BO));
   case BO_Add:
     if (BO->getType()->isFloatingType())
-      return Discard(this->emitAddf(getRoundingMode(BO), BO));
+      return Discard(this->emitAddf(getFPOptions(BO), BO));
     return Discard(this->emitAdd(*T, BO));
   case BO_Mul:
     if (BO->getType()->isFloatingType())
-      return Discard(this->emitMulf(getRoundingMode(BO), BO));
+      return Discard(this->emitMulf(getFPOptions(BO), BO));
     return Discard(this->emitMul(*T, BO));
   case BO_Rem:
     return Discard(this->emitRem(*T, BO));
   case BO_Div:
     if (BO->getType()->isFloatingType())
-      return Discard(this->emitDivf(getRoundingMode(BO), BO));
+      return Discard(this->emitDivf(getFPOptions(BO), BO));
     return Discard(this->emitDiv(*T, BO));
   case BO_Assign:
     if (DiscardResult)
@@ -1153,7 +1153,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
       if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
         return false;
       if (ResultElemT == PT_Float) {
-        if (!this->emitAddf(getRoundingMode(E), E))
+        if (!this->emitAddf(getFPOptions(E), E))
           return false;
       } else {
         if (!this->emitAdd(ResultElemT, E))
@@ -1167,7 +1167,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
       if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
         return false;
       if (ResultElemT == PT_Float) {
-        if (!this->emitSubf(getRoundingMode(E), E))
+        if (!this->emitSubf(getFPOptions(E), E))
           return false;
       } else {
         if (!this->emitSub(ResultElemT, E))
@@ -1182,7 +1182,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
         return false;
 
       if (ResultElemT == PT_Float) {
-        if (!this->emitMulf(getRoundingMode(E), E))
+        if (!this->emitMulf(getFPOptions(E), E))
           return false;
       } else {
         if (!this->emitMul(ResultElemT, E))
@@ -1198,7 +1198,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
         return false;
 
       if (ResultElemT == PT_Float) {
-        if (!this->emitDivf(getRoundingMode(E), E))
+        if (!this->emitDivf(getFPOptions(E), E))
           return false;
       } else {
         if (!this->emitDiv(ResultElemT, E))
@@ -2063,22 +2063,21 @@ bool Compiler<Emitter>::VisitFloatCompoundAssignOperator(
   if (!this->emitGetLocal(*RT, TempOffset, E))
     return false;
 
-  llvm::RoundingMode RM = getRoundingMode(E);
   switch (E->getOpcode()) {
   case BO_AddAssign:
-    if (!this->emitAddf(RM, E))
+    if (!this->emitAddf(getFPOptions(E), E))
       return false;
     break;
   case BO_SubAssign:
-    if (!this->emitSubf(RM, E))
+    if (!this->emitSubf(getFPOptions(E), E))
       return false;
     break;
   case BO_MulAssign:
-    if (!this->emitMulf(RM, E))
+    if (!this->emitMulf(getFPOptions(E), E))
       return false;
     break;
   case BO_DivAssign:
-    if (!this->emitDivf(RM, E))
+    if (!this->emitDivf(getFPOptions(E), E))
       return false;
     break;
   default:
@@ -3325,7 +3324,7 @@ template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) {
 
   // Or Floats.
   if (T == PT_Float)
-    return this->emitCastFloatingIntegralBool(E);
+    return this->emitCastFloatingIntegralBool(getFPOptions(E), E);
 
   // Or anything else we can.
   return this->emitCast(*T, PT_Bool, E);
@@ -5005,8 +5004,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     }
 
     if (T == PT_Float) {
-      return DiscardResult ? this->emitIncfPop(getRoundingMode(E), E)
-                           : this->emitIncf(getRoundingMode(E), E);
+      return DiscardResult ? this->emitIncfPop(getFPOptions(E), E)
+                           : this->emitIncf(getFPOptions(E), E);
     }
 
     return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
@@ -5028,8 +5027,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     }
 
     if (T == PT_Float) {
-      return DiscardResult ? this->emitDecfPop(getRoundingMode(E), E)
-                           : this->emitDecf(getRoundingMode(E), E);
+      return DiscardResult ? this->emitDecfPop(getFPOptions(E), E)
+                           : this->emitDecf(getFPOptions(E), E);
     }
 
     return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
@@ -5056,7 +5055,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     // Post-inc and pre-inc are the same if the value is to be discarded.
     if (DiscardResult) {
       if (T == PT_Float)
-        return this->emitIncfPop(getRoundingMode(E), E);
+        return this->emitIncfPop(getFPOptions(E), E);
       return this->emitIncPop(*T, E);
     }
 
@@ -5066,7 +5065,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
         return false;
       if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
         return false;
-      if (!this->emitAddf(getRoundingMode(E), E))
+      if (!this->emitAddf(getFPOptions(E), E))
         return false;
       if (!this->emitStoreFloat(E))
         return false;
@@ -5105,7 +5104,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     // Post-dec and pre-dec are the same if the value is to be discarded.
     if (DiscardResult) {
       if (T == PT_Float)
-        return this->emitDecfPop(getRoundingMode(E), E);
+        return this->emitDecfPop(getFPOptions(E), E);
       return this->emitDecPop(*T, E);
     }
 
@@ -5115,7 +5114,7 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
         return false;
       if (!this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E))
         return false;
-      if (!this->emitSubf(getRoundingMode(E), E))
+      if (!this->emitSubf(getFPOptions(E), E))
         return false;
       if (!this->emitStoreFloat(E))
         return false;
@@ -5579,13 +5578,15 @@ bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
     }
 
     if (ToT == PT_IntAP)
-      return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT), E);
+      return this->emitCastFloatingIntegralAP(Ctx.getBitWidth(ToQT),
+                                              getFPOptions(E), E);
     if (ToT == PT_IntAPS)
-      return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT), E);
+      return this->emitCastFloatingIntegralAPS(Ctx.getBitWidth(ToQT),
+                                               getFPOptions(E), E);
 
     // Float to integral.
     if (isIntegralType(ToT) || ToT == PT_Bool)
-      return this->emitCastFloatingIntegral(ToT, E);
+      return this->emitCastFloatingIntegral(ToT, getFPOptions(E), E);
   }
 
   if (isIntegralType(FromT) || FromT == PT_Bool) {
@@ -5601,8 +5602,7 @@ bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
     if (ToT == PT_Float) {
       // Integral to floating.
       const llvm::fltSemantics *ToSem = &Ctx.getFloatSemantics(ToQT);
-      return this->emitCastIntegralFloating(FromT, ToSem, getRoundingMode(E),
-                                            E);
+      return this->emitCastIntegralFloating(FromT, ToSem, getFPOptions(E), E);
     }
   }
 
@@ -5639,7 +5639,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
   if (!this->emitArrayElem(ElemT, 0, E))
     return false;
   if (ElemT == PT_Float) {
-    if (!this->emitCastFloatingIntegral(PT_Bool, E))
+    if (!this->emitCastFloatingIntegral(PT_Bool, getFPOptions(E), E))
       return false;
   } else {
     if (!this->emitCast(ElemT, PT_Bool, E))
@@ -5654,7 +5654,7 @@ bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
   if (!this->emitArrayElemPop(ElemT, 1, E))
     return false;
   if (ElemT == PT_Float) {
-    if (!this->emitCastFloatingIntegral(PT_Bool, E))
+    if (!this->emitCastFloatingIntegral(PT_Bool, getFPOptions(E), E))
       return false;
   } else {
     if (!this->emitCast(ElemT, PT_Bool, E))
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 939cc0dae3546f..b18afacdb2e491 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -341,6 +341,10 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
     return FPO.getRoundingMode();
   }
 
+  uint32_t getFPOptions(const Expr *E) const {
+    return E->getFPFeaturesInEffect(Ctx.getLangOpts()).getAsOpaqueInt();
+  }
+
   bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
   PrimType classifyComplexElementType(QualType T) const {
     assert(T->isAnyComplexType());
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 30ccceb42eb374..8f57afcb4dc120 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -756,14 +756,13 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
 }
 
 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
-                      APFloat::opStatus Status) {
-  const SourceInfo &E = S.Current->getSource(OpPC);
-
+                      APFloat::opStatus Status, FPOptions FPO) {
   // [expr.pre]p4:
   //   If during the evaluation of an expression, the result is not
   //   mathematically defined [...], the behavior is undefined.
   // FIXME: C++ rules require us to not conform to IEEE 754 here.
   if (Result.isNan()) {
+    const SourceInfo &E = S.Current->getSource(OpPC);
     S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
         << /*NaN=*/true << S.Current->getRange(OpPC);
     return S.noteUndefinedBehavior();
@@ -774,12 +773,11 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
   if (S.inConstantContext())
     return true;
 
-  FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
-
   if ((Status & APFloat::opInexact) &&
       FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
     // Inexact result means that it depends on rounding mode. If the requested
     // mode is dynamic, the evaluation cannot be made in compile time.
+    const SourceInfo &E = S.Current->getSource(OpPC);
     S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
     return false;
   }
@@ -788,12 +786,14 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
       (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
        FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
        FPO.getAllowFEnvAccess())) {
+    const SourceInfo &E = S.Current->getSource(OpPC);
     S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
     return false;
   }
 
   if ((Status & APFloat::opStatus::opInvalidOp) &&
       FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
+    const SourceInfo &E = S.Current->getSource(OpPC);
     // There is no usefully definable result.
     S.FFDiag(E);
     return false;
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index c1423a060bcb97..e1d880060a0bac 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -246,7 +246,7 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
 /// Checks if the result of a floating-point operation is valid
 /// in the current context.
 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
-                      APFloat::opStatus Status);
+                      APFloat::opStatus Status, FPOptions FPO);
 
 /// Checks why the given DeclRefExpr is invalid.
 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
@@ -376,14 +376,22 @@ bool Add(InterpState &S, CodePtr OpPC) {
   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
 }
 
-inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
+  auto RM = FPO.getRoundingMode();
+  if (RM == llvm::RoundingMode::Dynamic)
+    return llvm::RoundingMode::NearestTiesToEven;
+  return RM;
+}
+
+inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Floating &RHS = S.Stk.pop<Floating>();
   const Floating &LHS = S.Stk.pop<Floating>();
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   Floating Result;
-  auto Status = Floating::add(LHS, RHS, RM, &Result);
+  auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -394,14 +402,15 @@ bool Sub(InterpState &S, CodePtr OpPC) {
   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
 }
 
-inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Floating &RHS = S.Stk.pop<Floating>();
   const Floating &LHS = S.Stk.pop<Floating>();
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   Floating Result;
-  auto Status = Floating::sub(LHS, RHS, RM, &Result);
+  auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -412,14 +421,15 @@ bool Mul(InterpState &S, CodePtr OpPC) {
   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
 }
 
-inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Floating &RHS = S.Stk.pop<Floating>();
   const Floating &LHS = S.Stk.pop<Floating>();
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   Floating Result;
-  auto Status = Floating::mul(LHS, RHS, RM, &Result);
+  auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -647,17 +657,18 @@ bool Div(InterpState &S, CodePtr OpPC) {
   return false;
 }
 
-inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Floating &RHS = S.Stk.pop<Floating>();
   const Floating &LHS = S.Stk.pop<Floating>();
 
   if (!CheckDivRem(S, OpPC, LHS, RHS))
     return false;
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   Floating Result;
-  auto Status = Floating::div(LHS, RHS, RM, &Result);
+  auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
 //===----------------------------------------------------------------------===//
@@ -822,54 +833,55 @@ bool DecPop(InterpState &S, CodePtr OpPC) {
 
 template <IncDecOp Op, PushVal DoPush>
 bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                       llvm::RoundingMode RM) {
+                       uint32_t FPOI) {
   Floating Value = Ptr.deref<Floating>();
   Floating Result;
 
   if constexpr (DoPush == PushVal::Yes)
     S.Stk.push<Floating>(Value);
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   llvm::APFloat::opStatus Status;
   if constexpr (Op == IncDecOp::Inc)
-    Status = Floating::increment(Value, RM, &Result);
+    Status = Floating::increment(Value, getRoundingMode(FPO), &Result);
   else
-    Status = Floating::decrement(Value, RM, &Result);
+    Status = Floating::decrement(Value, getRoundingMode(FPO), &Result);
 
   Ptr.deref<Floating>() = Result;
 
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
-inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
 
-  return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
+  return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
 }
 
-inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
 
-  return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
+  return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
 }
 
-inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
 
-  return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
+  return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
 }
 
-inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
 
-  return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
+  return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
 }
 
 /// 1) Pops the value from the stack.
@@ -2126,20 +2138,21 @@ bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
-                          const llvm::fltSemantics *Sem,
-                          llvm::RoundingMode RM) {
+                          const llvm::fltSemantics *Sem, uint32_t FPOI) {
   const T &From = S.Stk.pop<T>();
   APSInt FromAP = From.toAPSInt();
   Floating Result;
 
-  auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
+  auto Status =
+      Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result);
   S.Stk.push<Floating>(Result);
 
-  return CheckFloatResult(S, OpPC, Result, Status);
+  return CheckFloatResult(S, OpPC, Result, Status, FPO);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
+bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
   const Floating &F = S.Stk.pop<Floating>();
 
   if constexpr (std::is_same_v<T, Boolean>) {
@@ -2163,13 +2176,14 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
       return false;
     }
 
+    FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
     S.Stk.push<T>(T(Result));
-    return CheckFloatResult(S, OpPC, F, Status);
+    return CheckFloatResult(S, OpPC, F, Status, FPO);
   }
 }
 
 static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
-                                          uint32_t BitWidth) {
+                                          uint32_t BitWidth, uint32_t FPOI) {
   const Floating &F = S.Stk.pop<Floating>();
 
   APSInt Result(BitWidth, /*IsUnsigned=*/true);
@@ -2184,12 +2198,13 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
     return S.noteUndefinedBehavior();
   }
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
-  return CheckFloatResult(S, OpPC, F, Status);
+  return CheckFloatResult(S, OpPC, F, Status, FPO);
 }
 
 static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
-                                           uint32_t BitWidth) {
+                                           uint32_t BitWidth, uint32_t FPOI) {
   const Floating &F = S.Stk.pop<Floating>();
 
   APSInt Result(BitWidth, /*IsUnsigned=*/false);
@@ -2204,8 +2219,9 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
     return S.noteUndefinedBehavior();
   }
 
+  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
-  return CheckFloatResult(S, OpPC, F, Status);
+  return CheckFloatResult(S, OpPC, F, Status, FPO);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 46247688d4ef85..67350abe5401e1 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -140,7 +140,7 @@ class AluOpcode : Opcode {
 }
 
 class FloatOpcode : Opcode {
-  let Args = [ArgRoundingMode];
+  let Args = [ArgUint32];
 }
 
 class IntegerOpcode : Opcode {
@@ -642,23 +642,23 @@ def CastAPS : Opcode {
 // Cast an integer to a floating type
 def CastIntegralFloating : Opcode {
   let Types = [AluTypeClass];
-  let Args = [ArgFltSemantics, ArgRoundingMode];
+  let Args = [ArgFltSemantics, ArgUint32];
   let HasGroup = 1;
 }
 
 // Cast a floating to an integer type
 def CastFloatingIntegral : Opcode {
   let Types = [FixedSizeIntegralTypes];
-  let Args = [];
+  let Args = [ArgUint32];
   let HasGroup = 1;
 }
 
 def CastFloatingIntegralAP : Opcode {
-  let Args = [ArgUint32];
+  let Args = [ArgUint32, ArgUint32];
 }
 
 def CastFloatingIntegralAPS : Opcode {
-  let Args = [ArgUint32];
+  let Args = [ArgUint32, ArgUint32];
 }
 
 def CastPointerIntegral : Opcode {



More information about the cfe-commits mailing list