Преглед изворни кода

floats indexes, write code

Nicolas Cannasse пре 10 година
родитељ
комит
707a5dcdbb
1 измењених фајлова са 270 додато и 41 уклоњено
  1. 270 41
      genhl.ml

+ 270 - 41
genhl.ml

@@ -58,8 +58,8 @@ type ttype =
 	| TF32
 	| TF64
 	| TBool
-	| TFun of ttype list * ttype
 	| TAny
+	| TFun of ttype list * ttype
 
 (*
 
@@ -83,7 +83,7 @@ type global = int
 type opcode =
 	| OMov of reg * reg
 	| OInt of reg * int32
-	| OFloat of reg * float
+	| OFloat of reg * int
 	| OBool of reg * bool
 	| OAdd of reg * reg * reg
 	| OSub of reg * reg * reg
@@ -95,7 +95,7 @@ type opcode =
 	| OCall3 of reg * global * reg * reg * reg
 	| OCallN of reg * reg * reg list
 	| OGetGlobal of reg * global
-	| OSetGlobal of global * reg
+	| OSetGlobal of reg * global
 	| OEq of reg * reg * reg
 	| ONotEq of reg * reg * reg
 	| OLt of reg * reg * reg
@@ -118,6 +118,7 @@ type code = {
 	version : int;
 	entrypoint : global;
 	globals : ttype array;
+	floats : float array;
 	functions : fundecl array;
 	natives : (string * int) array;
 }
@@ -131,6 +132,8 @@ type method_context = {
 type context = {
 	com : Common.context;
 	mutable hglobals : (string, int) PMap.t;
+	mutable hfloats : (float, int) PMap.t;
+	cfloats : float DynArray.t;
 	cglobals : ttype DynArray.t;
 	cfunctions : fundecl DynArray.t;
 	cnatives : (string * int) DynArray.t;
@@ -148,6 +151,10 @@ let rec tstr t =
 	| TAny -> "any"
 	| TFun (args,ret) -> "(" ^ String.concat "," (List.map tstr args) ^ "):" ^ tstr ret
 
+let iteri f l =
+	let p = ref (-1) in
+	List.iter (fun v -> incr p; f !p v) l
+
 let method_context() =
 	{
 		mregs = DynArray.create();
@@ -205,6 +212,15 @@ let alloc_reg ctx v =
 		ctx.m.hregs <- PMap.add v.v_id rid ctx.m.hregs;
 		rid
 
+let alloc_float ctx f =
+	try
+		PMap.find f ctx.hfloats
+	with Not_found ->
+		let fid = DynArray.length ctx.cfloats in
+		DynArray.add ctx.cfloats f;
+		ctx.hfloats <- PMap.add f fid ctx.hfloats;
+		fid
+
 let alloc_tmp ctx t =
 	let rid = DynArray.length ctx.m.mregs in
 	DynArray.add ctx.m.mregs t;
@@ -231,7 +247,7 @@ let rec eval_expr ctx e =
 			r
 		| TFloat f ->
 			let r = alloc_tmp ctx TF64 in
-			op ctx (OFloat (r,float_of_string f));
+			op ctx (OFloat (r,alloc_float ctx (float_of_string f)));
 			r
 		| Type.TBool b ->
 			let r = alloc_tmp ctx TBool in
@@ -351,7 +367,7 @@ let make_fun ctx f idx =
 			match c with
 			| TNull | TThis | TSuper -> assert false
 			| TInt i -> op ctx (OInt (r, i))
-			| TFloat s -> op ctx (OFloat (r, float_of_string s))
+			| TFloat s -> op ctx (OFloat (r, alloc_float ctx (float_of_string s)))
 			| Type.TBool b -> op ctx (OBool (r, b))
 			| TString s -> assert false (* TODO *)
 	) f.tf_args;
@@ -423,35 +439,6 @@ let rec str v =
 	| VAny (v,t) -> "any(" ^ str v ^ ":" ^ tstr t ^ ")"
 	| VNativeFun _ -> "native"
 
-let ostr o =
-	match o with
-	| OMov (a,b) -> Printf.sprintf "mov %d,%d" a b
-	| OInt (r,i) -> Printf.sprintf "int %d,%ld" r i
-	| OFloat (r,f) -> Printf.sprintf "float %d,%f" r f
-	| OBool (r,b) -> if b then Printf.sprintf "true %d" r else Printf.sprintf "false %d" r
-	| OAdd (r,a,b) -> Printf.sprintf "add %d,%d,%d" r a b
-	| OSub (r,a,b) -> Printf.sprintf "sub %d,%d,%d" r a b
-	| OIncr r -> Printf.sprintf "incr %d" r
-	| ODecr r -> Printf.sprintf "decr %d" r
-	| OCall0 (r,g) -> Printf.sprintf "call %d, %d()" r g
-	| OCall1 (r,g,a) -> Printf.sprintf "call %d, %d(%d)" r g a
-	| OCall2 (r,g,a,b) -> Printf.sprintf "call %d, %d(%d,%d)" r g a b
-	| OCall3 (r,g,a,b,c) -> Printf.sprintf "call %d, %d(%d,%d,%d)" r g a b c
-	| OCallN (r,g,rl) -> Printf.sprintf "call %d, %d(%s)" r g (String.concat "," (List.map string_of_int rl))
-	| OGetGlobal (r,g) -> Printf.sprintf "global %d, %d" r g
-	| OSetGlobal (g,r) -> Printf.sprintf "setglobal %d, %d" g r
-	| OEq (r,a,b) -> Printf.sprintf "eq %d,%d,%d" r a b
-	| ONotEq (r,a,b)  -> Printf.sprintf "noteq %d,%d,%d" r a b
-	| OLt (r,a,b) -> Printf.sprintf "lt %d,%d,%d" r a b
-	| OGte (r,a,b) -> Printf.sprintf "gte %d,%d,%d" r a b
-	| ORet r -> Printf.sprintf "ret %d" r
-	| OJTrue (r,d) -> Printf.sprintf "jtrue %d,%d" r d
-	| OJFalse (r,d) -> Printf.sprintf "jfalse %d,%d" r d
-	| OJNull (r,d) -> Printf.sprintf "jnull %d,%d" r d
-	| OJNotNull (r,d) -> Printf.sprintf "jnotnull %d,%d" r d
-	| OJAlways d -> Printf.sprintf "jalways %d" d
-	| OToAny (r,a) -> Printf.sprintf "toany %d,%d" r a
-
 let interp code =
 
 	let check f =
@@ -485,7 +472,7 @@ let interp code =
 		let can_jump delta =
 			if !pos + 1 + delta < 0 || !pos + 1 + delta >= Array.length f.code then failwith "Jump outside function bounds";
 		in
-		List.iteri reg targs;
+		iteri reg targs;
 		Array.iteri (fun i op ->
 			pos := i;
 			match op with
@@ -496,8 +483,9 @@ let interp code =
 				| TUI8 -> if Int32.to_int i < 0 || Int32.to_int i > 0xFF then reg r TI32
 				| TI32 -> ()
 				| _ -> reg r TI32)
-			| OFloat (r,_) ->
-				if rtype r <> TF32 then reg r TF64
+			| OFloat (r,i) ->
+				if rtype r <> TF32 then reg r TF64;
+				if i < 0 || i >= Array.length code.floats then failwith "float outside range"
 			| OBool (r,_) ->
 				reg r TBool
 			| OAdd (r,a,b) ->
@@ -524,7 +512,7 @@ let interp code =
 				(match rtype f with
 				| TFun (targs,tret) when List.length targs = List.length rl -> List.iter2 reg rl targs; reg r tret
 				| _ -> reg f (TFun(List.map rtype rl,rtype r)))
-			| OGetGlobal (r,g) | OSetGlobal (g,r) ->
+			| OGetGlobal (r,g) | OSetGlobal (r,g) ->
 				reg r code.globals.(g)
 			| OEq (r,a,b) | ONotEq (r, a, b) | OLt (r, a, b) | OGte (r, a, b) ->
 				reg r TBool;
@@ -550,7 +538,7 @@ let interp code =
 
 	let rec call f args =
 		let regs = Array.map default f.regs in
-		List.iteri (fun i v -> regs.(i) <- v) args;
+		iteri (fun i v -> regs.(i) <- v) args;
 		let pos = ref 0 in
 		let rtype i = f.regs.(i) in
 		let set r v = Array.unsafe_set regs r v in
@@ -592,7 +580,7 @@ let interp code =
 			(match op with
 			| OMov (a,b) -> set a (get b)
 			| OInt (r,i) -> set r (VInt i)
-			| OFloat (r,f) -> set r (VFloat f)
+			| OFloat (r,i) -> set r (VFloat (Array.unsafe_get code.floats i))
 			| OBool (r,b) -> set r (VBool b)
 			| OAdd (r,a,b) -> set r (numop Int32.add ( +. ) a b)
 			| OSub (r,a,b) -> set r (numop Int32.sub ( -. ) a b)
@@ -608,7 +596,7 @@ let interp code =
 				| VNativeFun f -> set r (f (List.map get rl))
 				| _ -> assert false)
 			| OGetGlobal (r,g) -> set r (global g)
-			| OSetGlobal (g,r) -> Array.unsafe_set globals g (get r)
+			| OSetGlobal (r,g) -> Array.unsafe_set globals g (get r)
 			| OEq (r,a,b) -> set r (VBool (get a = get b))
 			| ONotEq (r,a,b) -> set r (VBool (get a <> get b))
 			| OGte (r,a,b) -> set r (VBool (get a >= get b))
@@ -641,6 +629,234 @@ let interp code =
 	| _ -> assert false
 
 (* --------------------------------------------------------------------------------------------------------------------- *)
+(* WRITE *)
+
+let write_code ch code =
+	IO.write_string ch "HLB";
+	IO.write_byte ch code.version;
+	IO.write_i32 ch code.entrypoint;
+	IO.write_i32 ch (Array.length code.globals);
+	IO.write_i32 ch (Array.length code.functions);
+	IO.write_i32 ch (Array.length code.natives);
+
+	let b = IO.write_byte ch in
+	let byte = b in
+
+	(* 	from -500M to +500M
+		0[7] = 0-127
+		10[+/-][5] [8] = -x2000/+x2000
+		11[+/-][5] [24] = -x20000000/+x20000000
+	*)
+	let write_index i =
+		if i < 0 then
+			let i = -i in
+			if i < 0x2000 then begin
+				b ((i lsr 8) lor 0xA0);
+				b (i land 0xFF);
+			end else if i >= 0x20000000 then assert false else begin
+				b ((i lsr 24) lor 0xE0);
+				b ((i lsr 16) land 0xFF);
+				b ((i lsr 8) land 0xFF);
+				b (i land 0xFF);
+			end
+		else if i < 0x80 then
+			b i
+		else if i < 0x2000 then begin
+			b ((i lsr 8) lor 0x80);
+			b (i land 0xFF);
+		end else if i >= 0x20000000 then assert false else begin
+			b ((i lsr 24) lor 0xC0);
+			b ((i lsr 16) land 0xFF);
+			b ((i lsr 8) land 0xFF);
+			b (i land 0xFF);
+		end
+	in
+
+	let rec write_type = function
+		| TVoid -> b 0
+		| TUI8	-> b 1
+		| TI32	-> b 2
+		| TF32 	-> b 3
+		| TF64	-> b 4
+		| TBool	-> b 5
+		| TAny -> b 6
+		| TFun (tl,t) ->
+			let nargs = List.length tl in
+			if nargs > 0xFF then assert false;
+			if nargs < 5 then b (7 + nargs) else begin b 12; b nargs; end;
+			List.iter write_type tl;
+			write_type t
+	in
+
+	let reg = write_index in
+
+	let binop i r ra rb =
+		if r < 8 && ra < 8 && rb < 8 && i < 64 then begin
+			(* short format : 2 bytes instead of 4 *)
+			b (((i lsl 1) lor 0x80) lor (if r > 4 then 1 else 0));
+			b (((r land 3) lsl 6) lor (ra lsl 3) lor rb);
+		end else begin
+			b i;
+			reg r;
+			reg ra;
+			reg rb;
+		end
+	in
+
+	let unop i r =
+		b i;
+		reg r
+	in
+
+	let write_op = function
+		| OMov (a,b) ->
+			byte 0;
+			reg a;
+			reg b;
+		| OInt (r, i) when i >= 0l && i <= 0xFFl ->
+			b 1;
+			reg r;
+			b (Int32.to_int i);
+		| OInt (r, i) ->
+			b 2;
+			reg r;
+			IO.write_real_i32 ch i
+		| OFloat (r,i) ->
+			b 3;
+			reg r;
+			write_index i
+		| OBool (r, f) ->
+			b (if f then 4 else 5);
+			reg r
+		| OAdd (r,a,b) ->
+			binop 6 r a b
+		| OSub (r,a,b) ->
+			binop 7 r a b
+		| OIncr r ->
+			unop 8 r
+		| ODecr r ->
+			unop 9 r
+		| OCall0 (r, g) ->
+			b 10;
+			reg r;
+			write_index g
+		| OCall1 (r,g,a) ->
+			b 11;
+			reg r;
+			write_index g;
+			reg a
+		| OCall2 (r,g,a,b) ->
+			byte 12;
+			reg r;
+			write_index g;
+			reg a;
+			reg b;
+		| OCall3 (r,g,a,b,c) ->
+			byte 12;
+			reg r;
+			write_index g;
+			reg a;
+			reg b;
+			reg c;
+		| OCallN (r, f, pl) ->
+			byte 13;
+			reg r;
+			reg f;
+			let n = List.length pl in
+			if n > 0xFF then assert false;
+			b n;
+			List.iter reg pl
+		| OGetGlobal (r, g) ->
+			b 14;
+			reg r;
+			write_index g
+		| OSetGlobal (r, g) ->
+			b 15;
+			write_index g;
+			reg r
+		| OEq (r,a,b) ->
+			binop 16 r a b
+		| ONotEq (r,a,b) ->
+			binop 17 r a b
+		| OLt (r,a,b) ->
+			binop 18 r a b
+		| OGte (r,a,b) ->
+			binop 20 r a b
+		| ORet r ->
+			unop 21 r
+		| OJTrue (r,i) ->
+			b 22;
+			reg r;
+			write_index i
+		| OJFalse (r, i) ->
+			b 23;
+			reg r;
+			write_index i
+		| OJNull (r, i) ->
+			b 24;
+			reg r;
+			write_index i
+		| OJNotNull (r, i) ->
+			b 25;
+			reg r;
+			write_index i
+		| OJAlways i ->
+			b 26;
+			write_index i
+		| OToAny (a,b) ->
+			byte 27;
+			reg a;
+			reg b
+	in
+	Array.iter write_type code.globals;
+	Array.iter (fun f ->
+		write_index f.index;
+		write_index (Array.length f.regs);
+		write_index (Array.length f.code);
+		Array.iter write_type f.regs;
+		Array.iter write_op f.code;
+	) code.functions;
+	Array.iter (fun (n,nargs) ->
+		let len = String.length n in
+		if len > 0xFF then assert false;
+		if nargs > 0xFF then assert false;
+		b len;
+		IO.write_string ch n;
+		b nargs;
+	) code.natives
+
+
+(* --------------------------------------------------------------------------------------------------------------------- *)
+(* DUMP *)
+
+let ostr o =
+	match o with
+	| OMov (a,b) -> Printf.sprintf "mov %d,%d" a b
+	| OInt (r,i) -> Printf.sprintf "int %d,%ld" r i
+	| OFloat (r,i) -> Printf.sprintf "float %d,@%d" r i
+	| OBool (r,b) -> if b then Printf.sprintf "true %d" r else Printf.sprintf "false %d" r
+	| OAdd (r,a,b) -> Printf.sprintf "add %d,%d,%d" r a b
+	| OSub (r,a,b) -> Printf.sprintf "sub %d,%d,%d" r a b
+	| OIncr r -> Printf.sprintf "incr %d" r
+	| ODecr r -> Printf.sprintf "decr %d" r
+	| OCall0 (r,g) -> Printf.sprintf "call %d, %d()" r g
+	| OCall1 (r,g,a) -> Printf.sprintf "call %d, %d(%d)" r g a
+	| OCall2 (r,g,a,b) -> Printf.sprintf "call %d, %d(%d,%d)" r g a b
+	| OCall3 (r,g,a,b,c) -> Printf.sprintf "call %d, %d(%d,%d,%d)" r g a b c
+	| OCallN (r,g,rl) -> Printf.sprintf "call %d, %d(%s)" r g (String.concat "," (List.map string_of_int rl))
+	| OGetGlobal (r,g) -> Printf.sprintf "global %d, %d" r g
+	| OSetGlobal (g,r) -> Printf.sprintf "setglobal %d, %d" g r
+	| OEq (r,a,b) -> Printf.sprintf "eq %d,%d,%d" r a b
+	| ONotEq (r,a,b)  -> Printf.sprintf "noteq %d,%d,%d" r a b
+	| OLt (r,a,b) -> Printf.sprintf "lt %d,%d,%d" r a b
+	| OGte (r,a,b) -> Printf.sprintf "gte %d,%d,%d" r a b
+	| ORet r -> Printf.sprintf "ret %d" r
+	| OJTrue (r,d) -> Printf.sprintf "jtrue %d,%d" r d
+	| OJFalse (r,d) -> Printf.sprintf "jfalse %d,%d" r d
+	| OJNull (r,d) -> Printf.sprintf "jnull %d,%d" r d
+	| OJNotNull (r,d) -> Printf.sprintf "jnotnull %d,%d" r d
+	| OJAlways d -> Printf.sprintf "jalways %d" d
+	| OToAny (r,a) -> Printf.sprintf "toany %d,%d" r a
 
 let dump code =
 	let lines = ref [] in
@@ -652,6 +868,10 @@ let dump code =
 	Array.iteri (fun i g ->
 		pr ("	@" ^ string_of_int i ^ " : " ^ tstr g);
 	) code.globals;
+	pr (string_of_int (Array.length code.floats) ^ " floats");
+	Array.iteri (fun i f ->
+		pr ("	@" ^ string_of_int i ^ " : " ^ string_of_float f);
+	) code.floats;
 	pr (string_of_int (Array.length code.functions) ^ " functions");
 	Array.iter (fun f ->
 		pr ("	fun " ^ string_of_int f.index ^ " : " ^ (try tstr code.globals.(f.index) with _ -> "???"));
@@ -680,6 +900,8 @@ let generate com =
 		cfunctions = DynArray.create();
 		cnatives = DynArray.create();
 		hglobals = PMap.empty;
+		hfloats = PMap.empty;
+		cfloats = DynArray.create();
 	} in
 	List.iter (generate_type ctx) com.types;
 	let ep = (match com.main_class with
@@ -691,9 +913,16 @@ let generate com =
 		version = 1;
 		entrypoint = ep;
 		globals = DynArray.to_array ctx.cglobals;
+		floats = DynArray.to_array ctx.cfloats;
 		functions = DynArray.to_array ctx.cfunctions;
 		natives = DynArray.to_array ctx.cnatives;
 	} in
 	prerr_endline (dump code);
+	let ch = IO.output_string() in
+	write_code ch code;
+	let str = IO.close_out ch in
+	let ch = open_out_bin com.file in
+	output_string ch str;
+	close_out ch;
 	ignore(interp code)