Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: define ISize and basic operations on it #5961

Merged
merged 1 commit into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions src/Init/Data/SInt/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ structure Int64 where
-/
toUInt64 : UInt64

/--
A `ISize` is a signed integer with the size of a word for the platform's architecture.
For example, if running on a 32-bit machine, ISize is equivalent to `Int32`.
Or on a 64-bit machine, `Int64`.
-/
structure ISize where
/--
Obtain the `USize` that is 2's complement equivalent to the `ISize`.
-/
toUSize : USize

/-- The size of type `Int8`, that is, `2^8 = 256`. -/
abbrev Int8.size : Nat := 256

Expand Down Expand Up @@ -463,3 +475,114 @@ instance (a b : Int64) : Decidable (a < b) := Int64.decLt a b
instance (a b : Int64) : Decidable (a ≤ b) := Int64.decLe a b
instance : Max Int64 := maxOfLe
instance : Min Int64 := minOfLe

/-- The size of type `ISize`, that is, `2^System.Platform.numBits`. -/
abbrev ISize.size : Nat := 2^System.Platform.numBits

/--
Obtain the `BitVec` that contains the 2's complement representation of the `ISize`.
-/
@[inline] def ISize.toBitVec (x : ISize) : BitVec System.Platform.numBits := x.toUSize.toBitVec

@[extern "lean_isize_of_int"]
def ISize.ofInt (i : @& Int) : ISize := ⟨⟨BitVec.ofInt System.Platform.numBits i⟩⟩
@[extern "lean_isize_of_nat"]
def ISize.ofNat (n : @& Nat) : ISize := ⟨⟨BitVec.ofNat System.Platform.numBits n⟩⟩
abbrev Int.toISize := ISize.ofInt
abbrev Nat.toISize := ISize.ofNat
@[extern "lean_isize_to_int"]
def ISize.toInt (i : ISize) : Int := i.toBitVec.toInt
/--
This function has the same behavior as `Int.toNat` for negative numbers.
If you want to obtain the 2's complement representation use `toBitVec`.
-/
@[inline] def ISize.toNat (i : ISize) : Nat := i.toInt.toNat
@[extern "lean_isize_to_int32"]
def ISize.toInt32 (a : ISize) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
/--
Upcast `ISize` to `Int64`. This function is losless as `ISize` is either `Int32` or `Int64`.
-/
@[extern "lean_isize_to_int64"]
def ISize.toInt64 (a : ISize) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
/--
Upcast `Int32` to `ISize`. This function is losless as `ISize` is either `Int32` or `Int64`.
-/
@[extern "lean_int32_to_isize"]
def Int32.toISize (a : Int32) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
@[extern "lean_int64_to_isize"]
def Int64.toISize (a : Int64) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
@[extern "lean_isize_neg"]
def ISize.neg (i : ISize) : ISize := ⟨⟨-i.toBitVec⟩⟩

instance : ToString ISize where
toString i := toString i.toInt

instance : OfNat ISize n := ⟨ISize.ofNat n⟩
instance : Neg ISize where
neg := ISize.neg

@[extern "lean_isize_add"]
def ISize.add (a b : ISize) : ISize := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
@[extern "lean_isize_sub"]
def ISize.sub (a b : ISize) : ISize := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
@[extern "lean_isize_mul"]
def ISize.mul (a b : ISize) : ISize := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
@[extern "lean_isize_div"]
def ISize.div (a b : ISize) : ISize := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
@[extern "lean_isize_mod"]
def ISize.mod (a b : ISize) : ISize := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
@[extern "lean_isize_land"]
def ISize.land (a b : ISize) : ISize := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
@[extern "lean_isize_lor"]
def ISize.lor (a b : ISize) : ISize := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
@[extern "lean_isize_xor"]
def ISize.xor (a b : ISize) : ISize := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
@[extern "lean_isize_shift_left"]
def ISize.shiftLeft (a b : ISize) : ISize := ⟨⟨a.toBitVec <<< (b.toBitVec.smod System.Platform.numBits)⟩⟩
@[extern "lean_isize_shift_right"]
def ISize.shiftRight (a b : ISize) : ISize := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod System.Platform.numBits)⟩⟩
@[extern "lean_isize_complement"]
def ISize.complement (a : ISize) : ISize := ⟨⟨~~~a.toBitVec⟩⟩

@[extern "lean_isize_dec_eq"]
def ISize.decEq (a b : ISize) : Decidable (a = b) :=
match a, b with
| ⟨n⟩, ⟨m⟩ =>
if h : n = m then
isTrue <| h ▸ rfl
else
isFalse (fun h' => ISize.noConfusion h' (fun h' => absurd h' h))

def ISize.lt (a b : ISize) : Prop := a.toBitVec.slt b.toBitVec
def ISize.le (a b : ISize) : Prop := a.toBitVec.sle b.toBitVec

instance : Inhabited ISize where
default := 0

instance : Add ISize := ⟨ISize.add⟩
instance : Sub ISize := ⟨ISize.sub⟩
instance : Mul ISize := ⟨ISize.mul⟩
instance : Mod ISize := ⟨ISize.mod⟩
instance : Div ISize := ⟨ISize.div⟩
instance : LT ISize := ⟨ISize.lt⟩
instance : LE ISize := ⟨ISize.le⟩
instance : Complement ISize := ⟨ISize.complement⟩
instance : AndOp ISize := ⟨ISize.land⟩
instance : OrOp ISize := ⟨ISize.lor⟩
instance : Xor ISize := ⟨ISize.xor⟩
instance : ShiftLeft ISize := ⟨ISize.shiftLeft⟩
instance : ShiftRight ISize := ⟨ISize.shiftRight⟩
instance : DecidableEq ISize := ISize.decEq

@[extern "lean_isize_dec_lt"]
def ISize.decLt (a b : ISize) : Decidable (a < b) :=
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))

@[extern "lean_isize_dec_le"]
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))

instance (a b : ISize) : Decidable (a < b) := ISize.decLt a b
instance (a b : ISize) : Decidable (a ≤ b) := ISize.decLe a b
instance : Max ISize := maxOfLe
instance : Min ISize := minOfLe
142 changes: 142 additions & 0 deletions src/include/lean/lean.h
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,7 @@ static inline uint8_t lean_int32_dec_le(uint32_t a1, uint32_t a2) {
static inline uint8_t lean_int32_to_int8(uint32_t a) { return (uint8_t)(int8_t)(int32_t)a; }
static inline uint16_t lean_int32_to_int16(uint32_t a) { return (uint16_t)(int16_t)(int32_t)a; }
static inline uint64_t lean_int32_to_int64(uint32_t a) { return (uint64_t)(int64_t)(int32_t)a; }
static inline size_t lean_int32_to_isize(uint32_t a) { return (size_t)(ptrdiff_t)(int32_t)a; }

/* Int64 */
LEAN_EXPORT int64_t lean_int64_of_big_int(b_lean_obj_arg a);
Expand Down Expand Up @@ -2368,6 +2369,147 @@ static inline uint8_t lean_int64_dec_le(uint64_t a1, uint64_t a2) {
static inline uint8_t lean_int64_to_int8(uint64_t a) { return (uint8_t)(int8_t)(int64_t)a; }
static inline uint16_t lean_int64_to_int16(uint64_t a) { return (uint16_t)(int16_t)(int64_t)a; }
static inline uint32_t lean_int64_to_int32(uint64_t a) { return (uint32_t)(int32_t)(int64_t)a; }
static inline size_t lean_int64_to_isize(uint64_t a) { return (size_t)(ptrdiff_t)(int64_t)a; }

/* ISize */
LEAN_EXPORT ptrdiff_t lean_isize_of_big_int(b_lean_obj_arg a);
static inline size_t lean_isize_of_int(b_lean_obj_arg a) {
ptrdiff_t res;

if (lean_is_scalar(a)) {
res = (ptrdiff_t)lean_scalar_to_int64(a);
} else {
res = lean_isize_of_big_int(a);
}

return (size_t)res;
}

static inline size_t lean_isize_of_nat(b_lean_obj_arg a) {
ptrdiff_t res;

if (lean_is_scalar(a)) {
res = (ptrdiff_t)lean_unbox(a);
} else {
res = lean_isize_of_big_int(a);
}

return (size_t)res;
}

static inline lean_obj_res lean_isize_to_int(size_t a) {
ptrdiff_t arg = (ptrdiff_t)a;
return lean_int64_to_int((int64_t)arg);
}

static inline size_t lean_isize_neg(size_t a) {
ptrdiff_t arg = (ptrdiff_t)a;

return (size_t)(-arg);
}

static inline size_t lean_isize_add(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs + rhs);
}

static inline size_t lean_isize_sub(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs - rhs);
}

static inline size_t lean_isize_mul(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs * rhs);
}

static inline size_t lean_isize_div(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(rhs == 0 ? 0 : lhs / rhs);
}

static inline size_t lean_isize_mod(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(rhs == 0 ? lhs : lhs % rhs);
}

static inline size_t lean_isize_land(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs & rhs);
}

static inline size_t lean_isize_lor(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs | rhs);
}

static inline size_t lean_isize_xor(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return (size_t)(lhs ^ rhs);
}

static inline size_t lean_isize_shift_right(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t size = sizeof(ptrdiff_t) * 8;
ptrdiff_t rhs = (((ptrdiff_t)a2 % size) + size) % size; // this is smod

return (size_t)(lhs >> rhs);
}

static inline size_t lean_isize_shift_left(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t size = sizeof(ptrdiff_t) * 8;
ptrdiff_t rhs = (((ptrdiff_t)a2 % size) + size) % size; // this is smod

return (size_t)(lhs << rhs);
}

static inline size_t lean_isize_complement(size_t a) {
ptrdiff_t arg = (ptrdiff_t)a;

return (size_t)(~arg);
}

static inline uint8_t lean_isize_dec_eq(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return lhs == rhs;
}

static inline uint8_t lean_isize_dec_lt(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return lhs < rhs;
}

static inline uint8_t lean_isize_dec_le(size_t a1, size_t a2) {
ptrdiff_t lhs = (ptrdiff_t)a1;
ptrdiff_t rhs = (ptrdiff_t)a2;

return lhs <= rhs;
}

/* ISize -> other */
static inline uint32_t lean_isize_to_int32(size_t a) { return (uint32_t)(int32_t)(ptrdiff_t)a; }
static inline uint64_t lean_isize_to_int64(size_t a) { return (uint64_t)(int64_t)(ptrdiff_t)a; }

/* Float */

Expand Down
4 changes: 4 additions & 0 deletions src/runtime/int.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,9 @@ static_assert(sizeof(int64) == 8, "unexpected int64 size"); // NOLINT
static_assert(sizeof(uint64) == 8, "unexpected uint64 size"); // NOLINT
//
typedef size_t usize;
typedef ptrdiff_t isize;
static_assert(sizeof(usize) == sizeof(isize), "unexpected size difference usize/isize"); // NOLINT
static_assert(sizeof(usize) == 4 || sizeof(usize) == 8, "usize is neither 32 nor 64 bit"); // NOLINT
//

}
9 changes: 9 additions & 0 deletions src/runtime/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,15 @@ extern "C" LEAN_EXPORT int64 lean_int64_of_big_int(b_obj_arg a) {
return mpz_value(a).smod64();
}

extern "C" LEAN_EXPORT isize lean_isize_of_big_int(b_obj_arg a) {
if (sizeof(ptrdiff_t) == 8) {
return static_cast<isize>(mpz_value(a).smod64());
} else {
// We assert in int.h that the size of ptrdiff_t is 8 or 4.
return static_cast<isize>(mpz_value(a).smod32());
}
}

// =======================================
// Float

Expand Down
Loading
Loading