tbaeder updated this revision to Diff 463785.
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
@@ -245,3 +245,24 @@
#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}}
+
+};
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 Not: 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,146 @@
+//===--- 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 integral.
+ 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; }
+
+ 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 rem(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 Bytes = getASTContext().getTypeSize(T);
+ if (Bytes == 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits