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

Analyzer const propagation typing fixes (#12059)

* track const type

* use actual type and fix equality check

* don't optimize shifts if we're not numeric
Simon Krajewski пре 5 месеци
родитељ
комит
52104c5e25

+ 21 - 9
src/optimization/analyzer.ml

@@ -185,6 +185,7 @@ end
 
 
 module type DataFlowApi = sig
 module type DataFlowApi = sig
 	type t
 	type t
+	val to_string : t -> string
 	val flag : BasicBlock.cfg_edge_Flag
 	val flag : BasicBlock.cfg_edge_Flag
 	val transfer : analyzer_context -> BasicBlock.t -> texpr -> t (* The transfer function *)
 	val transfer : analyzer_context -> BasicBlock.t -> texpr -> t (* The transfer function *)
 	val equals : t -> t -> bool                                   (* The equality function *)
 	val equals : t -> t -> bool                                   (* The equality function *)
@@ -360,10 +361,20 @@ module ConstPropagation = DataFlow(struct
 		| Top
 		| Top
 		| Bottom
 		| Bottom
 		| Null of Type.t
 		| Null of Type.t
-		| Const of tconstant
+		| Const of tconstant * Type.t
 		| EnumValue of int * t list
 		| EnumValue of int * t list
 		| ModuleType of module_type * Type.t
 		| ModuleType of module_type * Type.t
 
 
+	let rec to_string =
+		let st = s_type (print_context()) in
+		function
+		| Top -> "Top"
+		| Bottom -> "Bottom"
+		| Null t -> Printf.sprintf "Null(%s)" (st t)
+		| Const(ct,t) -> Printf.sprintf "Const(%s,%s)" (s_const ct) (st t)
+		| EnumValue(i,tl) -> Printf.sprintf "EnumValue(%i, %s)" i (String.concat ", " (List.map to_string tl))
+		| ModuleType(mt,t) -> Printf.sprintf "ModuleType(%s,%s)" (s_module_type_kind mt) (st t)
+
 	let conditional = true
 	let conditional = true
 	let flag = FlagExecutable
 	let flag = FlagExecutable
 
 
@@ -377,7 +388,7 @@ module ConstPropagation = DataFlow(struct
 
 
 	let equals lat1 lat2 = match lat1,lat2 with
 	let equals lat1 lat2 = match lat1,lat2 with
 		| Top,Top | Bottom,Bottom -> true
 		| Top,Top | Bottom,Bottom -> true
-		| Const ct1,Const ct2 -> ct1 = ct2
+		| Const(ct1,t1),Const(ct2,t2) -> ct1 = ct2 && type_iseq t1 t2
 		| Null t1,Null t2 -> t1 == t2
 		| Null t1,Null t2 -> t1 == t2
 		| EnumValue(i1,[]),EnumValue(i2,[]) -> i1 = i2
 		| EnumValue(i1,[]),EnumValue(i2,[]) -> i1 = i2
 		| ModuleType(mt1,_),ModuleType (mt2,_) -> mt1 == mt2
 		| ModuleType(mt1,_),ModuleType (mt2,_) -> mt1 == mt2
@@ -386,12 +397,12 @@ module ConstPropagation = DataFlow(struct
 	let transfer ctx bb e =
 	let transfer ctx bb e =
 		let rec eval bb e =
 		let rec eval bb e =
 			let wrap = function
 			let wrap = function
-				| Const ct -> mk (TConst ct) t_dynamic null_pos
+				| Const(ct,t) -> mk (TConst ct) t null_pos
 				| Null t -> mk (TConst TNull) t e.epos
 				| Null t -> mk (TConst TNull) t e.epos
 				| _ -> raise Exit
 				| _ -> raise Exit
 			in
 			in
 			let unwrap e = match e.eexpr with
 			let unwrap e = match e.eexpr with
-				| TConst ct -> Const ct
+				| TConst ct -> Const(ct,e.etype)
 				| _ -> raise Exit
 				| _ -> raise Exit
 			in
 			in
 			match e.eexpr with
 			match e.eexpr with
@@ -400,7 +411,7 @@ module ConstPropagation = DataFlow(struct
 			| TConst TNull ->
 			| TConst TNull ->
 				Null e.etype
 				Null e.etype
 			| TConst ct ->
 			| TConst ct ->
-				Const ct
+				Const(ct,e.etype)
 			| TTypeExpr mt ->
 			| TTypeExpr mt ->
 				ModuleType(mt,e.etype)
 				ModuleType(mt,e.etype)
 			| TLocal v ->
 			| TLocal v ->
@@ -442,12 +453,12 @@ module ConstPropagation = DataFlow(struct
 				end;
 				end;
 			| TEnumIndex e1 ->
 			| TEnumIndex e1 ->
 				begin match eval bb e1 with
 				begin match eval bb e1 with
-					| EnumValue(i,_) -> Const (TInt (Int32.of_int i))
+					| EnumValue(i,_) -> Const (TInt (Int32.of_int i),ctx.com.basic.tint)
 					| _ -> raise Exit
 					| _ -> raise Exit
 				end;
 				end;
 			| TCall ({ eexpr = TField (_,FStatic({cl_path=[],"Type"} as c,({cf_name="enumIndex"} as cf)))},[e1]) when ctx.com.platform = Eval ->
 			| TCall ({ eexpr = TField (_,FStatic({cl_path=[],"Type"} as c,({cf_name="enumIndex"} as cf)))},[e1]) when ctx.com.platform = Eval ->
 				begin match follow e1.etype,eval bb e1 with
 				begin match follow e1.etype,eval bb e1 with
-					| TEnum _,EnumValue(i,_) -> Const (TInt (Int32.of_int i))
+					| TEnum _,EnumValue(i,_) -> Const (TInt (Int32.of_int i),ctx.com.basic.tint)
 					| _,e1 ->
 					| _,e1 ->
 						begin match Inline.api_inline2 ctx.com c cf.cf_name [wrap e1] e.epos with
 						begin match Inline.api_inline2 ctx.com c cf.cf_name [wrap e1] e.epos with
 							| None -> raise Exit
 							| None -> raise Exit
@@ -472,7 +483,7 @@ module ConstPropagation = DataFlow(struct
 					| _ -> raise Exit
 					| _ -> raise Exit
 				in
 				in
 				begin match follow e1.etype,eval bb e1 with
 				begin match follow e1.etype,eval bb e1 with
-					| TEnum _,EnumValue(i,_) -> Const (TInt (Int32.of_int i))
+					| TEnum _,EnumValue(i,_) -> Const (TInt (Int32.of_int i),ctx.com.basic.tint)
 					| _ -> raise Exit
 					| _ -> raise Exit
 				end
 				end
 		in
 		in
@@ -488,8 +499,9 @@ module ConstPropagation = DataFlow(struct
 		let inline e i = match get_cell i with
 		let inline e i = match get_cell i with
 			| Top | Bottom | EnumValue _ | Null _ ->
 			| Top | Bottom | EnumValue _ | Null _ ->
 				raise Not_found
 				raise Not_found
-			| Const ct ->
+			| Const(ct,t) ->
 				let e' = Texpr.type_constant ctx.com.basic (tconst_to_const ct) e.epos in
 				let e' = Texpr.type_constant ctx.com.basic (tconst_to_const ct) e.epos in
+				let e' = {e' with etype = t} in
 				if not (type_change_ok ctx.com e'.etype e.etype) then raise Not_found;
 				if not (type_change_ok ctx.com e'.etype e.etype) then raise Not_found;
 				e'
 				e'
 			| ModuleType(mt,t) ->
 			| ModuleType(mt,t) ->

+ 3 - 3
src/optimization/optimizerTexpr.ml

@@ -130,9 +130,9 @@ let optimize_binop e op e1 e2 =
 		| OpAnd -> opt Int32.logand
 		| OpAnd -> opt Int32.logand
 		| OpOr -> opt Int32.logor
 		| OpOr -> opt Int32.logor
 		| OpXor -> opt Int32.logxor
 		| OpXor -> opt Int32.logxor
-		| OpShl -> opt (fun a b -> Int32.shift_left a (Int32.to_int (Int32.logand b i32_31)))
-		| OpShr -> opt (fun a b -> Int32.shift_right a (Int32.to_int (Int32.logand b i32_31)))
-		| OpUShr -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int (Int32.logand b i32_31)))
+		| OpShl when is_numeric e.etype -> opt (fun a b -> Int32.shift_left a (Int32.to_int (Int32.logand b i32_31)))
+		| OpShr when is_numeric e.etype -> opt (fun a b -> Int32.shift_right a (Int32.to_int (Int32.logand b i32_31)))
+		| OpUShr when is_numeric e.etype -> opt (fun a b -> Int32.shift_right_logical a (Int32.to_int (Int32.logand b i32_31)))
 		| OpEq -> ebool (=)
 		| OpEq -> ebool (=)
 		| OpNotEq -> ebool (<>)
 		| OpNotEq -> ebool (<>)
 		| OpGt -> ebool (>)
 		| OpGt -> ebool (>)

+ 1 - 1
tests/optimization/src/issues/Issue6229.hx

@@ -18,7 +18,7 @@ class Issue6229 {
 		}
 		}
 	}
 	}
 
 
-	@:js('var a = 1 + 1;')
+	@:js('var v_x = 1;var v_y = 1;var a = 2;')
 	@:analyzer(no_local_dce)
 	@:analyzer(no_local_dce)
     static function test() {
     static function test() {
         var v = mkVec(1);
         var v = mkVec(1);

+ 30 - 0
tests/unit/src/unit/issues/Issue12031.hx

@@ -0,0 +1,30 @@
+package unit.issues;
+
+import utest.Assert;
+
+class Issue12031 extends Test {
+	#if hl
+	inline function inlinef(v:hl.I64) {
+		var str = "";
+		str += (v >> 32);
+		return str;
+	}
+
+	function noInlinef(v:hl.I64) {
+		var str = "";
+		str += (v >> 32);
+		return str;
+	}
+
+	function test() {
+		var base:hl.I64 = 22; // 0b10110
+		eq(22, base.toInt());
+		eq("0", inlinef(base));
+		eq("0", noInlinef(base));
+		var manual1 = "" + (base >> 33);
+		eq("0", manual1);
+		var manual2 = "" + (base >> 34);
+		eq("0", manual2);
+	}
+	#end
+}