[clang] b3b1d86 - Revert "[clang][Interp] Support floating-point values"

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 25 05:49:07 PST 2023


Author: Timm Bäder
Date: 2023-01-25T14:48:39+01:00
New Revision: b3b1d86137422dbdc9e8626925067f1b50734036

URL: https://github.com/llvm/llvm-project/commit/b3b1d86137422dbdc9e8626925067f1b50734036
DIFF: https://github.com/llvm/llvm-project/commit/b3b1d86137422dbdc9e8626925067f1b50734036.diff

LOG: Revert "[clang][Interp] Support floating-point values"

This reverts commit 62f43c3eae2460d4ca3da7897fd2d7c56920638c.

This breaks a couple of builders, e.g.

https://lab.llvm.org/buildbot/#/builders/139/builds/34925

Added: 
    

Modified: 
    clang/lib/AST/CMakeLists.txt
    clang/lib/AST/Interp/Boolean.h
    clang/lib/AST/Interp/ByteCodeEmitter.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Context.cpp
    clang/lib/AST/Interp/Descriptor.cpp
    clang/lib/AST/Interp/Disasm.cpp
    clang/lib/AST/Interp/Integral.h
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/InterpFrame.cpp
    clang/lib/AST/Interp/InterpStack.h
    clang/lib/AST/Interp/Opcodes.td
    clang/lib/AST/Interp/PrimType.cpp
    clang/lib/AST/Interp/PrimType.h
    clang/test/SemaCXX/rounding-math.cpp

Removed: 
    clang/lib/AST/Interp/Floating.cpp
    clang/lib/AST/Interp/Floating.h
    clang/lib/AST/Interp/Primitives.h
    clang/test/AST/Interp/const-fpfeatures.cpp
    clang/test/AST/Interp/floats.cpp


################################################################################
diff  --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 3d8d8cc077615..e4c1008fe34b1 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -74,7 +74,6 @@ add_clang_library(clangAST
   Interp/Frame.cpp
   Interp/Function.cpp
   Interp/InterpBuiltin.cpp
-  Interp/Floating.cpp
   Interp/Interp.cpp
   Interp/InterpBlock.cpp
   Interp/InterpFrame.cpp

diff  --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index e496f70eb4117..3122388a49a55 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -27,10 +27,12 @@ class Boolean final {
   /// Underlying boolean.
   bool V;
 
+  /// Construct a wrapper from a boolean.
+  explicit Boolean(bool V) : V(V) {}
+
  public:
   /// Zero-initializes a boolean.
   Boolean() : V(false) {}
-  explicit Boolean(bool V) : V(V) {}
 
   bool operator<(Boolean RHS) const { return V < RHS.V; }
   bool operator>(Boolean RHS) const { return V > RHS.V; }

diff  --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index be56348beca73..4633d1e0823b6 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -8,7 +8,6 @@
 
 #include "ByteCodeEmitter.h"
 #include "Context.h"
-#include "Floating.h"
 #include "Opcode.h"
 #include "Program.h"
 #include "clang/AST/DeclCXX.h"

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 62ed09f078c18..ae8bf377d262f 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -11,7 +11,6 @@
 #include "ByteCodeGenError.h"
 #include "ByteCodeStmtGen.h"
 #include "Context.h"
-#include "Floating.h"
 #include "Function.h"
 #include "PrimType.h"
 #include "Program.h"
@@ -96,41 +95,6 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
     return this->emitGetPtrBase(ToBase->Offset, CE);
   }
 
-  case CK_FloatingCast: {
-    if (!this->visit(SubExpr))
-      return false;
-    const auto *TargetSemantics =
-        &Ctx.getASTContext().getFloatTypeSemantics(CE->getType());
-    return this->emitCastFP(TargetSemantics, getRoundingMode(CE), CE);
-  }
-
-  case CK_IntegralToFloating: {
-    std::optional<PrimType> FromT = classify(SubExpr->getType());
-    if (!FromT)
-      return false;
-
-    if (!this->visit(SubExpr))
-      return false;
-
-    const auto *TargetSemantics =
-        &Ctx.getASTContext().getFloatTypeSemantics(CE->getType());
-    llvm::RoundingMode RM = getRoundingMode(CE);
-    return this->emitCastIntegralFloating(*FromT, TargetSemantics, RM, CE);
-  }
-
-  case CK_FloatingToBoolean:
-  case CK_FloatingToIntegral: {
-    std::optional<PrimType> ToT = classify(CE->getType());
-
-    if (!ToT)
-      return false;
-
-    if (!this->visit(SubExpr))
-      return false;
-
-    return this->emitCastFloatingIntegral(*ToT, CE);
-  }
-
   case CK_ArrayToPointerDecay:
   case CK_AtomicToNonAtomic:
   case CK_ConstructorConversion:
@@ -172,14 +136,6 @@ bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
   return this->emitConst(LE->getValue(), LE);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
-  if (DiscardResult)
-    return true;
-
-  return this->emitConstFloat(E->getValue(), E);
-}
-
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
   return this->visit(PE->getSubExpr());
@@ -239,22 +195,14 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
   case BO_GE:
     return Discard(this->emitGE(*LT, BO));
   case BO_Sub:
-    if (BO->getType()->isFloatingType())
-      return Discard(this->emitSubf(getRoundingMode(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->emitAdd(*T, BO));
   case BO_Mul:
-    if (BO->getType()->isFloatingType())
-      return Discard(this->emitMulf(getRoundingMode(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->emitDiv(*T, BO));
   case BO_Assign:
     if (DiscardResult)
@@ -567,9 +515,6 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
   assert(!E->getType()->isPointerType() &&
          "Support pointer arithmethic in compound assignment operators");
 
-  assert(!E->getType()->isFloatingType() &&
-         "Support floating types in compound assignment operators");
-
   // Get LHS pointer, load its value and get RHS value.
   if (!visit(LHS))
     return false;
@@ -691,8 +636,6 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, const Expr *E) {
     return this->emitZeroUint64(E);
   case PT_Ptr:
     return this->emitNullPtr(E);
-  case PT_Float:
-    assert(false);
   }
   llvm_unreachable("unknown primitive type");
 }
@@ -857,7 +800,6 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
   case PT_Bool:
     return this->emitConstBool(Value, E);
   case PT_Ptr:
-  case PT_Float:
     llvm_unreachable("Invalid integral type");
     break;
   }

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 6b82818fe09ae..7af61695864c9 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -58,7 +58,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   // Expression visitors - result returned on interp stack.
   bool VisitCastExpr(const CastExpr *E);
   bool VisitIntegerLiteral(const IntegerLiteral *E);
-  bool VisitFloatingLiteral(const FloatingLiteral *E);
   bool VisitParenExpr(const ParenExpr *E);
   bool VisitBinaryOperator(const BinaryOperator *E);
   bool VisitPointerArithBinOp(const BinaryOperator *E);
@@ -235,15 +234,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
     return VD->hasGlobalStorage() || VD->isConstexpr();
   }
 
-  llvm::RoundingMode getRoundingMode(const Expr *E) const {
-    FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());
-
-    if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
-      return llvm::RoundingMode::NearestTiesToEven;
-
-    return FPO.getRoundingMode();
-  }
-
 protected:
   /// Variable to storage mapping.
   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;

diff  --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 8d1c077e1817d..16471242f3282 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -113,9 +113,6 @@ std::optional<PrimType> Context::classify(QualType T) const {
   if (T->isNullPtrType())
     return PT_Ptr;
 
-  if (T->isFloatingType())
-    return PT_Float;
-
   if (auto *AT = dyn_cast<AtomicType>(T))
     return classify(AT->getValueType());
 

diff  --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index e9fe159eccd4b..04bc8681dd6ec 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -8,7 +8,6 @@
 
 #include "Descriptor.h"
 #include "Boolean.h"
-#include "Floating.h"
 #include "Pointer.h"
 #include "PrimType.h"
 #include "Record.h"
@@ -171,11 +170,6 @@ static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) {
 }
 
 static BlockCtorFn getCtorPrim(PrimType Type) {
-  // Floating types are special. They are primitives, but need their
-  // constructor called.
-  if (Type == PT_Float)
-    return ctorTy<PrimConv<PT_Float>::T>;
-
   COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
 }
 

diff  --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp
index d362ccdc73282..d31e879d516fb 100644
--- a/clang/lib/AST/Interp/Disasm.cpp
+++ b/clang/lib/AST/Interp/Disasm.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Floating.h"
 #include "Function.h"
 #include "Opcode.h"
 #include "PrimType.h"

diff  --git a/clang/lib/AST/Interp/Floating.cpp b/clang/lib/AST/Interp/Floating.cpp
deleted file mode 100644
index 922e17ad1450d..0000000000000
--- a/clang/lib/AST/Interp/Floating.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===---- Floating.cpp - Support for floating point values ------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Floating.h"
-
-namespace clang {
-namespace interp {
-
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F) {
-  F.print(OS);
-  return OS;
-}
-
-Floating getSwappedBytes(Floating F) { return F; }
-
-} // namespace interp
-} // namespace clang

diff  --git a/clang/lib/AST/Interp/Floating.h b/clang/lib/AST/Interp/Floating.h
deleted file mode 100644
index fb0884bb3b605..0000000000000
--- a/clang/lib/AST/Interp/Floating.h
+++ /dev/null
@@ -1,144 +0,0 @@
-//===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the VM types and helpers operating on types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_INTERP_FLOATING_H
-#define LLVM_CLANG_AST_INTERP_FLOATING_H
-
-#include "Primitives.h"
-#include "clang/AST/APValue.h"
-#include "llvm/ADT/APFloat.h"
-
-namespace clang {
-namespace interp {
-
-using APFloat = llvm::APFloat;
-using APSInt = llvm::APSInt;
-
-class Floating final {
-private:
-  // The underlying value storage.
-  APFloat F;
-
-public:
-  /// Zero-initializes a Floating.
-  Floating() : F(0.0f) {}
-  Floating(const APFloat &F) : F(F) {}
-
-  // Static constructors for special floating point values.
-  static Floating getInf(const llvm::fltSemantics &Sem) {
-    return Floating(APFloat::getInf(Sem));
-  }
-  const APFloat &getAPFloat() const { return F; }
-
-  bool operator<(Floating RHS) const { return F < RHS.F; }
-  bool operator>(Floating RHS) const { return F > RHS.F; }
-  bool operator<=(Floating RHS) const { return F <= RHS.F; }
-  bool operator>=(Floating RHS) const { return F >= RHS.F; }
-  bool operator==(Floating RHS) const { return F == RHS.F; }
-  bool operator!=(Floating RHS) const { return F != RHS.F; }
-  Floating operator-() const { return Floating(-F); }
-
-  APFloat::opStatus convertToInteger(APSInt &Result) const {
-    bool IsExact;
-    return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
-  }
-
-  Floating toSemantics(const llvm::fltSemantics *Sem,
-                       llvm::RoundingMode RM) const {
-    APFloat Copy = F;
-    bool LosesInfo;
-    Copy.convert(*Sem, RM, &LosesInfo);
-    (void)LosesInfo;
-    return Floating(Copy);
-  }
-
-  /// Convert this Floating to one with the same semantics as \Other.
-  Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
-    return toSemantics(&Other.F.getSemantics(), RM);
-  }
-
-  APSInt toAPSInt(unsigned NumBits = 0) const {
-    return APSInt(F.bitcastToAPInt());
-  }
-  APValue toAPValue() const { return APValue(F); }
-  void print(llvm::raw_ostream &OS) const {
-    // Can't use APFloat::print() since it appends a newline.
-    SmallVector<char, 16> Buffer;
-    F.toString(Buffer);
-    OS << Buffer;
-  }
-
-  unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
-
-  bool isSigned() const { return true; }
-  bool isNegative() const { return F.isNegative(); }
-  bool isPositive() const { return !F.isNegative(); }
-  bool isZero() const { return F.isZero(); }
-  bool isNonZero() const { return F.isNonZero(); }
-  bool isMin() const { return F.isSmallest(); }
-  bool isMinusOne() const { return F.isExactlyValue(-1.0); }
-  bool isNan() const { return F.isNaN(); }
-  bool isFinite() const { return F.isFinite(); }
-
-  ComparisonCategoryResult compare(const Floating &RHS) const {
-    return Compare(F, RHS.F);
-  }
-
-  static APFloat::opStatus fromIntegral(APSInt Val,
-                                        const llvm::fltSemantics &Sem,
-                                        llvm::RoundingMode RM,
-                                        Floating &Result) {
-    APFloat F = APFloat(Sem);
-    APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
-    Result = Floating(F);
-    return Status;
-  }
-
-  // -------
-
-  static APFloat::opStatus add(Floating A, Floating B, llvm::RoundingMode RM,
-                               Floating *R) {
-    *R = Floating(A.F);
-    return R->F.add(B.F, 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 mul(Floating A, Floating B, llvm::RoundingMode RM,
-                               Floating *R) {
-    *R = Floating(A.F);
-    return R->F.multiply(B.F, RM);
-  }
-
-  static APFloat::opStatus div(Floating A, Floating B, llvm::RoundingMode RM,
-                               Floating *R) {
-    *R = Floating(A.F);
-    return R->F.divide(B.F, RM);
-  }
-
-  static bool neg(Floating A, Floating *R) {
-    *R = -A;
-    return false;
-  }
-};
-
-llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
-Floating getSwappedBytes(Floating F);
-
-} // namespace interp
-} // namespace clang
-
-#endif

diff  --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index d45bd89bb5a66..8a742333ae57e 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -21,14 +21,33 @@
 #include <cstddef>
 #include <cstdint>
 
-#include "Primitives.h"
-
 namespace clang {
 namespace interp {
 
 using APInt = llvm::APInt;
 using APSInt = llvm::APSInt;
 
+/// Helper to compare two comparable types.
+template <typename T>
+ComparisonCategoryResult Compare(const T &X, const T &Y) {
+  if (X < Y)
+    return ComparisonCategoryResult::Less;
+  if (X > Y)
+    return ComparisonCategoryResult::Greater;
+  return ComparisonCategoryResult::Equal;
+}
+
+// Helper structure to select the representation.
+template <unsigned Bits, bool Signed> struct Repr;
+template <> struct Repr<8, false> { using Type = uint8_t; };
+template <> struct Repr<16, false> { using Type = uint16_t; };
+template <> struct Repr<32, false> { using Type = uint32_t; };
+template <> struct Repr<64, false> { using Type = uint64_t; };
+template <> struct Repr<8, true> { using Type = int8_t; };
+template <> struct Repr<16, true> { using Type = int16_t; };
+template <> struct Repr<32, true> { using Type = int32_t; };
+template <> struct Repr<64, true> { using Type = int64_t; };
+
 /// Wrapper around numeric types.
 ///
 /// These wrappers are required to shared an interface between APSint and
@@ -37,16 +56,6 @@ using APSInt = llvm::APSInt;
 template <unsigned Bits, bool Signed> class Integral final {
 private:
   template <unsigned OtherBits, bool OtherSigned> friend class Integral;
-  // Helper structure to select the representation.
-  template <unsigned ReprBits, bool ReprSigned> struct Repr;
-  template <> struct Repr<8, false> { using Type = uint8_t; };
-  template <> struct Repr<16, false> { using Type = uint16_t; };
-  template <> struct Repr<32, false> { using Type = uint32_t; };
-  template <> struct Repr<64, false> { using Type = uint64_t; };
-  template <> struct Repr<8, true> { using Type = int8_t; };
-  template <> struct Repr<16, true> { using Type = int16_t; };
-  template <> struct Repr<32, true> { using Type = int32_t; };
-  template <> struct Repr<64, true> { using Type = int64_t; };
 
   // The primitive representing the integral.
   using ReprT = typename Repr<Bits, Signed>::Type;

diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 648f63105985a..6a600b306bad4 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -473,49 +473,6 @@ bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
   return CheckFieldsInitialized(S, OpPC, This, R);
 }
 
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
-  // In a constant context, assume that any dynamic rounding mode or FP
-  // exception state matches the default floating-point environment.
-  if (S.inConstantContext())
-    return true;
-
-  const SourceInfo &E = S.Current->getSource(OpPC);
-  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.
-    S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
-    return false;
-  }
-
-  if ((Status != APFloat::opOK) &&
-      (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
-       FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
-       FPO.getAllowFEnvAccess())) {
-    S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
-    return false;
-  }
-
-  if ((Status & APFloat::opStatus::opInvalidOp) &&
-      FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
-    // There is no usefully definable result.
-    S.FFDiag(E);
-    return false;
-  }
-
-  return true;
-}
-
-bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
-            llvm::RoundingMode RM) {
-  Floating F = S.Stk.pop<Floating>();
-  Floating Result = F.toSemantics(Sem, RM);
-  S.Stk.push<Floating>(Result);
-  return true;
-}
-
 bool Interpret(InterpState &S, APValue &Result) {
   // The current stack frame when we started Interpret().
   // This is being used by the ops to determine wheter

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 9613eafdb5911..7ee823ef130af 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -14,7 +14,6 @@
 #define LLVM_CLANG_AST_INTERP_INTERP_H
 
 #include "Boolean.h"
-#include "Floating.h"
 #include "Function.h"
 #include "InterpFrame.h"
 #include "InterpStack.h"
@@ -138,10 +137,6 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
   return true;
 }
 
-/// Checks if the result is a floating-point operation is valid
-/// in the current context.
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
-
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
 
@@ -193,16 +188,6 @@ 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) {
-  const Floating &RHS = S.Stk.pop<Floating>();
-  const Floating &LHS = S.Stk.pop<Floating>();
-
-  Floating Result;
-  auto Status = Floating::add(LHS, RHS, RM, &Result);
-  S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
-}
-
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool Sub(InterpState &S, CodePtr OpPC) {
   const T &RHS = S.Stk.pop<T>();
@@ -211,16 +196,6 @@ 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) {
-  const Floating &RHS = S.Stk.pop<Floating>();
-  const Floating &LHS = S.Stk.pop<Floating>();
-
-  Floating Result;
-  auto Status = Floating::sub(LHS, RHS, RM, &Result);
-  S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
-}
-
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool Mul(InterpState &S, CodePtr OpPC) {
   const T &RHS = S.Stk.pop<T>();
@@ -229,15 +204,6 @@ 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) {
-  const Floating &RHS = S.Stk.pop<Floating>();
-  const Floating &LHS = S.Stk.pop<Floating>();
-
-  Floating Result;
-  auto Status = Floating::mul(LHS, RHS, RM, &Result);
-  S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
-}
 /// 1) Pops the RHS from the stack.
 /// 2) Pops the LHS from the stack.
 /// 3) Pushes 'LHS & RHS' on the stack
@@ -329,19 +295,6 @@ bool Div(InterpState &S, CodePtr OpPC) {
   return false;
 }
 
-inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
-  const Floating &RHS = S.Stk.pop<Floating>();
-  const Floating &LHS = S.Stk.pop<Floating>();
-
-  if (!CheckDivRem(S, OpPC, LHS, RHS))
-    return false;
-
-  Floating Result;
-  auto Status = Floating::div(LHS, RHS, RM, &Result);
-  S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
-}
-
 //===----------------------------------------------------------------------===//
 // Inv
 //===----------------------------------------------------------------------===//
@@ -1229,52 +1182,6 @@ template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
   return true;
 }
 
-/// 1) Pops a Floating from the stack.
-/// 2) Pushes a new floating on the stack that uses the given semantics.
-/// Not templated, so implemented in Interp.cpp.
-bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
-            llvm::RoundingMode RM);
-
-template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
-                          const llvm::fltSemantics *Sem,
-                          llvm::RoundingMode RM) {
-  const T &From = S.Stk.pop<T>();
-  APSInt FromAP = From.toAPSInt();
-  Floating Result;
-
-  auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
-  S.Stk.push<Floating>(Result);
-
-  return CheckFloatResult(S, OpPC, Status);
-}
-
-template <PrimType Name, class T = typename PrimConv<Name>::T>
-bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
-  const Floating &F = S.Stk.pop<Floating>();
-
-  if constexpr (std::is_same_v<T, Boolean>) {
-    S.Stk.push<T>(T(F.isNonZero()));
-    return true;
-  } else {
-    APSInt Result(std::max(8u, T::bitWidth() + 1),
-                  /*IsUnsigned=*/!T::isSigned());
-    auto Status = F.convertToInteger(Result);
-
-    // Float-to-Integral overflow check.
-    if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
-      const Expr *E = S.Current->getExpr(OpPC);
-      QualType Type = E->getType();
-
-      S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
-      return S.noteUndefinedBehavior();
-    }
-
-    S.Stk.push<T>(T(Result));
-    return CheckFloatResult(S, OpPC, Status);
-  }
-}
-
 //===----------------------------------------------------------------------===//
 // Zero, Nullptr
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index ee29997cfeccb..40644c538c6a7 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -8,7 +8,6 @@
 
 #include "InterpFrame.h"
 #include "Boolean.h"
-#include "Floating.h"
 #include "Function.h"
 #include "InterpStack.h"
 #include "InterpState.h"

diff  --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h
index 4987b2c33d6de..3adaad96515e0 100644
--- a/clang/lib/AST/Interp/InterpStack.h
+++ b/clang/lib/AST/Interp/InterpStack.h
@@ -160,8 +160,6 @@ class InterpStack final {
     else if constexpr (std::is_same_v<T, uint64_t> ||
                        std::is_same_v<T, Integral<64, false>>)
       return PT_Uint64;
-    else if constexpr (std::is_same_v<T, Floating>)
-      return PT_Float;
 
     llvm_unreachable("unknown type push()'ed into InterpStack");
   }

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 54487e9d011b1..64582980b7e8c 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -25,7 +25,6 @@ def Sint32 : Type;
 def Uint32 : Type;
 def Sint64 : Type;
 def Uint64 : Type;
-def Float : Type;
 def Ptr : Type;
 
 //===----------------------------------------------------------------------===//
@@ -41,14 +40,11 @@ def ArgSint32 : ArgType { let Name = "int32_t"; }
 def ArgUint32 : ArgType { let Name = "uint32_t"; }
 def ArgSint64 : ArgType { let Name = "int64_t"; }
 def ArgUint64 : ArgType { let Name = "uint64_t"; }
-def ArgFloat : ArgType { let Name = "Floating"; }
 def ArgBool : ArgType { let Name = "bool"; }
 
 def ArgFunction : ArgType { let Name = "const Function *"; }
 def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
 def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
-def ArgFltSemantics : ArgType { let Name = "const llvm::fltSemantics *"; }
-def ArgRoundingMode : ArgType { let Name = "llvm::RoundingMode"; }
 
 //===----------------------------------------------------------------------===//
 // Classes of types instructions operate on.
@@ -58,21 +54,18 @@ class TypeClass {
   list<Type> Types;
 }
 
-def IntegerTypeClass : TypeClass {
+def NumberTypeClass : TypeClass {
   let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
                Uint32, Sint64, Uint64];
 }
 
-def NumberTypeClass : TypeClass {
-  let Types = !listconcat(IntegerTypeClass.Types, [Float]);
-}
-
-def FloatTypeClass : TypeClass {
-  let Types = [Float];
+def IntegerTypeClass : TypeClass {
+  let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+               Uint32, Sint64, Uint64];
 }
 
 def AluTypeClass : TypeClass {
-  let Types = !listconcat(IntegerTypeClass.Types, [Bool]);
+  let Types = !listconcat(NumberTypeClass.Types, [Bool]);
 }
 
 def PtrTypeClass : TypeClass {
@@ -83,16 +76,12 @@ def BoolTypeClass : TypeClass {
   let Types = [Bool];
 }
 
-def NonPtrTypeClass : TypeClass {
-  let Types = !listconcat(IntegerTypeClass.Types, [Bool], [Float]);
-}
-
 def AllTypeClass : TypeClass {
-  let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types, FloatTypeClass.Types);
+  let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
 }
 
 def ComparableTypeClass : TypeClass {
-  let Types = !listconcat(AluTypeClass.Types, [Ptr], [Float]);
+  let Types = !listconcat(AluTypeClass.Types, [Ptr]);
 }
 
 class SingletonTypeClass<Type Ty> : TypeClass {
@@ -119,11 +108,6 @@ class AluOpcode : Opcode {
   let HasGroup = 1;
 }
 
-class FloatOpcode : Opcode {
-  let Types = [];
-  let Args = [ArgRoundingMode];
-}
-
 class IntegerOpcode : Opcode {
   let Types = [IntegerTypeClass];
   let HasGroup = 1;
@@ -215,7 +199,6 @@ def ConstSint32 : ConstOpcode<Sint32, ArgSint32>;
 def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
 def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
 def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
-def ConstFloat : ConstOpcode<Float, ArgFloat>;
 def ConstBool : ConstOpcode<Bool, ArgBool>;
 
 // [] -> [Integer]
@@ -436,19 +419,13 @@ def DecPtr : Opcode {
 //===----------------------------------------------------------------------===//
 
 // [Real, Real] -> [Real]
-def Add  : AluOpcode;
-def Addf : FloatOpcode;
-def Sub  : AluOpcode;
-def Subf : FloatOpcode;
-def Mul  : AluOpcode;
-def Mulf : FloatOpcode;
-def Rem  : IntegerOpcode;
-def Div  : IntegerOpcode;
-def Divf : FloatOpcode;
-
-def BitAnd : IntegerOpcode;
-def BitOr : IntegerOpcode;
-def BitXor : IntegerOpcode;
+def Sub : AluOpcode;
+def Add : AluOpcode;
+def Mul : AluOpcode;
+def Rem : Opcode {
+  let Types = [NumberTypeClass];
+  let HasGroup = 1;
+}
 
 def Shl : Opcode {
   let Types = [IntegerTypeClass, IntegerTypeClass];
@@ -460,6 +437,14 @@ def Shr : Opcode {
   let HasGroup = 1;
 }
 
+def BitAnd : IntegerOpcode;
+def BitOr : IntegerOpcode;
+def Div : Opcode {
+  let Types = [NumberTypeClass];
+  let HasGroup = 1;
+}
+def BitXor : IntegerOpcode;
+
 //===----------------------------------------------------------------------===//
 // Unary operators.
 //===----------------------------------------------------------------------===//
@@ -477,19 +462,20 @@ def DecPop: IntegerOpcode;
 
 // [Real] -> [Real]
 def Neg: Opcode {
-  let Types = [NonPtrTypeClass];
+  let Types = [AluTypeClass];
   let HasGroup = 1;
 }
 
 // [Real] -> [Real]
 def Comp: Opcode {
-  let Types = [IntegerTypeClass];
+  let Types = [NumberTypeClass];
   let HasGroup = 1;
 }
 
 //===----------------------------------------------------------------------===//
-// Cast, CastFP.
+// Cast.
 //===----------------------------------------------------------------------===//
+// TODO: Expand this to handle casts between more types.
 
 def FromCastTypeClass : TypeClass {
   let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
@@ -504,25 +490,6 @@ def Cast: Opcode {
   let HasGroup = 1;
 }
 
-def CastFP : Opcode {
-  let Types = [];
-  let Args = [ArgFltSemantics, ArgRoundingMode];
-}
-
-// Cast an integer to a floating type
-def CastIntegralFloating : Opcode {
-  let Types = [AluTypeClass];
-  let Args = [ArgFltSemantics, ArgRoundingMode];
-  let HasGroup = 1;
-}
-
-// Cast a floating to an integer type
-def CastFloatingIntegral : Opcode {
-  let Types = [AluTypeClass];
-  let Args = [];
-  let HasGroup = 1;
-}
-
 //===----------------------------------------------------------------------===//
 // Comparison opcodes.
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/PrimType.cpp b/clang/lib/AST/Interp/PrimType.cpp
index da07b6f0fb0c6..eda90e1c36c20 100644
--- a/clang/lib/AST/Interp/PrimType.cpp
+++ b/clang/lib/AST/Interp/PrimType.cpp
@@ -8,7 +8,6 @@
 
 #include "PrimType.h"
 #include "Boolean.h"
-#include "Floating.h"
 #include "Pointer.h"
 
 using namespace clang;

diff  --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index 042325ad8428f..c8f2a600fb3ca 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -23,7 +23,6 @@ namespace interp {
 
 class Pointer;
 class Boolean;
-class Floating;
 
 /// Enumeration of the primitive types of the VM.
 enum PrimType : unsigned {
@@ -36,7 +35,6 @@ enum PrimType : unsigned {
   PT_Sint64,
   PT_Uint64,
   PT_Bool,
-  PT_Float,
   PT_Ptr,
 };
 
@@ -50,7 +48,6 @@ template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; };
 template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; };
 template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; };
 template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; };
-template <> struct PrimConv<PT_Float> { using T = Floating; };
 template <> struct PrimConv<PT_Bool> { using T = Boolean; };
 template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
 
@@ -80,7 +77,6 @@ inline bool isPrimitiveIntegral(PrimType Type) {
   case PT_Uint32:
   case PT_Sint64:
   case PT_Uint64:
-  case PT_Float:
     return true;
   default:
     return false;
@@ -105,7 +101,6 @@ inline bool isPrimitiveIntegral(PrimType Type) {
       TYPE_SWITCH_CASE(PT_Uint32, B)                                           \
       TYPE_SWITCH_CASE(PT_Sint64, B)                                           \
       TYPE_SWITCH_CASE(PT_Uint64, B)                                           \
-      TYPE_SWITCH_CASE(PT_Float, B)                                            \
       TYPE_SWITCH_CASE(PT_Bool, B)                                             \
       TYPE_SWITCH_CASE(PT_Ptr, B)                                              \
     }                                                                          \

diff  --git a/clang/lib/AST/Interp/Primitives.h b/clang/lib/AST/Interp/Primitives.h
deleted file mode 100644
index e935dbfd3691c..0000000000000
--- a/clang/lib/AST/Interp/Primitives.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//===------ Primitives.h - Types for the constexpr VM -----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Utilities and helper functions for all primitive types:
-//  - Integral
-//  - Floating
-//  - Boolean
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_INTERP_PRIMITIVES_H
-#define LLVM_CLANG_AST_INTERP_PRIMITIVES_H
-
-#include "clang/AST/ComparisonCategories.h"
-
-namespace clang {
-namespace interp {
-
-/// Helper to compare two comparable types.
-template <typename T> ComparisonCategoryResult Compare(const T &X, const T &Y) {
-  if (X < Y)
-    return ComparisonCategoryResult::Less;
-  if (X > Y)
-    return ComparisonCategoryResult::Greater;
-  return ComparisonCategoryResult::Equal;
-}
-
-} // namespace interp
-} // namespace clang
-
-#endif

diff  --git a/clang/test/AST/Interp/const-fpfeatures.cpp b/clang/test/AST/Interp/const-fpfeatures.cpp
deleted file mode 100644
index 8f5d872916674..0000000000000
--- a/clang/test/AST/Interp/const-fpfeatures.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-// RUN: %clang_cc1 -S -emit-llvm -triple i386-linux -std=c++2a -Wno-unknown-pragmas %s -o - | FileCheck %s
-// RUN: %clang_cc1 -S -emit-llvm -triple i386-linux -fexperimental-new-constant-interpreter -std=c++2a -Wno-unknown-pragmas %s -o - | FileCheck %s
-
-
-#pragma STDC FENV_ROUND FE_UPWARD
-
-float F1u = 1.0F + 0x0.000002p0F;
-float F2u = 1.0F + 0x0.000001p0F;
-float F3u = 0x1.000001p0;
-// CHECK: @F1u = {{.*}} float 0x3FF0000020000000
-// CHECK: @F2u = {{.*}} float 0x3FF0000020000000
-// CHECK: @F3u = {{.*}} float 0x3FF0000020000000
-
-float FI1u = 0xFFFFFFFFU;
-// CHECK: @FI1u = {{.*}} float 0x41F0000000000000
-
-#pragma STDC FENV_ROUND FE_DOWNWARD
-
-float F1d = 1.0F + 0x0.000002p0F;
-float F2d = 1.0F + 0x0.000001p0F;
-float F3d = 0x1.000001p0;
-
-// CHECK: @F1d = {{.*}} float 0x3FF0000020000000
-// CHECK: @F2d = {{.*}} float 1.000000e+00
-// CHECK: @F3d = {{.*}} float 1.000000e+00
-
-
-float FI1d = 0xFFFFFFFFU;
-// CHECK: @FI1d = {{.*}} float 0x41EFFFFFE0000000
-
-// nextUp(1.F) == 0x1.000002p0F
-
-constexpr float add_round_down(float x, float y) {
-  #pragma STDC FENV_ROUND FE_DOWNWARD
-  float res = x;
-  res = res + y;
-  return res;
-}
-
-constexpr float add_round_up(float x, float y) {
-  #pragma STDC FENV_ROUND FE_UPWARD
-  float res = x;
-  res = res + y;
-  return res;
-}
-
-float V1 = add_round_down(1.0F, 0x0.000001p0F);
-float V2 = add_round_up(1.0F, 0x0.000001p0F);
-// CHECK: @V1 = {{.*}} float 1.000000e+00
-// CHECK: @V2 = {{.*}} float 0x3FF0000020000000
-
-
-/// FIXME: The following tests need support for compound assign operators
-///   with LHS and RHS of 
diff erent semantics.
-#if 0
-constexpr float add_cast_round_down(float x, double y) {
-  #pragma STDC FENV_ROUND FE_DOWNWARD
-  float res = x;
-  res += y;
-  return res;
-}
-
-constexpr float add_cast_round_up(float x, double y) {
-  #pragma STDC FENV_ROUND FE_UPWARD
-  float res = x;
-  res += y;
-  return res;
-}
-
-float V3 = add_cast_round_down(1.0F, 0x0.000001p0F);
-float V4 = add_cast_round_up(1.0F, 0x0.000001p0F);
-
-
-#endif

diff  --git a/clang/test/AST/Interp/floats.cpp b/clang/test/AST/Interp/floats.cpp
deleted file mode 100644
index 9c9831c3f10a0..0000000000000
--- a/clang/test/AST/Interp/floats.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
-// RUN: %clang_cc1 -verify=ref %s
-
-constexpr int i = 2;
-constexpr float f = 1.0f;
-static_assert(f == 1.0f, "");
-
-constexpr float f2 = 1u * f;
-static_assert(f2 == 1.0f, "");
-
-constexpr float f3 = 1.5;
-constexpr int i3 = f3;
-static_assert(i3 == 1);
-
-constexpr bool b3 = f3;
-static_assert(b3);
-
-
-static_assert(1.0f + 3u == 4, "");
-static_assert(4.0f / 1.0f == 4, "");
-static_assert(10.0f * false == 0, "");
-
-constexpr float floats[] = {1.0f, 2.0f, 3.0f, 4.0f};
-
-constexpr float m = 5.0f / 0.0f; // ref-error {{must be initialized by a constant expression}} \
-                                 // ref-note {{division by zero}} \
-                                 // expected-error {{must be initialized by a constant expression}} \
-                                 // expected-note {{division by zero}}
-
-static_assert(~2.0f == 3, ""); // ref-error {{invalid argument type 'float' to unary expression}} \
-                               // expected-error {{invalid argument type 'float' to unary expression}}
-
-/// Initialized by a double.
-constexpr float df = 0.0;
-/// The other way around.
-constexpr double fd = 0.0f;
-
-static_assert(0.0f == -0.0f, "");
-
-const int k = 3 * (1.0f / 3.0f);
-static_assert(k == 1, "");
-
-constexpr bool b = 1.0;
-static_assert(b, "");
-
-constexpr double db = true;
-static_assert(db == 1.0, "");
-
-constexpr float fa[] = {1.0f, 2.0, 1, false};
-constexpr double da[] = {1.0f, 2.0, 1, false};
-
-constexpr float fm = __FLT_MAX__;
-constexpr int someInt = fm; // ref-error {{must be initialized by a constant expression}} \
-                            // ref-note {{is outside the range of representable values}} \
-                            // expected-error {{must be initialized by a constant expression}} \
-                            // expected-note {{is outside the range of representable values}}

diff  --git a/clang/test/SemaCXX/rounding-math.cpp b/clang/test/SemaCXX/rounding-math.cpp
index 73f9f10e6d594..867534e6a20da 100644
--- a/clang/test/SemaCXX/rounding-math.cpp
+++ b/clang/test/SemaCXX/rounding-math.cpp
@@ -1,6 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-linux -verify=norounding -Wno-unknown-pragmas %s
 // RUN: %clang_cc1 -triple x86_64-linux -verify=rounding %s -frounding-math -Wno-unknown-pragmas
-// RUN: %clang_cc1 -triple x86_64-linux -verify=rounding %s -frounding-math -fexperimental-new-constant-interpreter -Wno-unknown-pragmas
 // rounding-no-diagnostics
 
 #define fold(x) (__builtin_constant_p(x) ? (x) : (x))


        


More information about the cfe-commits mailing list