[clang] [clang][Interp] Add IntegralAP for arbitrary-precision integers (PR #65844)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 15 03:58:41 PDT 2023


Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm/llvm-project/pull/65844/clang at github.com>


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

>From db98faff4cfc86657ee8f47dac0e1e2a441049b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 9 Sep 2023 10:34:26 +0200
Subject: [PATCH 1/3] [clang][Interp] Add IntegralAP for arbitrary-precision
 integers

---
 clang/lib/AST/Interp/ByteCodeExprGen.cpp |  11 +-
 clang/lib/AST/Interp/Context.cpp         |   6 +-
 clang/lib/AST/Interp/Descriptor.cpp      |   9 +
 clang/lib/AST/Interp/EvalEmitter.cpp     |   1 +
 clang/lib/AST/Interp/Integral.h          |   4 +
 clang/lib/AST/Interp/IntegralAP.h        | 253 +++++++++++++++++++++++
 clang/lib/AST/Interp/Interp.h            |  21 +-
 clang/lib/AST/Interp/InterpStack.h       |   5 +
 clang/lib/AST/Interp/Opcodes.td          |   8 +-
 clang/lib/AST/Interp/PrimType.cpp        |   1 +
 clang/lib/AST/Interp/PrimType.h          |  13 ++
 clang/test/AST/Interp/literals.cpp       |  24 +++
 12 files changed, 343 insertions(+), 13 deletions(-)
 create mode 100644 clang/lib/AST/Interp/IntegralAP.h

diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index e49dc80a5c9ce7c..1d7b8201ae92802 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -171,14 +171,17 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
       return this->discard(SubExpr);
     std::optional<PrimType> FromT = classify(SubExpr->getType());
     std::optional<PrimType> ToT = classify(CE->getType());
+
     if (!FromT || !ToT)
       return false;
 
     if (!this->visit(SubExpr))
       return false;
 
-    if (FromT == ToT)
+    if (FromT == ToT) {
+      assert(ToT != PT_IntAP && ToT != PT_IntAPS);
       return true;
+    }
 
     return this->emitCast(*FromT, *ToT, CE);
   }
@@ -1596,6 +1599,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(QualType QT,
     return this->emitZeroSint64(E);
   case PT_Uint64:
     return this->emitZeroUint64(E);
+  case PT_IntAP:
+  case PT_IntAPS:
+    assert(false);
   case PT_Ptr:
     return this->emitNullPtr(E);
   case PT_FnPtr:
@@ -1835,6 +1841,9 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
     return this->emitConstSint64(Value, E);
   case PT_Uint64:
     return this->emitConstUint64(Value, E);
+  case PT_IntAP:
+  case PT_IntAPS:
+    assert(false);
   case PT_Bool:
     return this->emitConstBool(Value, E);
   case PT_Ptr:
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 1a732b6c1a092ac..ed2b23514e86665 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -102,7 +102,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
     case 8:
       return PT_Sint8;
     default:
-      return std::nullopt;
+      return PT_IntAPS;
+      // return std::nullopt;
     }
   }
 
@@ -117,7 +118,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
     case 8:
       return PT_Uint8;
     default:
-      return std::nullopt;
+      return PT_IntAP;
+      // return std::nullopt;
     }
   }
 
diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index db49a569eff33ea..4ecb7466998e705 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -10,6 +10,7 @@
 #include "Boolean.h"
 #include "Floating.h"
 #include "FunctionPointer.h"
+#include "IntegralAP.h"
 #include "Pointer.h"
 #include "PrimType.h"
 #include "Record.h"
@@ -182,6 +183,10 @@ static BlockCtorFn getCtorPrim(PrimType Type) {
   // constructor called.
   if (Type == PT_Float)
     return ctorTy<PrimConv<PT_Float>::T>;
+  if (Type == PT_IntAP)
+    return ctorTy<PrimConv<PT_IntAP>::T>;
+  if (Type == PT_IntAPS)
+    return ctorTy<PrimConv<PT_IntAPS>::T>;
 
   COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
 }
@@ -191,6 +196,10 @@ static BlockDtorFn getDtorPrim(PrimType Type) {
   // destructor called, since they might allocate memory.
   if (Type == PT_Float)
     return dtorTy<PrimConv<PT_Float>::T>;
+  if (Type == PT_IntAP)
+    return dtorTy<PrimConv<PT_IntAP>::T>;
+  if (Type == PT_IntAPS)
+    return dtorTy<PrimConv<PT_IntAPS>::T>;
 
   COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
 }
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index d26ee8e40a437b9..c9332d8b2364fa1 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -8,6 +8,7 @@
 
 #include "EvalEmitter.h"
 #include "Context.h"
+#include "IntegralAP.h"
 #include "Interp.h"
 #include "Opcode.h"
 #include "Program.h"
diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index 72285cabcbbf8ce..f8e529aa3392696 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -29,6 +29,8 @@ namespace interp {
 using APInt = llvm::APInt;
 using APSInt = llvm::APSInt;
 
+template <bool Signed> class IntegralAP;
+
 // Helper structure to select the representation.
 template <unsigned Bits, bool Signed> struct Repr;
 template <> struct Repr<8, false> { using Type = uint8_t; };
@@ -61,6 +63,8 @@ template <unsigned Bits, bool Signed> class Integral final {
   template <typename T> explicit Integral(T V) : V(V) {}
 
 public:
+  using AsUnsigned = Integral<Bits, false>;
+
   /// Zero-initializes an integral.
   Integral() : V(0) {}
 
diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
new file mode 100644
index 000000000000000..236430c36883a3e
--- /dev/null
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -0,0 +1,253 @@
+//===--- Integral.h - Wrapper for numeric types for the 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_INTEGRAL_AP_H
+#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+#include "Primitives.h"
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+template <unsigned Bits, bool Signed> class Integral;
+class Boolean;
+
+template <bool Signed> class IntegralAP final {
+public:
+  APSInt V;
+
+public:
+  using AsUnsigned = IntegralAP<false>;
+
+  template <typename T>
+  IntegralAP(T Value) : V(APInt(sizeof(T) * 8, Value, std::is_signed_v<T>)) {}
+
+  IntegralAP(APInt V) : V(V) {}
+  IntegralAP(APSInt V) : V(V) {}
+  IntegralAP(bool b) : V(APInt(8, b, Signed)) {}
+  /// Bullshit value for initialized variables.
+  IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {}
+
+  IntegralAP operator-() const { return IntegralAP(-V); }
+  // bool operator <=> (const IntegralAP &RHS) const = default;
+  bool operator>(IntegralAP RHS) const { return V > RHS.V; }
+  bool operator>=(IntegralAP RHS) const { return V >= RHS.V; }
+  bool operator<(IntegralAP RHS) const { return V < RHS.V; }
+  bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
+
+  explicit operator bool() const { return !V.isZero(); }
+  explicit operator int8_t() const { return V.getSExtValue(); }
+  explicit operator uint8_t() const { return V.getZExtValue(); }
+  explicit operator int16_t() const { return V.getSExtValue(); }
+  explicit operator uint16_t() const { return V.getZExtValue(); }
+  explicit operator int32_t() const { return V.getSExtValue(); }
+  explicit operator uint32_t() const { return V.getZExtValue(); }
+  explicit operator int64_t() const { return V.getSExtValue(); }
+  explicit operator uint64_t() const { return V.getZExtValue(); }
+
+  template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
+    assert(NumBits > 0);
+    APSInt Copy = APSInt(APInt(NumBits, Value, Signed), !Signed);
+
+    return IntegralAP<Signed>(Copy);
+  }
+
+  template <bool InputSigned>
+  static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
+    if constexpr (Signed == InputSigned)
+      return V;
+
+    APSInt Copy = V.V;
+    Copy.setIsSigned(Signed);
+
+    return IntegralAP<Signed>(Copy);
+  }
+
+  template <unsigned Bits, bool InputSigned>
+  static IntegralAP from(Integral<Bits, InputSigned> I) {
+    assert(InputSigned);
+    /// TODO: Take bits parameter.
+    APSInt Copy =
+        APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
+    Copy.setIsSigned(Signed);
+
+    assert(Copy.isSigned() == Signed);
+    return IntegralAP<Signed>(Copy);
+  }
+  static IntegralAP from(const Boolean &B) {
+    assert(false);
+    return IntegralAP::zero();
+  }
+
+  static IntegralAP zero() {
+    assert(false);
+    return IntegralAP(0);
+  }
+
+  static constexpr unsigned bitWidth() { return 128; }
+
+  APSInt toAPSInt(unsigned Bits = 0) const { return V; }
+  APValue toAPValue() const { return APValue(V); }
+
+  bool isZero() const { return false; }
+  bool isPositive() const { return true; }
+  bool isNegative() const { return false; }
+  bool isMin() const { return false; }
+  bool isMax() const { return false; }
+  static bool isSigned() { return Signed; }
+  bool isMinusOne() const { return false; }
+
+  unsigned countLeadingZeros() const { return V.countl_zero(); }
+
+  void print(llvm::raw_ostream &OS) const { OS << V; }
+
+  IntegralAP truncate(unsigned bitWidth) const { return V; }
+  IntegralAP<false> toUnsigned() const {
+    APSInt Copy = V;
+    Copy.setIsSigned(false);
+    return IntegralAP<false>(Copy);
+  }
+
+  ComparisonCategoryResult compare(const IntegralAP &RHS) const {
+    return Compare(V, RHS.V);
+  }
+
+  static bool increment(IntegralAP A, IntegralAP *R) {
+    *R = IntegralAP(A.V - 1);
+    return false;
+  }
+
+  static bool decrement(IntegralAP A, IntegralAP *R) {
+    *R = IntegralAP(A.V - 1);
+    return false;
+  }
+
+  static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+    /// TODO: Gotta check if the result fits into OpBits bits.
+    return CheckAddUB(A, B, OpBits, R);
+  }
+
+  static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+    /// TODO: Gotta check if the result fits into OpBits bits.
+    return CheckSubUB(A, B, R);
+  }
+
+  static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+    assert(false);
+    // return CheckMulUB(A.V, B.V, R->V);
+    return false;
+  }
+
+  static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(A.V % B.V);
+    return false;
+  }
+
+  static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(A.V / B.V);
+    return false;
+  }
+
+  static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
+                     IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(A.V & B.V);
+    return false;
+  }
+
+  static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
+                    IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(A.V | B.V);
+    return false;
+  }
+
+  static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
+                     IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(A.V ^ B.V);
+    return false;
+  }
+
+  static bool neg(const IntegralAP &A, IntegralAP *R) {
+    APSInt AI = A.V;
+
+    AI.setIsSigned(Signed);
+    *R = IntegralAP(AI);
+    return false;
+  }
+
+  static bool comp(IntegralAP A, IntegralAP *R) {
+    assert(false);
+    *R = IntegralAP(~A.V);
+    return false;
+  }
+
+  static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
+                        IntegralAP *R) {
+    *R = IntegralAP(A.V << B.V.getZExtValue());
+  }
+
+  static void shiftRight(const IntegralAP A, const IntegralAP B,
+                         unsigned OpBits, IntegralAP *R) {
+    *R = IntegralAP(A.V >> B.V.getZExtValue());
+  }
+
+private:
+  static bool CheckAddUB(const IntegralAP &A, const IntegralAP &B,
+                         unsigned BitWidth, IntegralAP *R) {
+    if (!A.isSigned()) {
+      R->V = A.V + B.V;
+      return false;
+    }
+
+    const APSInt &LHS = A.V;
+    const APSInt &RHS = B.V;
+
+    APSInt Value(LHS.extend(BitWidth) + RHS.extend(BitWidth), false);
+    APSInt Result = Value.trunc(LHS.getBitWidth());
+    if (Result.extend(BitWidth) != Value)
+      return true;
+
+    R->V = Result;
+    return false;
+  }
+  static bool CheckSubUB(const IntegralAP &A, const IntegralAP &B,
+                         IntegralAP *R) {
+    R->V = A.V - B.V;
+    return false; // Success!
+  }
+};
+
+template <bool Signed>
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     IntegralAP<Signed> I) {
+  I.print(OS);
+  return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index b109f2bda17bfb1..a417111bcfa9321 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -286,7 +286,11 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
     return true;
   } else {
     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
-    return S.noteUndefinedBehavior();
+    if (!S.noteUndefinedBehavior()) {
+      S.Stk.pop<T>();
+      return false;
+    }
+    return true;
   }
 }
 
@@ -1623,9 +1627,11 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
     return false;
 
-  Integral<LT::bitWidth(), false> R;
-  Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
-  S.Stk.push<LT>(R);
+  typename LT::AsUnsigned R;
+  LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
+                             LT::AsUnsigned::from(RHS), Bits, &R);
+  S.Stk.push<LT>(LT::from(R));
+
   return true;
 }
 
@@ -1640,9 +1646,10 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
     return false;
 
-  Integral<LT::bitWidth(), false> R;
-  Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
-  S.Stk.push<LT>(R);
+  typename LT::AsUnsigned R;
+  LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
+                            LT::AsUnsigned::from(RHS), Bits, &R);
+  S.Stk.push<LT>(LT::from(R));
   return true;
 }
 
diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h
index ab4351a6dc679fd..3fd0f63c781fc70 100644
--- a/clang/lib/AST/Interp/InterpStack.h
+++ b/clang/lib/AST/Interp/InterpStack.h
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
 
 #include "FunctionPointer.h"
+#include "IntegralAP.h"
 #include "PrimType.h"
 #include <memory>
 #include <vector>
@@ -183,6 +184,10 @@ class InterpStack final {
       return PT_Float;
     else if constexpr (std::is_same_v<T, FunctionPointer>)
       return PT_FnPtr;
+    else if constexpr (std::is_same_v<T, IntegralAP<true>>)
+      return PT_IntAP;
+    else if constexpr (std::is_same_v<T, IntegralAP<false>>)
+      return PT_IntAP;
 
     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 e0c7cf1eaf92489..f8136caa0f5adff 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -25,6 +25,8 @@ def Sint32 : Type;
 def Uint32 : Type;
 def Sint64 : Type;
 def Uint64 : Type;
+def IntAP : Type;
+def IntAPS : Type;
 def Float : Type;
 def Ptr : Type;
 def FnPtr : Type;
@@ -65,7 +67,7 @@ class TypeClass {
 
 def IntegerTypeClass : TypeClass {
   let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
-               Uint32, Sint64, Uint64];
+               Uint32, Sint64, Uint64, IntAP, IntAPS];
 }
 
 def NumberTypeClass : TypeClass {
@@ -552,11 +554,11 @@ def Comp: Opcode {
 //===----------------------------------------------------------------------===//
 
 def FromCastTypeClass : TypeClass {
-  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS];
 }
 
 def ToCastTypeClass : TypeClass {
-  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+  let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool, IntAP, IntAPS];
 }
 
 def Cast: Opcode {
diff --git a/clang/lib/AST/Interp/PrimType.cpp b/clang/lib/AST/Interp/PrimType.cpp
index a9b5d8ea8cc8c7c..9b96dcfe6a272fc 100644
--- a/clang/lib/AST/Interp/PrimType.cpp
+++ b/clang/lib/AST/Interp/PrimType.cpp
@@ -10,6 +10,7 @@
 #include "Boolean.h"
 #include "Floating.h"
 #include "FunctionPointer.h"
+#include "IntegralAP.h"
 #include "Pointer.h"
 
 using namespace clang;
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index 7c7ee6120b89a4a..8c5e87f37be1867 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -25,6 +25,7 @@ class Pointer;
 class Boolean;
 class Floating;
 class FunctionPointer;
+template <bool Signed> class IntegralAP;
 template <unsigned Bits, bool Signed> class Integral;
 
 /// Enumeration of the primitive types of the VM.
@@ -37,6 +38,8 @@ enum PrimType : unsigned {
   PT_Uint32,
   PT_Sint64,
   PT_Uint64,
+  PT_IntAP,
+  PT_IntAPS,
   PT_Bool,
   PT_Float,
   PT_Ptr,
@@ -68,6 +71,12 @@ 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_IntAP> {
+  using T = IntegralAP<false>;
+};
+template <> struct PrimConv<PT_IntAPS> {
+  using T = IntegralAP<true>;
+};
 template <> struct PrimConv<PT_Float> { using T = Floating; };
 template <> struct PrimConv<PT_Bool> { using T = Boolean; };
 template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
@@ -108,6 +117,8 @@ static inline bool aligned(const void *P) {
       TYPE_SWITCH_CASE(PT_Uint32, B)                                           \
       TYPE_SWITCH_CASE(PT_Sint64, B)                                           \
       TYPE_SWITCH_CASE(PT_Uint64, B)                                           \
+      TYPE_SWITCH_CASE(PT_IntAP, B)                                            \
+      TYPE_SWITCH_CASE(PT_IntAPS, B)                                           \
       TYPE_SWITCH_CASE(PT_Float, B)                                            \
       TYPE_SWITCH_CASE(PT_Bool, B)                                             \
       TYPE_SWITCH_CASE(PT_Ptr, B)                                              \
@@ -126,6 +137,8 @@ static inline bool aligned(const void *P) {
       TYPE_SWITCH_CASE(PT_Uint32, B)                                           \
       TYPE_SWITCH_CASE(PT_Sint64, B)                                           \
       TYPE_SWITCH_CASE(PT_Uint64, B)                                           \
+      TYPE_SWITCH_CASE(PT_IntAP, B)                                            \
+      TYPE_SWITCH_CASE(PT_IntAPS, B)                                           \
       TYPE_SWITCH_CASE(PT_Bool, B)                                             \
     default:                                                                   \
       llvm_unreachable("Not an integer value");                                \
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index dae1d5af6f7ae38..058074434f0eb9d 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -7,6 +7,8 @@
 #define INT_MAX __INT_MAX__
 
 typedef __INTPTR_TYPE__ intptr_t;
+typedef __int128 int128_t;
+typedef unsigned __int128 uint128_t;
 
 
 static_assert(true, "");
@@ -26,6 +28,28 @@ static_assert(number != 10, ""); // expected-error{{failed}} \
                                  // expected-note{{evaluates to}} \
                                  // ref-note{{evaluates to}}
 
+
+namespace i128 {
+  constexpr int128_t I128_1 = 12;
+  static_assert(I128_1 == 12, "");
+  static_assert(I128_1 != 10, "");
+  static_assert(I128_1 != 12, ""); // expected-error{{failed}} \
+                                   // ref-error{{failed}} \
+                                   // expected-note{{evaluates to}} \
+                                   // ref-note{{evaluates to}}
+
+  static const __uint128_t UINT128_MAX =__uint128_t(__int128_t(-1L));
+  static_assert(UINT128_MAX == -1, "");
+
+  static const __int128_t INT128_MAX = UINT128_MAX >> (__int128_t)1;
+  static_assert(INT128_MAX != 0, "");
+  static const __int128_t INT128_MIN = -INT128_MAX - 1;
+  constexpr __int128 A = INT128_MAX + 1; // expected-error {{must be initialized by a constant expression}} \
+                                         // expected-note {{outside the range}} \
+                                         // ref-error {{must be initialized by a constant expression}} \
+                                         // ref-note {{outside the range}}
+}
+
 constexpr bool b = number;
 static_assert(b, "");
 constexpr int one = true;

>From a58ae5a047c9bb6a8b3f03f853b4908f8981f7e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 12 Sep 2023 13:10:36 +0200
Subject: [PATCH 2/3] Address review comments

---
 clang/lib/AST/Interp/Context.cpp  |  2 --
 clang/lib/AST/Interp/IntegralAP.h | 21 +++++++++------------
 2 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index ed2b23514e86665..395fbc86fdfd549 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -103,7 +103,6 @@ std::optional<PrimType> Context::classify(QualType T) const {
       return PT_Sint8;
     default:
       return PT_IntAPS;
-      // return std::nullopt;
     }
   }
 
@@ -119,7 +118,6 @@ std::optional<PrimType> Context::classify(QualType T) const {
       return PT_Uint8;
     default:
       return PT_IntAP;
-      // return std::nullopt;
     }
   }
 
diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
index 236430c36883a3e..854c8dc60e6fe98 100644
--- a/clang/lib/AST/Interp/IntegralAP.h
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -43,12 +43,10 @@ template <bool Signed> class IntegralAP final {
 
   IntegralAP(APInt V) : V(V) {}
   IntegralAP(APSInt V) : V(V) {}
-  IntegralAP(bool b) : V(APInt(8, b, Signed)) {}
-  /// Bullshit value for initialized variables.
+  /// Arbitrary value for initialized variables.
   IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {}
 
   IntegralAP operator-() const { return IntegralAP(-V); }
-  // bool operator <=> (const IntegralAP &RHS) const = default;
   bool operator>(IntegralAP RHS) const { return V > RHS.V; }
   bool operator>=(IntegralAP RHS) const { return V >= RHS.V; }
   bool operator<(IntegralAP RHS) const { return V < RHS.V; }
@@ -85,7 +83,7 @@ template <bool Signed> class IntegralAP final {
   template <unsigned Bits, bool InputSigned>
   static IntegralAP from(Integral<Bits, InputSigned> I) {
     assert(InputSigned);
-    /// TODO: Take bits parameter.
+    /// FIXME: Take bits parameter.
     APSInt Copy =
         APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
     Copy.setIsSigned(Signed);
@@ -108,13 +106,13 @@ template <bool Signed> class IntegralAP final {
   APSInt toAPSInt(unsigned Bits = 0) const { return V; }
   APValue toAPValue() const { return APValue(V); }
 
-  bool isZero() const { return false; }
-  bool isPositive() const { return true; }
-  bool isNegative() const { return false; }
-  bool isMin() const { return false; }
-  bool isMax() const { return false; }
+  bool isZero() const { return V.isZero(); }
+  bool isPositive() const { return V.isNonNegative(); }
+  bool isNegative() const { return !V.isNonNegative(); }
+  bool isMin() const { return V.isMinValue(); }
+  bool isMax() const { return V.isMaxValue(); }
   static bool isSigned() { return Signed; }
-  bool isMinusOne() const { return false; }
+  bool isMinusOne() const { return Signed && V == -1; }
 
   unsigned countLeadingZeros() const { return V.countl_zero(); }
 
@@ -142,12 +140,11 @@ template <bool Signed> class IntegralAP final {
   }
 
   static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
-    /// TODO: Gotta check if the result fits into OpBits bits.
     return CheckAddUB(A, B, OpBits, R);
   }
 
   static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
-    /// TODO: Gotta check if the result fits into OpBits bits.
+    /// FIXME: Gotta check if the result fits into OpBits bits.
     return CheckSubUB(A, B, R);
   }
 

>From e37b660a44428871d372f6b6dbe1e2702d942ee9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Fri, 15 Sep 2023 12:57:52 +0200
Subject: [PATCH 3/3] Handle ::from for unsigned inputs

---
 clang/lib/AST/Interp/IntegralAP.h  | 3 +--
 clang/test/AST/Interp/literals.cpp | 2 ++
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
index 854c8dc60e6fe98..735256286198ec8 100644
--- a/clang/lib/AST/Interp/IntegralAP.h
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -82,8 +82,7 @@ template <bool Signed> class IntegralAP final {
 
   template <unsigned Bits, bool InputSigned>
   static IntegralAP from(Integral<Bits, InputSigned> I) {
-    assert(InputSigned);
-    /// FIXME: Take bits parameter.
+    // FIXME: Take bits parameter.
     APSInt Copy =
         APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
     Copy.setIsSigned(Signed);
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 058074434f0eb9d..4dcb13915b72d29 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -48,6 +48,8 @@ namespace i128 {
                                          // expected-note {{outside the range}} \
                                          // ref-error {{must be initialized by a constant expression}} \
                                          // ref-note {{outside the range}}
+  constexpr int128_t Two = (int128_t)1 << 1ul;
+  static_assert(Two == 2, "");
 }
 
 constexpr bool b = number;



More information about the cfe-commits mailing list