tbaeder updated this revision to Diff 464156.
tbaeder marked an inline comment as done.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134859/new/

https://reviews.llvm.org/D134859

Files:
  clang/lib/AST/Interp/Boolean.h
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Context.cpp
  clang/lib/AST/Interp/Floating.h
  clang/lib/AST/Interp/Integral.h
  clang/lib/AST/Interp/InterpStack.h
  clang/lib/AST/Interp/Opcodes.td
  clang/lib/AST/Interp/PrimType.h
  clang/lib/AST/Interp/Primitives.h
  clang/test/AST/Interp/literals.cpp

Index: clang/test/AST/Interp/literals.cpp
===================================================================
--- clang/test/AST/Interp/literals.cpp
+++ clang/test/AST/Interp/literals.cpp
@@ -253,3 +253,27 @@
 #endif
 
 };
+
+namespace floats {
+  constexpr int i = 2;
+  constexpr float f = 1.0f;
+  static_assert(f == 1.0f, "");
+
+  constexpr float f2 = 1u * f;
+  static_assert(f2 == 1.0f, "");
+
+  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}}
+
+};
Index: clang/lib/AST/Interp/Primitives.h
===================================================================
--- /dev/null
+++ clang/lib/AST/Interp/Primitives.h
@@ -0,0 +1,34 @@
+//===------ 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
+
+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
Index: clang/lib/AST/Interp/PrimType.h
===================================================================
--- clang/lib/AST/Interp/PrimType.h
+++ clang/lib/AST/Interp/PrimType.h
@@ -13,11 +13,12 @@
 #ifndef LLVM_CLANG_AST_INTERP_TYPE_H
 #define LLVM_CLANG_AST_INTERP_TYPE_H
 
+#include "Boolean.h"
+#include "Floating.h"
+#include "Integral.h"
 #include <climits>
 #include <cstddef>
 #include <cstdint>
-#include "Boolean.h"
-#include "Integral.h"
 
 namespace clang {
 namespace interp {
@@ -35,6 +36,7 @@
   PT_Sint64,
   PT_Uint64,
   PT_Bool,
+  PT_Float32,
   PT_Ptr,
 };
 
@@ -48,6 +50,7 @@
 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_Float32> { using T = Floating<32>; };
 template <> struct PrimConv<PT_Bool> { using T = Boolean; };
 template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
 
@@ -70,6 +73,7 @@
   case PT_Uint32:
   case PT_Sint64:
   case PT_Uint64:
+  case PT_Float32:
     return true;
   default:
     return false;
@@ -94,6 +98,7 @@
       TYPE_SWITCH_CASE(PT_Uint32, B)                                           \
       TYPE_SWITCH_CASE(PT_Sint64, B)                                           \
       TYPE_SWITCH_CASE(PT_Uint64, B)                                           \
+      TYPE_SWITCH_CASE(PT_Float32, B)                                          \
       TYPE_SWITCH_CASE(PT_Bool, B)                                             \
       TYPE_SWITCH_CASE(PT_Ptr, B)                                              \
     }                                                                          \
Index: clang/lib/AST/Interp/Opcodes.td
===================================================================
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -25,6 +25,7 @@
 def Uint32 : Type;
 def Sint64 : Type;
 def Uint64 : Type;
+def Float32 : Type;
 def Ptr : Type;
 
 //===----------------------------------------------------------------------===//
@@ -40,6 +41,7 @@
 def ArgUint32 : ArgType { let Name = "uint32_t"; }
 def ArgSint64 : ArgType { let Name = "int64_t"; }
 def ArgUint64 : ArgType { let Name = "uint64_t"; }
+def ArgFloat32 : ArgType { let Name = "float"; }
 def ArgBool : ArgType { let Name = "bool"; }
 
 def ArgFunction : ArgType { let Name = "const Function *"; }
@@ -54,11 +56,15 @@
   list<Type> Types;
 }
 
-def NumberTypeClass : TypeClass {
+def IntegerTypeClass : TypeClass {
   let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
                Uint32, Sint64, Uint64];
 }
 
+def NumberTypeClass : TypeClass {
+  let Types = !listconcat(IntegerTypeClass.Types, [Float32]);
+}
+
 def AluTypeClass : TypeClass {
   let Types = !listconcat(NumberTypeClass.Types, [Bool]);
 }
@@ -192,6 +198,7 @@
 def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
 def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
 def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
+def ConstFloat32 : ConstOpcode<Float32, ArgFloat32>;
 def ConstBool : ConstOpcode<Bool, ArgBool>;
 
 // [] -> [Integer]
@@ -385,9 +392,15 @@
 //===----------------------------------------------------------------------===//
 
 // [Pointer, Integral] -> [Pointer]
-def AddOffset : AluOpcode;
+def AddOffset : Opcode {
+  let Types = [IntegerTypeClass];
+  let HasGroup = 1;
+}
 // [Pointer, Integral] -> [Pointer]
-def SubOffset : AluOpcode;
+def SubOffset : Opcode {
+  let Types = [IntegerTypeClass];
+  let HasGroup = 1;
+}
 
 //===----------------------------------------------------------------------===//
 // Binary operators.
@@ -398,7 +411,7 @@
 def Add : AluOpcode;
 def Mul : AluOpcode;
 def Rem : Opcode {
-  let Types = [NumberTypeClass];
+  let Types = [IntegerTypeClass];
   let HasGroup = 1;
 }
 def Div : Opcode {
@@ -424,7 +437,7 @@
 
 // [Real] -> [Real]
 def Comp: Opcode {
-  let Types = [NumberTypeClass];
+  let Types = [IntegerTypeClass];
   let HasGroup = 1;
 }
 
@@ -434,11 +447,11 @@
 // TODO: Expand this to handle casts between more types.
 
 def FromCastTypeClass : TypeClass {
-  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Float32, Bool];
 }
 
 def ToCastTypeClass : TypeClass {
-  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Float32, Bool];
 }
 
 def Cast: Opcode {
Index: clang/lib/AST/Interp/InterpStack.h
===================================================================
--- clang/lib/AST/Interp/InterpStack.h
+++ clang/lib/AST/Interp/InterpStack.h
@@ -160,6 +160,9 @@
     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, float> ||
+                       std::is_same_v<T, Floating<32>>)
+      return PT_Float32;
 
     llvm_unreachable("unknown type push()'ed into InterpStack");
   }
Index: clang/lib/AST/Interp/Integral.h
===================================================================
--- clang/lib/AST/Interp/Integral.h
+++ clang/lib/AST/Interp/Integral.h
@@ -21,33 +21,14 @@
 #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
@@ -56,6 +37,16 @@
 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;
@@ -105,6 +96,7 @@
   explicit operator unsigned() const { return V; }
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
+  explicit operator float() const { return V; }
 
   APSInt toAPSInt() const {
     return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
Index: clang/lib/AST/Interp/Floating.h
===================================================================
--- /dev/null
+++ clang/lib/AST/Interp/Floating.h
@@ -0,0 +1,142 @@
+//===--- 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 <limits>
+
+namespace clang {
+namespace interp {
+
+using APFloat = llvm::APFloat;
+using APSInt = llvm::APSInt;
+
+template <unsigned Bits> class Floating final {
+private:
+  template <unsigned ReprBits> struct Repr;
+  template <> struct Repr<32> { using Type = float; };
+  template <> struct Repr<64> { using Type = double; };
+
+  // The primitive representing the Floating.
+  using ReprT = typename Repr<Bits>::Type;
+  ReprT V;
+
+  /// Primitive representing limits.
+  static constexpr auto Min = std::numeric_limits<ReprT>::min();
+  static constexpr auto Max = std::numeric_limits<ReprT>::max();
+
+  /// Construct a Floating from anything that is convertible to storage.
+  template <typename T> explicit Floating(T V) : V(V) {}
+
+public:
+  /// Zero-initializes a Floating.
+  Floating() : V(0) {}
+
+  bool operator<(Floating RHS) const { return V < RHS.V; }
+  bool operator>(Floating RHS) const { return V > RHS.V; }
+  bool operator<=(Floating RHS) const { return V <= RHS.V; }
+  bool operator>=(Floating RHS) const { return V >= RHS.V; }
+  bool operator==(Floating RHS) const { return V == RHS.V; }
+  bool operator!=(Floating RHS) const { return V != RHS.V; }
+  Floating operator-() const { return Floating(-V); }
+  Floating operator~() const { return Floating(~V); }
+
+  explicit operator int8_t() const { return V; }
+  explicit operator uint8_t() const { return V; }
+  explicit operator int16_t() const { return V; }
+  explicit operator uint16_t() const { return V; }
+  explicit operator int32_t() const { return V; }
+  explicit operator uint32_t() const { return V; }
+  explicit operator int64_t() const { return V; }
+  explicit operator uint64_t() const { return V; }
+  explicit operator bool() const { return V; }
+  explicit operator ReprT() const { return V; }
+
+  APFloat toAPFloat() const { return APFloat(V); }
+  APSInt toAPSInt(unsigned NumBits = 0) const { return APSInt(V); }
+  APValue toAPValue() const { return APValue(toAPFloat()); }
+  void print(llvm::raw_ostream &OS) const { OS << V; }
+
+  constexpr static unsigned bitWidth() { return Bits; }
+  static Floating zero() { return from(0); }
+
+  bool isSigned() const { return true; }
+  bool isNegative() const { return V < 0; }
+  bool isPositive() const { return V >= 0; }
+  bool isZero() const { return V == 0; }
+  bool isMin() const { return V == Min; }
+  bool isMinusOne() const { return V == -1; }
+  bool isNan() const { return V != V; }
+
+  ComparisonCategoryResult compare(const Floating &RHS) const {
+    return Compare(V, RHS.V);
+  }
+
+  // TODO: Properly implement this(?)
+  Floating truncate(unsigned TruncBits) const {
+    if (TruncBits >= Bits)
+      return *this;
+
+    return Floating(this->V);
+  }
+
+  template <typename ValT> static Floating from(ValT Value) {
+    if constexpr (std::is_integral<ValT>::value ||
+                  std::is_floating_point<ValT>::value)
+      return Floating(Value);
+    else
+      return Floating::from(static_cast<Floating::ReprT>(Value));
+  }
+
+  template <typename T> static Floating from(T Value, unsigned NumBits) {
+    return Floating(Value);
+  }
+
+  // -------
+
+  static bool add(Floating A, Floating B, unsigned OpBits, Floating *R) {
+    *R = Floating(A.V + B.V);
+    return false;
+  }
+  static bool sub(Floating A, Floating B, unsigned OpBits, Floating *R) {
+    *R = Floating(A.V - B.V);
+    return false;
+  }
+
+  static bool neg(Floating A, Floating *R) {
+    *R = -A;
+    return false;
+  }
+
+  static bool div(Floating A, Floating B, unsigned OpBits, Floating *R) {
+    *R = Floating(A.V / B.V);
+    return false;
+  }
+
+  static bool mul(Floating A, Floating B, unsigned OpBits, Floating *R) {
+    *R = Floating(A.V * B.V);
+    return false;
+  }
+};
+
+template <unsigned Bits>
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating<Bits> F) {
+  F.print(OS);
+  return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
Index: clang/lib/AST/Interp/Context.cpp
===================================================================
--- clang/lib/AST/Interp/Context.cpp
+++ clang/lib/AST/Interp/Context.cpp
@@ -126,6 +126,13 @@
   if (T->isNullPtrType())
     return PT_Ptr;
 
+  if (T->isFloatingType()) {
+    unsigned Bits = getASTContext().getTypeSize(T);
+    if(Bits == 32)
+      return PT_Float32;
+    return None;
+  }
+
   if (auto *AT = dyn_cast<AtomicType>(T))
     return classify(AT->getValueType());
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -68,6 +68,7 @@
   // 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 VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -118,6 +118,8 @@
     return this->Visit(SubExpr);
 
   case CK_IntegralToBoolean:
+  case CK_FloatingToIntegral:
+  case CK_IntegralToFloating:
   case CK_IntegralCast: {
     Optional<PrimType> FromT = classify(SubExpr->getType());
     Optional<PrimType> ToT = classify(CE->getType());
@@ -151,6 +153,14 @@
   return this->bail(LE);
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
+  if (DiscardResult)
+    return true;
+
+  return this->emitConstFloat32(E->getValue().convertToFloat(), E);
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
   return this->Visit(PE->getSubExpr());
@@ -418,6 +428,8 @@
     return this->emitZeroUint64(E);
   case PT_Ptr:
     return this->emitNullPtr(E);
+  case PT_Float32:
+    return this->emitZeroFloat32(E);
   }
   llvm_unreachable("unknown primitive type");
 }
@@ -582,6 +594,7 @@
   case PT_Bool:
     return this->emitConstBool(Value.getBoolValue(), E);
   case PT_Ptr:
+  case PT_Float32:
     llvm_unreachable("Invalid integral type");
     break;
   }
Index: clang/lib/AST/Interp/Boolean.h
===================================================================
--- clang/lib/AST/Interp/Boolean.h
+++ clang/lib/AST/Interp/Boolean.h
@@ -56,6 +56,7 @@
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
   explicit operator bool() const { return V; }
+  explicit operator float() const { return V; }
 
   APSInt toAPSInt() const {
     return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to