Kaynağa Gözat

optimized switch on ints

Nicolas Cannasse 17 yıl önce
ebeveyn
işleme
5a4fead43d
2 değiştirilmiş dosya ile 64 ekleme ve 19 silme
  1. 1 1
      doc/CHANGES.txt
  2. 63 18
      genswf9.ml

+ 1 - 1
doc/CHANGES.txt

@@ -1,6 +1,5 @@
 TODO genswf9 : inline code can give bad file in debug infos
 TODO genswf9 var x = if( true ) Math.POSITIVE_INFINITY : 0.; VerifyError
-TODO genswf9 : fast switch on ints
 TODO optimizer : optimizations and ast manipulation in a separate module
 TODO optimizer : when an object is only used localy, move its fields on the stack (allow inlined iterators)
 TODO optimizer : precompute constant expressions
@@ -23,6 +22,7 @@ TODO inlining : substitute class+function type parameters in order to have fully
 	fixed private/protected differences in gen-hx-classes
 	genswf9 : allowed to store a Class in a typed register
 	fixed switch-on-bool (don't use matching)
+	genswf9 : optimized switch on ints
 
 2008-02-23: 1.18
 	some optimization and bugfix for as3 codegen

+ 63 - 18
genswf9.ml

@@ -427,6 +427,26 @@ let begin_branch ctx =
 		(fun() -> ctx.infos.icond <- false)
 	end
 
+let begin_switch ctx =
+	let branch = begin_branch ctx in
+	let switch_index = DynArray.length ctx.code in
+	let switch_pos = ctx.infos.ipos in
+	write ctx (HSwitch (0,[]));
+	let constructs = ref [] in
+	let max = ref 0 in
+	let ftag tag = 
+		if tag > !max then max := tag;
+		constructs := (tag,ctx.infos.ipos) :: !constructs;
+	in
+	let fend() =
+		let cases = Array.create (!max + 1) 1 in
+		List.iter (fun (tag,pos) -> Array.set cases tag (pos - switch_pos)) !constructs;
+		DynArray.set ctx.code switch_index (HSwitch (1,Array.to_list cases));
+		branch();
+	in
+	fend, ftag
+
+
 let debug ctx p =
 	let line = Lexer.get_error_line p in
 	if ctx.last_line <> line then begin
@@ -838,6 +858,43 @@ let rec gen_expr_content ctx retval e =
 		no_value ctx retval
 	| TSwitch (e0,el,eo) ->
 		let t = classify ctx e.etype in
+		(try
+			(* generate optimized int switch *)
+			if t <> KInt && t <> KUInt then raise Exit;
+			let rec get_int e =
+				match e.eexpr with
+				| TConst (TInt n) -> Int32.to_int n
+				| TParenthesis e | TBlock [e] -> get_int e
+				| _ -> raise Not_found
+			in
+			List.iter (fun (vl,_) -> List.iter (fun v ->
+				let n = (try get_int v with _ -> raise Exit) in
+				if n < 0 || n > 512 then raise Exit;
+			) vl) el;
+			gen_expr ctx true e0;
+			let switch, case = begin_switch ctx in
+			(match eo with
+			| None ->
+				if retval then begin
+					write ctx HNull;
+					coerce ctx t;
+				end;
+			| Some e ->
+				gen_expr ctx retval e;
+				if retval && classify ctx e.etype <> t then coerce ctx t);
+			let jends = List.map (fun (vl,e) ->
+				let j = jump ctx J3Always in
+				List.iter (fun v -> case (get_int v)) vl;
+				gen_expr ctx retval e;
+				if retval then begin
+					ctx.infos.istack <- ctx.infos.istack - 1;
+					if classify ctx e.etype <> t then coerce ctx t;
+				end;
+				j
+			) el in
+			List.iter (fun j -> j()) jends;
+			switch();
+		with Exit ->
 		let r = alloc_reg ctx (classify ctx e0.etype) in
 		gen_expr ctx true e0;
 		set_reg ctx r;
@@ -880,7 +937,7 @@ let rec gen_expr_content ctx retval e =
 			if retval && classify ctx e.etype <> t then coerce ctx t;
 		);
 		List.iter (fun j -> j()) jend;
-		branch();
+		branch());
 	| TMatch (e0,_,cases,def) ->
 		let t = classify ctx e.etype in
 		let rparams = alloc_reg ctx (KType (type_path ctx ([],"Array"))) in
@@ -893,10 +950,7 @@ let rec gen_expr_content ctx retval e =
 		end;
 		write ctx (HGetProp (ident "index"));
 		write ctx HToInt;
-		let branch = begin_branch ctx in
-		let switch_index = DynArray.length ctx.code in
-		let switch_pos = ctx.infos.ipos in
-		write ctx (HSwitch (0,[]));
+		let switch,case = begin_switch ctx in
 		(match def with
 		| None ->
 			if retval then begin
@@ -905,16 +959,10 @@ let rec gen_expr_content ctx retval e =
 			end;
 		| Some e ->
 			gen_expr ctx retval e;
-			if retval && classify ctx e.etype <> t then coerce ctx t;
-		);
-		let constructs = ref [] in
-		let max = ref 0 in
-		let jends = List.map (fun (cl,params,e) ->
+			if retval && classify ctx e.etype <> t then coerce ctx t);
+		let jends = List.map (fun (cl,params,e) ->			
 			let j = jump ctx J3Always in
-			List.iter (fun tag ->
-				if tag > !max then max := tag;
-				constructs := (tag,ctx.infos.ipos) :: !constructs;
-			) cl;
+			List.iter case cl;
 			let b = open_block ctx [e] retval in
 			(match params with
 			| None -> ()
@@ -941,11 +989,8 @@ let rec gen_expr_content ctx retval e =
 			end;
 			j
 		) cases in
-		let cases = Array.create (!max + 1) 1 in
-		List.iter (fun (tag,pos) -> Array.set cases tag (pos - switch_pos)) !constructs;
+		switch();
 		List.iter (fun j -> j()) jends;
-		DynArray.set ctx.code switch_index (HSwitch (1,Array.to_list cases));
-		branch();
 		free_reg ctx rparams
 
 and gen_call ctx retval e el =