Browse Source

Support Int64 natively on eval (#12411)

* support Int64 natively on eval

* add eval-specific FPHelper extern
Simon Krajewski 3 weeks ago
parent
commit
82ff5b4c10

+ 1 - 0
src/macro/eval/evalContext.ml

@@ -534,6 +534,7 @@ let is v path =
 		v <> vnull
 		v <> vnull
 	else match v with
 	else match v with
 	| VInt32 _ -> path = key_Int || path = key_Float
 	| VInt32 _ -> path = key_Int || path = key_Float
+	| VInt64 _ -> path = key_eval_integers_Int64
 	| VFloat f -> path = key_Float || (path = key_Int && f = (float_of_int (int_of_float f)) && f <= 2147483647. && f >= -2147483648.)
 	| VFloat f -> path = key_Float || (path = key_Int && f = (float_of_int (int_of_float f)) && f <= 2147483647. && f >= -2147483648.)
 	| VTrue | VFalse -> path = key_Bool
 	| VTrue | VFalse -> path = key_Bool
 	| VPrototype {pkind = PClass _} -> path = key_Class
 	| VPrototype {pkind = PClass _} -> path = key_Class

+ 3 - 1
src/macro/eval/evalEmitter.ml

@@ -531,7 +531,8 @@ let emit_vector_write exec1 p1 exec2 p2 exec3 p env =
 (* Read + write *)
 (* Read + write *)
 
 
 let do_incr v p = match v with
 let do_incr v p = match v with
-	| VInt32 i32 -> vint32 (Int32.add i32 Int32.one)
+	| VInt32 i32 -> vint32 (Int32.succ i32)
+	| VInt64 i64 -> vint64 (Int64.succ i64)
 	| VFloat f -> vfloat (f +. 1.)
 	| VFloat f -> vfloat (f +. 1.)
 	| v -> unexpected_value_p v "number" p
 	| v -> unexpected_value_p v "number" p
 
 
@@ -731,6 +732,7 @@ let emit_bool_or exec1 exec2 env =
 let emit_neg exec p env = match exec env with
 let emit_neg exec p env = match exec env with
 	| VFloat f -> vfloat (-.f)
 	| VFloat f -> vfloat (-.f)
 	| VInt32 i -> vint32 (Int32.neg i)
 	| VInt32 i -> vint32 (Int32.neg i)
+	| VInt64 i -> vint64 (Int64.neg i)
 	| _ -> throw_string "Invalid operation" p
 	| _ -> throw_string "Invalid operation" p
 
 
 (* Function *)
 (* Function *)

+ 5 - 3
src/macro/eval/evalHash.ml

@@ -213,6 +213,8 @@ let key_address = hash "address"
 let key_netmask = hash "netmask"
 let key_netmask = hash "netmask"
 let key_previous = hash "previous"
 let key_previous = hash "previous"
 let key_current = hash "current"
 let key_current = hash "current"
-let key_haxe_atomic_AtomicBool = hash "haxe.atomic.AtomicBool" 
-let key_haxe_atomic_AtomicInt = hash "haxe.atomic.AtomicInt" 
-let key_haxe_atomic_AtomicObject = hash "haxe.atomic.AtomicObject" 
+let key_haxe_atomic_AtomicBool = hash "haxe.atomic.AtomicBool"
+let key_haxe_atomic_AtomicInt = hash "haxe.atomic.AtomicInt"
+let key_haxe_atomic_AtomicObject = hash "haxe.atomic.AtomicObject"
+
+let key_eval_integers_Int64 = hash "eval.integers._Int64.Int64_Impl_" (* TODO: wonky... *)

+ 21 - 37
src/macro/eval/evalIntegers.ml

@@ -12,36 +12,6 @@ open EvalMisc
 open Unsigned
 open Unsigned
 open Signed
 open Signed
 
 
-let encode_haxe_i64 low high =
-	let vi = create_instance key_haxe__Int64____Int64 in
-	set_instance_field vi key_high (vint32 high);
-	set_instance_field vi key_low (vint32 low);
-	vinstance vi
-
-let encode_haxe_i64_int64 value =
-	let high = Stdlib.Int64.to_int32 (Stdlib.Int64.shift_right_logical value 32) in
-	let low = Stdlib.Int64.to_int32 value in
-	let vi = create_instance key_haxe__Int64____Int64 in
-	set_instance_field vi key_high (vint32 high);
-	set_instance_field vi key_low (vint32 low);
-	vinstance vi
-
-let encode_haxe_i64_direct i64 =
-	let low = GInt64.to_int32 i64 in
-	let high = GInt64.to_int32 (GInt64.shift_right_logical i64 32) in
-	encode_haxe_i64 low high
-
-let decode_haxe_i64 v =
-	match v with
-	| VInstance vi when is v key_haxe__Int64____Int64 ->
-		let high = decode_i32 (vi.ifields.(get_instance_field_index_raise vi.iproto key_high))
-		and low = decode_i32 (vi.ifields.(get_instance_field_index_raise vi.iproto key_low)) in
-		let high64 = GInt64.shift_left (Int32.to_int64 high) 32
-		and low64 = GInt64.logand (Int32.to_int64 low) 0xffffffffL in
-		GInt64.logor high64 low64
-	| _ ->
-		unexpected_value v "haxe.Int64"
-
 let decode_u64 = function
 let decode_u64 = function
 	| VUInt64 u -> u
 	| VUInt64 u -> u
 	| v -> unexpected_value v "eval.integers.UInt64"
 	| v -> unexpected_value v "eval.integers.UInt64"
@@ -163,6 +133,13 @@ let uint64_fields = [
 	);
 	);
 ]
 ]
 
 
+let make_int64 high low =
+	let high = GInt64.of_int32 high in
+	let high = Int64.shift_left high 32 in
+	let low = GInt64.of_int32 low in
+	let low = Int64.logand low (Int64.of_string "0xFFFFFFFF") in
+	Int64.logor high low
+
 let int64_fields = [
 let int64_fields = [
 	"MAX", VInt64 Int64.max_int;
 	"MAX", VInt64 Int64.max_int;
 	"MIN", VInt64 Int64.min_int;
 	"MIN", VInt64 Int64.min_int;
@@ -177,9 +154,6 @@ let int64_fields = [
 		try VInt64 (Int64.of_string s)
 		try VInt64 (Int64.of_string s)
 		with Failure _ -> throw_string "The string is not a valid Int64 representation" null_pos
 		with Failure _ -> throw_string "The string is not a valid Int64 representation" null_pos
 	);
 	);
-	"ofHxInt64", vfun1 (fun v ->
-		VInt64 (decode_haxe_i64 v)
-	);
 	"max", vfun2 (fun v1 v2 ->
 	"max", vfun2 (fun v1 v2 ->
 		let a = decode_i64 v1
 		let a = decode_i64 v1
 		and b = decode_i64 v2 in
 		and b = decode_i64 v2 in
@@ -195,18 +169,23 @@ let int64_fields = [
 		and b = decode_i64 v2 in
 		and b = decode_i64 v2 in
 		vint (Int64.compare a b)
 		vint (Int64.compare a b)
 	);
 	);
+	"make", vfun2 (fun vhigh vlow ->
+		let high = decode_i32 vhigh in
+		let low = decode_i32 vlow in
+		let i = make_int64 high low in
+		VInt64 i
+	);
 	"toInt", vfun1 (fun v ->
 	"toInt", vfun1 (fun v ->
 		let i = decode_i64 v in
 		let i = decode_i64 v in
 		vint32 (GInt64.to_int32 i)
 		vint32 (GInt64.to_int32 i)
 	);
 	);
+	"toInt32", vfun1 (fun v ->
+		vint32 (Int32.of_int64 (decode_i64 v))
+	);
 	"toUInt64", vfun1 (fun v ->
 	"toUInt64", vfun1 (fun v ->
 		let i = decode_i64 v in
 		let i = decode_i64 v in
 		VUInt64 (UInt64.of_int64 i)
 		VUInt64 (UInt64.of_int64 i)
 	);
 	);
-	"toHxInt64", vfun1 (fun v ->
-		let i = decode_i64 v in
-		encode_haxe_i64_direct i
-	);
 	"toString", vfun1 (fun v ->
 	"toString", vfun1 (fun v ->
 		let i = decode_i64 v in
 		let i = decode_i64 v in
 		EvalString.vstring (EvalString.create_ascii (Int64.to_string i))
 		EvalString.vstring (EvalString.create_ascii (Int64.to_string i))
@@ -271,6 +250,11 @@ let int64_fields = [
 		and i = decode_int v2 in
 		and i = decode_int v2 in
 		VInt64 (Int64.shift_right i64 i)
 		VInt64 (Int64.shift_right i64 i)
 	);
 	);
+	"shift_right_logical", vfun2 (fun v1 v2 ->
+		let i64 = decode_i64 v1
+		and i = decode_int v2 in
+		VInt64 (Int64.shift_right_logical i64 i)
+	);
 	"lognot", vfun1 (fun v ->
 	"lognot", vfun1 (fun v ->
 		let i = decode_i64 v in
 		let i = decode_i64 v in
 		VInt64 (Int64.lognot i)
 		VInt64 (Int64.lognot i)

+ 14 - 0
src/macro/eval/evalMisc.ml

@@ -123,10 +123,13 @@ let fcmp (a:float) b = if a = b then CEq else if a < b then CInf else if a > b t
 
 
 let icmp (a:int32) b = let l = Int32.compare a b in if l = 0 then CEq else if l < 0 then CInf else CSup
 let icmp (a:int32) b = let l = Int32.compare a b in if l = 0 then CEq else if l < 0 then CInf else CSup
 
 
+let i64cmp (a:int64) b = let l = Int64.compare a b in if l = 0 then CEq else if l < 0 then CInf else CSup
+
 let rec compare a b =
 let rec compare a b =
 	match a, b with
 	match a, b with
 	| VNull,VNull -> CEq
 	| VNull,VNull -> CEq
 	| VInt32 a,VInt32 b -> icmp a b
 	| VInt32 a,VInt32 b -> icmp a b
+	| VInt64 a,VInt64 b -> i64cmp a b
 	| VFloat a,VFloat b -> fcmp a b
 	| VFloat a,VFloat b -> fcmp a b
 	| VFloat a,VInt32 b -> fcmp a (Int32.to_float b)
 	| VFloat a,VInt32 b -> fcmp a (Int32.to_float b)
 	| VInt32 a,VFloat b -> fcmp (Int32.to_float a) b
 	| VInt32 a,VFloat b -> fcmp (Int32.to_float a) b
@@ -175,6 +178,7 @@ let rec arrays_equal cmp a1 a2 =
 and equals_structurally a b =
 and equals_structurally a b =
 	match a,b with
 	match a,b with
 	| VInt32 a,VInt32 b -> Int32.compare a b = 0
 	| VInt32 a,VInt32 b -> Int32.compare a b = 0
+	| VInt64 a,VInt64 b -> Int64.compare a b = 0
 	| VFloat a,VFloat b -> a = b
 	| VFloat a,VFloat b -> a = b
 	| VFloat a,VInt32 b -> a = (Int32.to_float b)
 	| VFloat a,VInt32 b -> a = (Int32.to_float b)
 	| VInt32 a,VFloat b -> (Int32.to_float a) = b
 	| VInt32 a,VFloat b -> (Int32.to_float a) = b
@@ -194,6 +198,11 @@ let is_true v = match v with
 
 
 let op_add p v1 v2 = match v1,v2 with
 let op_add p v1 v2 = match v1,v2 with
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.add i1 i2)
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.add i1 i2)
+	| VInt64 i1,VInt64 i2 -> vint64 (Int64.add i1 i2)
+	(* These two cases should technically not exist, but the analyzer emits code like this because
+	   our TConst only knows Int32 at the moment. *)
+	| VInt64 i1,VInt32 i2 -> vint64 (Int64.add i1 (Int64.of_int32 i2))
+	| VInt32 i1,VInt64 i2 -> vint64 (Int64.add (Int64.of_int32 i1) i2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 +. f2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 +. f2)
 	| VInt32 i,VFloat f | VFloat f,VInt32 i -> vfloat ((Int32.to_float i) +. f)
 	| VInt32 i,VFloat f | VFloat f,VInt32 i -> vfloat ((Int32.to_float i) +. f)
 	| VNativeString s1,VNativeString s2 -> vnative_string (s1 ^ s2)
 	| VNativeString s1,VNativeString s2 -> vnative_string (s1 ^ s2)
@@ -204,6 +213,7 @@ let op_add p v1 v2 = match v1,v2 with
 
 
 let op_mult p v1 v2 = match v1,v2 with
 let op_mult p v1 v2 = match v1,v2 with
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.mul i1 i2)
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.mul i1 i2)
+	| VInt64 i1,VInt64 i2 -> vint64 (Int64.mul i1 i2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 *. f2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 *. f2)
 	| VInt32 i,VFloat f | VFloat f,VInt32 i -> vfloat ((Int32.to_float i) *. f)
 	| VInt32 i,VFloat f | VFloat f,VInt32 i -> vfloat ((Int32.to_float i) *. f)
 	| _ -> invalid_binop OpMult v1 v2 p
 	| _ -> invalid_binop OpMult v1 v2 p
@@ -217,6 +227,10 @@ let op_div p v1 v2 = match v1,v2 with
 
 
 let op_sub p v1 v2 = match v1,v2 with
 let op_sub p v1 v2 = match v1,v2 with
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.sub i1 i2)
 	| VInt32 i1,VInt32 i2 -> vint32 (Int32.sub i1 i2)
+	| VInt64 i1,VInt64 i2 -> vint64 (Int64.sub i1 i2)
+	(* See op_add remark. *)
+	| VInt64 i1,VInt32 i2 -> vint64 (Int64.sub i1 (Int64.of_int32 i2))
+	| VInt32 i1,VInt64 i2 -> vint64 (Int64.sub (Int64.of_int32 i1) i2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 -. f2)
 	| VFloat f1,VFloat f2 -> vfloat (f1 -. f2)
 	| VInt32 i1,VFloat f2 -> vfloat ((Int32.to_float i1) -. f2)
 	| VInt32 i1,VFloat f2 -> vfloat ((Int32.to_float i1) -. f2)
 	| VFloat f1,VInt32 i2 -> vfloat (f1 -. (Int32.to_float i2))
 	| VFloat f1,VInt32 i2 -> vfloat (f1 -. (Int32.to_float i2))

+ 11 - 11
src/macro/eval/evalStdLib.ml

@@ -333,7 +333,7 @@ module StdBytes = struct
 		try
 		try
 			let low = read_i32 this pos in
 			let low = read_i32 this pos in
 			let high = read_i32 this (pos + 4) in
 			let high = read_i32 this (pos + 4) in
-			EvalIntegers.encode_haxe_i64 low high;
+			vint64 (EvalIntegers.make_int64 high low)
 		with _ ->
 		with _ ->
 			outside_bounds()
 			outside_bounds()
 	)
 	)
@@ -500,9 +500,9 @@ module StdBytesBuffer = struct
 
 
 	let addInt64 = vifun1 (fun vthis v ->
 	let addInt64 = vifun1 (fun vthis v ->
 		let this = this vthis in
 		let this = this vthis in
-		let v = decode_instance v in
-		let high = decode_i32 (instance_field v key_high) in
-		let low = decode_i32 (instance_field v key_low) in
+		let i64 = EvalIntegers.decode_i64 v in
+		let high = Int64.to_int32 (Int64.shift_right i64 32) in
+		let low = Int64.to_int32 i64 in
 		add_i32 this low;
 		add_i32 this low;
 		add_i32 this high;
 		add_i32 this high;
 		vnull;
 		vnull;
@@ -1164,7 +1164,7 @@ module StdFPHelper = struct
 	let doubleToI64 = vfun1 (fun v ->
 	let doubleToI64 = vfun1 (fun v ->
 		let f = num v in
 		let f = num v in
 		let i64 = Int64.bits_of_float f in
 		let i64 = Int64.bits_of_float f in
-		EvalIntegers.encode_haxe_i64_direct i64
+		vint64 i64
 	)
 	)
 
 
 	let floatToI32 = vfun1 (fun f ->
 	let floatToI32 = vfun1 (fun f ->
@@ -1581,11 +1581,11 @@ module StdInt64Map = struct
 	)
 	)
 
 
 	let exists = vifun1 (fun vthis vkey ->
 	let exists = vifun1 (fun vthis vkey ->
-		vbool (RuntimeInt64Hashtbl.mem (this vthis) (EvalIntegers.decode_haxe_i64 vkey))
+		vbool (RuntimeInt64Hashtbl.mem (this vthis) (EvalIntegers.decode_i64 vkey))
 	)
 	)
 
 
 	let get = vifun1 (fun vthis vkey ->
 	let get = vifun1 (fun vthis vkey ->
-		try RuntimeInt64Hashtbl.find (this vthis) (EvalIntegers.decode_haxe_i64 vkey)
+		try RuntimeInt64Hashtbl.find (this vthis) (EvalIntegers.decode_i64 vkey)
 		with Not_found -> vnull
 		with Not_found -> vnull
 	)
 	)
 
 
@@ -1595,7 +1595,7 @@ module StdInt64Map = struct
 	)
 	)
 
 
 	let keys = vifun0 (fun vthis ->
 	let keys = vifun0 (fun vthis ->
-		let keys = RuntimeInt64Hashtbl.fold (fun k _ acc -> EvalIntegers.encode_haxe_i64_int64 k :: acc) (this vthis) [] in
+		let keys = RuntimeInt64Hashtbl.fold (fun k _ acc -> vint64 k :: acc) (this vthis) [] in
 		encode_list_iterator keys
 		encode_list_iterator keys
 	)
 	)
 
 
@@ -1603,14 +1603,14 @@ module StdInt64Map = struct
 
 
 	let remove = vifun1 (fun vthis vkey ->
 	let remove = vifun1 (fun vthis vkey ->
 		let this = this vthis in
 		let this = this vthis in
-		let key = EvalIntegers.decode_haxe_i64 vkey in
+		let key = EvalIntegers.decode_i64 vkey in
 		let b = RuntimeInt64Hashtbl.mem this key in
 		let b = RuntimeInt64Hashtbl.mem this key in
 		RuntimeInt64Hashtbl.remove this key;
 		RuntimeInt64Hashtbl.remove this key;
 		vbool b
 		vbool b
 	)
 	)
 
 
 	let set = vifun2 (fun vthis vkey vvalue ->
 	let set = vifun2 (fun vthis vkey vvalue ->
-		RuntimeInt64Hashtbl.add (this vthis) (EvalIntegers.decode_haxe_i64 vkey) vvalue;
+		RuntimeInt64Hashtbl.add (this vthis) (EvalIntegers.decode_i64 vkey) vvalue;
 		vnull
 		vnull
 	)
 	)
 
 
@@ -2796,7 +2796,7 @@ module StdSys = struct
 
 
 	let time = vfun0 (fun () -> vfloat (catch_unix_error Unix.gettimeofday()))
 	let time = vfun0 (fun () -> vfloat (catch_unix_error Unix.gettimeofday()))
 
 
-	let timestamp_ms = vfun0 (fun () -> EvalIntegers.encode_haxe_i64_direct (* TODO: use vint64 once that works *) (Extc.timestamp_ms()))
+	let timestamp_ms = vfun0 (fun () -> vint64 (Extc.timestamp_ms()))
 end
 end
 
 
 module StdThread = struct
 module StdThread = struct

+ 220 - 0
std/eval/_std/haxe/Int64.hx

@@ -0,0 +1,220 @@
+package haxe;
+
+import eval.integers.Int64 as I64;
+
+private typedef __Int64 = I64;
+
+@:transitive
+@:coreApi
+abstract Int64(__Int64) from __Int64 to __Int64 {
+	public static inline function make(high:Int32, low:Int32):Int64
+		return I64.make(high, low);
+
+	private inline function new(x:__Int64)
+		this = x;
+
+	private var val(get, set):__Int64;
+
+	inline function get_val():__Int64
+		return this;
+
+	inline function set_val(x:__Int64):__Int64
+		return this = x;
+
+	public var high(get, never):Int32;
+
+	inline function get_high():Int32
+		return (this >> 32).toInt32();
+
+	public var low(get, never):Int32;
+
+	inline function get_low():Int32
+		return this.toInt32();
+
+	public inline function copy():Int64
+		return new Int64(this);
+
+	@:from public static inline function ofInt(x:Int):Int64
+		return I64.ofInt(x);
+
+	@:deprecated('haxe.Int64.is() is deprecated. Use haxe.Int64.isInt64() instead')
+	inline public static function is(val:Dynamic):Bool {
+		return isInt64(val);
+	}
+
+	inline public static function isInt64(val:Dynamic):Bool
+		return Std.isOfType(val, eval.integers.Int64);
+
+	public static inline function toInt(x:Int64):Int {
+		if (x.high != x.low >> 31)
+			throw "Overflow";
+		return x.val.toInt();
+	}
+
+	public static inline function getHigh(x:Int64):Int32
+		return x.high;
+
+	public static inline function getLow(x:Int64):Int32
+		return x.low;
+
+	public static inline function isNeg(x:Int64):Bool
+		return x.val < 0i64;
+
+	public static inline function isZero(x:Int64):Bool
+		return x.val == 0i64;
+
+	public static inline function compare(a:Int64, b:Int64):Int {
+		if (a.val < b.val)
+			return -1;
+		if (a.val > b.val)
+			return 1;
+		return 0;
+	}
+
+	public static inline function ucompare(a:Int64, b:Int64):Int {
+		if (a.val < 0i64)
+			return (b.val < 0i64) ? compare(a, b) : 1;
+		return (b.val < 0i64) ? -1 : compare(a, b);
+	}
+
+	public static inline function toStr(x:Int64):String
+		return '${x.val}';
+
+	public static inline function divMod(dividend:Int64, divisor:Int64):{quotient:Int64, modulus:Int64}
+		return {quotient: dividend / divisor, modulus: dividend % divisor};
+
+	public inline function toString():String
+		return '$this';
+
+	public static function parseString(sParam:String):Int64 {
+		return Int64Helper.parseString(sParam);
+	}
+
+	public static function fromFloat(f:Float):Int64 {
+		return Int64Helper.fromFloat(f);
+	}
+
+	@:op(-A) public static function neg(x:Int64):Int64
+		return -x.val;
+
+	@:op(++A) private inline function preIncrement():Int64
+		return ++this;
+
+	@:op(A++) private inline function postIncrement():Int64
+		return this++;
+
+	@:op(--A) private inline function preDecrement():Int64
+		return --this;
+
+	@:op(A--) private inline function postDecrement():Int64
+		return this
+
+	--;
+	@:op(A + B) public static inline function add(a:Int64, b:Int64):Int64
+		return a.val + b.val;
+
+	@:op(A + B) @:commutative private static inline function addInt(a:Int64, b:Int):Int64
+		return a.val + I64.ofInt(b);
+
+	@:op(A - B) public static inline function sub(a:Int64, b:Int64):Int64
+		return a.val - b.val;
+
+	@:op(A - B) private static inline function subInt(a:Int64, b:Int):Int64
+		return a.val - I64.ofInt(b);
+
+	@:op(A - B) private static inline function intSub(a:Int, b:Int64):Int64
+		return I64.ofInt(a) - b.val;
+
+	@:op(A * B) public static inline function mul(a:Int64, b:Int64):Int64
+		return a.val * b.val;
+
+	@:op(A * B) @:commutative private static inline function mulInt(a:Int64, b:Int):Int64
+		return a.val * I64.ofInt(b);
+
+	@:op(A / B) public static inline function div(a:Int64, b:Int64):Int64
+		return a.val / b.val;
+
+	@:op(A / B) private static inline function divInt(a:Int64, b:Int):Int64
+		return a.val / I64.ofInt(b);
+
+	@:op(A / B) private static inline function intDiv(a:Int, b:Int64):Int64
+		return I64.ofInt(a) / b.val;
+
+	@:op(A % B) public static inline function mod(a:Int64, b:Int64):Int64
+		return a.val % b.val;
+
+	@:op(A % B) private static inline function modInt(a:Int64, b:Int):Int64
+		return a.val % I64.ofInt(b);
+
+	@:op(A % B) private static inline function intMod(a:Int, b:Int64):Int64
+		return I64.ofInt(a) % b.val;
+
+	@:op(A == B) public static inline function eq(a:Int64, b:Int64):Bool
+		return a.val == b.val;
+
+	@:op(A == B) @:commutative private static inline function eqInt(a:Int64, b:Int):Bool
+		return a.val == I64.ofInt(b);
+
+	@:op(A != B) public static inline function neq(a:Int64, b:Int64):Bool
+		return a.val != b.val;
+
+	@:op(A != B) @:commutative private static inline function neqInt(a:Int64, b:Int):Bool
+		return a.val != I64.ofInt(b);
+
+	@:op(A < B) private static inline function lt(a:Int64, b:Int64):Bool
+		return a.val < b.val;
+
+	@:op(A < B) private static inline function ltInt(a:Int64, b:Int):Bool
+		return a.val < I64.ofInt(b);
+
+	@:op(A < B) private static inline function intLt(a:Int, b:Int64):Bool
+		return I64.ofInt(a) < b.val;
+
+	@:op(A <= B) private static inline function lte(a:Int64, b:Int64):Bool
+		return a.val <= b.val;
+
+	@:op(A <= B) private static inline function lteInt(a:Int64, b:Int):Bool
+		return a.val <= I64.ofInt(b);
+
+	@:op(A <= B) private static inline function intLte(a:Int, b:Int64):Bool
+		return I64.ofInt(a) <= b.val;
+
+	@:op(A > B) private static inline function gt(a:Int64, b:Int64):Bool
+		return a.val > b.val;
+
+	@:op(A > B) private static inline function gtInt(a:Int64, b:Int):Bool
+		return a.val > I64.ofInt(b);
+
+	@:op(A > B) private static inline function intGt(a:Int, b:Int64):Bool
+		return I64.ofInt(a) > b.val;
+
+	@:op(A >= B) private static inline function gte(a:Int64, b:Int64):Bool
+		return a.val >= b.val;
+
+	@:op(A >= B) private static inline function gteInt(a:Int64, b:Int):Bool
+		return a.val >= I64.ofInt(b);
+
+	@:op(A >= B) private static inline function intGte(a:Int, b:Int64):Bool
+		return I64.ofInt(a) >= b.val;
+
+	@:op(~A) private static inline function complement(x:Int64):Int64
+		return ~x.val;
+
+	@:op(A & B) public static inline function and(a:Int64, b:Int64):Int64
+		return a.val & b.val;
+
+	@:op(A | B) public static inline function or(a:Int64, b:Int64):Int64
+		return a.val | b.val;
+
+	@:op(A ^ B) public static inline function xor(a:Int64, b:Int64):Int64
+		return a.val ^ b.val;
+
+	@:op(A << B) public static inline function shl(a:Int64, b:Int):Int64
+		return a.val << b;
+
+	@:op(A >> B) public static inline function shr(a:Int64, b:Int):Int64
+		return a.val >> b;
+
+	@:op(A >>> B) public static inline function ushr(a:Int64, b:Int):Int64
+		return a.val >>> b;
+}

+ 11 - 0
std/eval/_std/haxe/io/FPHelper.hx

@@ -0,0 +1,11 @@
+package haxe.io;
+
+extern class FPHelper {
+	public static function i32ToFloat(i:Int):Float;
+
+	public static function floatToI32(f:Float):Int;
+
+	public static function i64ToDouble(low:Int, high:Int):Float;
+
+	public static function doubleToI64(v:Float):Int64;
+}

+ 17 - 2
std/eval/integers/Int64.hx

@@ -1,8 +1,11 @@
 package eval.integers;
 package eval.integers;
 
 
+import haxe.Int32;
+
 /**
 /**
 	Signed 64-bit integer type and operations.
 	Signed 64-bit integer type and operations.
 **/
 **/
+@:runtimeValue
 @:coreType abstract Int64 {
 @:coreType abstract Int64 {
 	/** The greatest representable Int64 value. */
 	/** The greatest representable Int64 value. */
 	extern static public final MAX:Int64;
 	extern static public final MAX:Int64;
@@ -47,6 +50,8 @@ package eval.integers;
 	**/
 	**/
 	static public function compare(a:Int64, b:Int64):Int;
 	static public function compare(a:Int64, b:Int64):Int;
 
 
+	static public function make(high:Int32, low:Int32):Int64;
+
 	/**
 	/**
 		Convert to an integer value.
 		Convert to an integer value.
 		The 64-bit signed integer is taken modulo 2{^32}, i.e. the top 32 bits
 		The 64-bit signed integer is taken modulo 2{^32}, i.e. the top 32 bits
@@ -59,6 +64,8 @@ package eval.integers;
 	**/
 	**/
 	public function toUInt64():UInt64;
 	public function toUInt64():UInt64;
 
 
+	public function toInt32():Int32;
+
 	/**
 	/**
 		Convert to `haxe.Int64`.
 		Convert to `haxe.Int64`.
 	**/
 	**/
@@ -72,12 +79,12 @@ package eval.integers;
 	/**
 	/**
 		Successor.
 		Successor.
 	**/
 	**/
-	public function successor():String;
+	public function successor():Int64;
 
 
 	/**
 	/**
 		Predecessor.
 		Predecessor.
 	**/
 	**/
-	public function predecessor():String;
+	public function predecessor():Int64;
 
 
 	/**
 	/**
 		Integer remainder.
 		Integer remainder.
@@ -94,8 +101,15 @@ package eval.integers;
 	function logxor(u:Int64):Int64;
 	function logxor(u:Int64):Int64;
 	function shift_left(i:Int):Int64;
 	function shift_left(i:Int):Int64;
 	function shift_right(i:Int):Int64;
 	function shift_right(i:Int):Int64;
+	function shift_right_logical(i:Int):Int64;
 	function lognot():Int64;
 	function lognot():Int64;
 
 
+	@:op(-A) function neg():Int64;
+	@:op(++A) function preIncr():Int64;
+	@:op(A++) function postIncr():Int64;
+	@:op(--A) function preDecr():Int64;
+	@:op(A--) function postDecr():Int64;
+
 	@:op(A + B) inline function _add(u:Int64):Int64 return this.add(u);
 	@:op(A + B) inline function _add(u:Int64):Int64 return this.add(u);
 	@:op(A - B) inline function _sub(u:Int64):Int64 return this.sub(u);
 	@:op(A - B) inline function _sub(u:Int64):Int64 return this.sub(u);
 	@:op(A * B) inline function _mul(u:Int64):Int64 return this.mul(u);
 	@:op(A * B) inline function _mul(u:Int64):Int64 return this.mul(u);
@@ -106,6 +120,7 @@ package eval.integers;
 	@:op(A ^ B) inline function _logxor(u:Int64):Int64 return this.logxor(u);
 	@:op(A ^ B) inline function _logxor(u:Int64):Int64 return this.logxor(u);
 	@:op(A << B) inline function _shift_left(i:Int):Int64 return this.shift_left(i);
 	@:op(A << B) inline function _shift_left(i:Int):Int64 return this.shift_left(i);
 	@:op(A >> B) inline function _shift_right(i:Int):Int64 return this.shift_right(i);
 	@:op(A >> B) inline function _shift_right(i:Int):Int64 return this.shift_right(i);
+	@:op(A >>> B) inline function _shift_right_logical(i:Int):Int64 return this.shift_right_logical(i);
 	@:op(~A) inline function _lognot():Int64 return this.lognot();
 	@:op(~A) inline function _lognot():Int64 return this.lognot();
 
 
 	@:op(A != B) static inline function eq(a:Int64, b:Int64):Bool return compare(a, b) != 0;
 	@:op(A != B) static inline function eq(a:Int64, b:Int64):Bool return compare(a, b) != 0;

+ 2 - 0
tests/unit/src/unit/issues/Issue12264.hx

@@ -1,6 +1,7 @@
 package unit.issues;
 package unit.issues;
 
 
 class Issue12264 extends Test {
 class Issue12264 extends Test {
+	#if !eval
 	function test() {
 	function test() {
 		#if (cpp || jvm || hl)
 		#if (cpp || jvm || hl)
 		eq(true, Type.typeof(0i64).match(TInt));
 		eq(true, Type.typeof(0i64).match(TInt));
@@ -8,4 +9,5 @@ class Issue12264 extends Test {
 		eq(true, Type.typeof(0i64).match(TClass(_)));
 		eq(true, Type.typeof(0i64).match(TClass(_)));
 		#end
 		#end
 	}
 	}
+	#end
 }
 }