BLUELOVETH 2 лет назад
Родитель
Сommit
7254c5a491
3 измененных файлов с 91 добавлено и 39 удалено
  1. 74 14
      include/pocketpy/common.h
  2. 13 12
      include/pocketpy/obj.h
  3. 4 13
      include/pocketpy/vm.h

+ 74 - 14
include/pocketpy/common.h

@@ -76,10 +76,6 @@ struct NumberTraits<4> {
 
 	template<typename... Args>
 	static float_t stof(Args&&... args) { return std::stof(std::forward<Args>(args)...); }
-
-	static constexpr int_t c0 = 0b00000000011111111111111111111100;
-	static constexpr int_t c1 = 0b11111111111111111111111111111100;
-	static constexpr int_t c2 = 0b00000000000000000000000000000011;
 };
 
 template <>
@@ -89,18 +85,59 @@ struct NumberTraits<8> {
 
 	template<typename... Args>
 	static float_t stof(Args&&... args) { return std::stod(std::forward<Args>(args)...); }
-
-	static constexpr int_t c0 = 0b0000000000001111111111111111111111111111111111111111111111111100;
-	static constexpr int_t c1 = 0b1111111111111111111111111111111111111111111111111111111111111100;
-	static constexpr int_t c2 = 0b0000000000000000000000000000000000000000000000000000000000000011;
 };
 
 using Number = NumberTraits<sizeof(void*)>;
-using i64 = int64_t;
+using i64 = int64_t;		// always 64-bit
 using f64 = Number::float_t;
 
+template<size_t T>
+union BitsCvtImpl;
+
+template<>
+union BitsCvtImpl<4>{
+	NumberTraits<4>::int_t _int;
+	NumberTraits<4>::float_t _float;
+
+	struct{
+		unsigned int sign: 1;
+		unsigned int exp: 8;
+		uint64_t mantissa: 23;
+	} _float_bits;
+
+	static constexpr int C0 = 127;	// 2^7 - 1
+	static constexpr int C1 = -62;	// 2 - 2^6
+	static constexpr int C2 = 63;	// 2^6 - 1
+
+	BitsCvtImpl(NumberTraits<4>::float_t val): _float(val) {}
+	BitsCvtImpl(NumberTraits<4>::int_t val): _int(val) {}
+};
+
+template<>
+union BitsCvtImpl<8>{
+	NumberTraits<8>::int_t _int;
+	NumberTraits<8>::float_t _float;
+
+	struct{
+		unsigned int sign: 1;
+		unsigned int exp: 11;
+		uint64_t mantissa: 52;
+	} _float_bits;
+
+	static constexpr int C0 = 1023;	// 2^10 - 1
+	static constexpr int C1 = -510;	// 2 - 2^9
+	static constexpr int C2 = 511;	// 2^9 - 1
+
+	BitsCvtImpl(NumberTraits<8>::float_t val): _float(val) {}
+	BitsCvtImpl(NumberTraits<8>::int_t val): _int(val) {}
+};
+
+using BitsCvt = BitsCvtImpl<sizeof(void*)>;
+
 static_assert(sizeof(i64) == 8);
-static_assert(sizeof(f64) == sizeof(void*));
+static_assert(sizeof(Number::float_t) == sizeof(void*));
+static_assert(sizeof(Number::int_t) == sizeof(void*));
+static_assert(sizeof(BitsCvt) == sizeof(void*));
 static_assert(std::numeric_limits<f64>::is_iec559);
 
 struct Dummy { };
@@ -133,10 +170,33 @@ struct Type {
 struct PyObject;
 #define PK_BITS(p) (reinterpret_cast<Number::int_t>(p))
 
-// special singals, is_tagged() for them is true
-inline PyObject* const PY_NULL = (PyObject*)0b000011;		// tagged null
-inline PyObject* const PY_OP_CALL = (PyObject*)0b100011;
-inline PyObject* const PY_OP_YIELD = (PyObject*)0b110011;
+inline PyObject* tag_float(f64 val){
+	BitsCvt decomposed(val);
+	unsigned int exp_7b = decomposed._float_bits.exp;
+	if(exp_7b - BitsCvt::C0 < BitsCvt::C1){
+		exp_7b = 0;
+		decomposed._float_bits.mantissa = 0;
+	}else if(exp_7b - BitsCvt::C0 > BitsCvt::C2){
+		exp_7b = BitsCvt::C0;
+		if(!std::isnan(val)) decomposed._float_bits.mantissa = 0;
+	}
+	decomposed._float_bits.exp = exp_7b - BitsCvt::C0 + BitsCvt::C2;
+	decomposed._int = (decomposed._int << 1) | 0b01;
+	return reinterpret_cast<PyObject*>(decomposed._int);
+}
+
+inline f64 untag_float(PyObject* val){
+	BitsCvt decomposed(reinterpret_cast<Number::int_t>(val));
+	decomposed._int >>= 1;
+	unsigned int exp_7b = decomposed._float_bits.exp;
+	if(exp_7b == 0) return 0.0f;
+	if(exp_7b == BitsCvt::C0){
+		decomposed._float_bits.exp = -1;
+		return decomposed._float;
+	}
+	decomposed._float_bits.exp = exp_7b - BitsCvt::C2 + BitsCvt::C0;
+	return decomposed._float;
+}
 
 // is_pod<> for c++17 and c++20
 template<typename T>

+ 13 - 12
include/pocketpy/obj.h

@@ -123,20 +123,29 @@ struct PyObject{
     }
 };
 
+struct PySignalObject: PyObject {
+    PySignalObject() : PyObject(0) {
+        gc.enabled = false;
+    }
+    void _obj_gc_mark() override {}
+};
+
+inline PyObject* const PY_NULL = new PySignalObject();
+inline PyObject* const PY_OP_CALL = new PySignalObject();
+inline PyObject* const PY_OP_YIELD = new PySignalObject();
+
 const int kTpIntIndex = 2;
 const int kTpFloatIndex = 3;
 
 inline bool is_tagged(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) != 0b00; }
-inline bool is_small_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b01; }
+inline bool is_small_int(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
 inline bool is_heap_int(PyObject* p) noexcept { return !is_tagged(p) && p->type.index == kTpIntIndex; }
-inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b10; }
-inline bool is_special(PyObject* p) noexcept { return (PK_BITS(p) & 0b11) == 0b11; }
+inline bool is_float(PyObject* p) noexcept { return (PK_BITS(p) & 1) == 1; }    // 01 or 11
 inline bool is_int(PyObject* p) noexcept { return is_small_int(p) || is_heap_int(p); }
 
 inline bool is_type(PyObject* obj, Type type) {
 #if PK_DEBUG_EXTRA_CHECK
     if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr");
-    if(is_special(obj)) throw std::runtime_error("is_type() called with special object");
 #endif
     switch(type.index){
         case kTpIntIndex: return is_int(obj);
@@ -148,7 +157,6 @@ inline bool is_type(PyObject* obj, Type type) {
 inline bool is_non_tagged_type(PyObject* obj, Type type) {
 #if PK_DEBUG_EXTRA_CHECK
     if(obj == nullptr) throw std::runtime_error("is_non_tagged_type() called with nullptr");
-    if(is_special(obj)) throw std::runtime_error("is_non_tagged_type() called with special object");
 #endif
     return !is_tagged(obj) && obj->type == type;
 }
@@ -200,13 +208,6 @@ Str obj_type_name(VM* vm, Type type);
 #define OBJ_NAME(obj) PK_OBJ_GET(Str, vm->getattr(obj, __name__))
 #endif
 
-union BitsCvt {
-    Number::int_t _int;
-    f64 _float;
-    BitsCvt(Number::int_t val) : _int(val) {}
-    BitsCvt(f64 val) : _float(val) {}
-};
-
 template <typename, typename=void> struct is_py_class : std::false_type {};
 template <typename T> struct is_py_class<T, std::void_t<decltype(T::_type)>> : std::true_type {};
 

+ 4 - 13
include/pocketpy/vm.h

@@ -505,7 +505,7 @@ PY_CAST_INT(unsigned long)
 PY_CAST_INT(unsigned long long)
 
 template<> inline float py_cast<float>(VM* vm, PyObject* obj){
-    if(is_float(obj)) return BitsCvt(PK_BITS(obj) & Number::c1)._float;
+    if(is_float(obj)) return untag_float(obj);
     i64 bits;
     if(try_cast_int(obj, &bits)) return (float)bits;
     vm->TypeError("expected 'int' or 'float', got " + OBJ_NAME(vm->_t(obj)).escape());
@@ -515,7 +515,7 @@ template<> inline float _py_cast<float>(VM* vm, PyObject* obj){
     return py_cast<float>(vm, obj);
 }
 template<> inline double py_cast<double>(VM* vm, PyObject* obj){
-    if(is_float(obj)) return BitsCvt(PK_BITS(obj) & Number::c1)._float;
+    if(is_float(obj)) return untag_float(obj);
     i64 bits;
     if(try_cast_int(obj, &bits)) return (float)bits;
     vm->TypeError("expected 'int' or 'float', got " + OBJ_NAME(vm->_t(obj)).escape());
@@ -532,7 +532,7 @@ const i64 kMinSmallInt = -(1ll << 28);
     inline PyObject* py_var(VM* vm, T _val){                \
         i64 val = static_cast<i64>(_val);                   \
         if(val >= kMinSmallInt && val <= kMaxSmallInt){     \
-            val = (val << 2) | 0b01;                        \
+            val = (val << 2) | 0b10;                        \
             return reinterpret_cast<PyObject*>(val);        \
         }else{                                              \
             return vm->heap.gcnew<i64>(vm->tp_int, val);    \
@@ -554,16 +554,7 @@ PY_VAR_INT(unsigned long long)
 #define PY_VAR_FLOAT(T)                             \
     inline PyObject* py_var(VM* vm, T _val){        \
         PK_UNUSED(vm);                              \
-        BitsCvt val(static_cast<f64>(_val));        \
-        i64 bits = val._int & Number::c1;           \
-        i64 tail = val._int & Number::c2;           \
-        if(tail == 0b10){                           \
-            if(bits&0b100) bits += 0b100;           \
-        }else if(tail == 0b11){                     \
-            bits += 0b100;                          \
-        }                                           \
-        bits |= 0b10;                               \
-        return reinterpret_cast<PyObject*>(bits);   \
+        return tag_float(static_cast<f64>(_val));   \
     }
 
 PY_VAR_FLOAT(float)