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

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 11 06:57:25 PDT 2023


================
@@ -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.
----------------
erichkeane wrote:

Typically these would be "FIXME", TODOs generally shouldn't be upstreamed.

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


More information about the cfe-commits mailing list