@@ -249,6 +249,21 @@ module Location = struct
249249end
250250
251251module IfExpressions = struct
252+ (* Check if an expression is simple enough to remain as a ternary operator *)
253+ let rec isSimpleValue (e : exp ) =
254+ match e.e with
255+ | EUnit | EBool _ | EInt _ | EReal _ | EFixed _ | EString _ -> true
256+ | EId _ | EMember _ -> true
257+ | EUnOp (_ , e ) -> isSimpleValue e
258+ | _ -> false
259+
260+
261+ let isSimpleIf (e : exp ) =
262+ match e.e with
263+ | EIf { cond; then_; else_ } -> isSimpleValue cond && isSimpleValue then_ && isSimpleValue else_
264+ | _ -> false
265+
266+
252267 let stmt_env =
253268 Mapper. makeEnv
254269 @@ fun env (s : stmt ) ->
@@ -291,6 +306,8 @@ module IfExpressions = struct
291306 then_
292307 else
293308 else_ )
309+ (* Preserve simple if-expressions as ternary operators *)
310+ | { e = EIf _ ; _ } when isSimpleIf e -> state, e
294311 (* Bind if-expressions to a variable in function context *)
295312 | { e = EIf _ ; t; loc } when (not env.in_if_exp) && (not env.bound_if) && env.in_function ->
296313 let tick = getTick env state in
@@ -929,12 +946,30 @@ module StrengthReduction = struct
929946 | TReal -> reapply state, C. ereal ~loc: e.loc 0.0
930947 | TFix16 -> reapply state, C. efix16 ~loc: e.loc 0.0
931948 | _ -> state, e)
949+ (* x * -1 -> -x *)
950+ | { e = EOp (OpMul, e1 , { e = EInt - 1 ; _ } ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e1) }
951+ | { e = EOp (OpMul, { e = EInt - 1 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
952+ (* x % 1 -> 0 *)
953+ | { e = EOp (OpMod, _ , { e = EInt 1 ; _ } ); loc; _ } -> reapply state, C. eint ~loc 0
954+ (* NOTE: x % 2^n -> x & (2^n - 1) optimization removed because Lua 5.1/LuaJIT
955+ doesn't support native bitwise operators, and modulo works correctly *)
956+ (* 0 / x -> 0 *)
957+ | { e = EOp (OpDiv, { e = EInt 0 ; _ } , _ ); loc; _ } -> reapply state, C. eint ~loc 0
958+ (* 0 - x -> -x *)
959+ | { e = EOp (OpSub, { e = EInt 0 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
932960 (* ========== FLOATING POINT ARITHMETIC OPTIMIZATIONS ========== *)
933961 (* x * 0.0 -> 0.0, x * 1.0 -> x *)
934962 | { e = EOp (OpMul , _ , { e = EReal 0.0 ; _ } ); _ } | { e = EOp (OpMul, { e = EReal 0.0 ; _ } , _ ); _ } ->
935963 reapply state, { e with e = EReal 0.0 }
936964 | { e = EOp (OpMul, e1 , { e = EReal 1.0 ; _ } ); _ } -> reapply state, e1
937965 | { e = EOp (OpMul, { e = EReal 1.0 ; _ } , e2 ); _ } -> reapply state, e2
966+ (* x * -1.0 -> -x *)
967+ | { e = EOp (OpMul, e1 , { e = EReal - 1.0 ; _ } ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e1) }
968+ | { e = EOp (OpMul, { e = EReal - 1.0 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
969+ (* 0.0 / x -> 0.0 *)
970+ | { e = EOp (OpDiv, { e = EReal 0.0 ; _ } , _ ); loc; _ } -> reapply state, C. ereal ~loc 0.0
971+ (* 0.0 - x -> -x *)
972+ | { e = EOp (OpSub, { e = EReal 0.0 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
938973 (* Removed x * 2.0 -> x + x transformation as it interferes with constant folding *)
939974 (* Removed x * 0.5 <-> x / 2.0 transformations as they create cycles with other passes *)
940975 (* Removed problematic power-of-2 real multiplication transformation *)
@@ -945,6 +980,18 @@ module StrengthReduction = struct
945980 | { e = EOp (OpMul, e1 , { e = EFixed 1.0 ; _ } ); _ } -> reapply state, e1
946981 | { e = EOp (OpMul, { e = EFixed 1.0 ; _ } , e2 ); _ } ->
947982 reapply state, e2 (* Removed x * 2.0 -> x + x for fixed point as it interferes with constant folding *)
983+ (* x * -1.0 -> -x (fixed) *)
984+ | { e = EOp (OpMul, e1 , { e = EFixed - 1.0 ; _ } ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e1) }
985+ | { e = EOp (OpMul, { e = EFixed - 1.0 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
986+ (* 0.0 / x -> 0.0 (fixed) *)
987+ | { e = EOp (OpDiv, { e = EFixed 0.0 ; _ } , _ ); loc; _ } -> reapply state, C. efix16 ~loc 0.0
988+ (* 0.0 - x -> -x (fixed) *)
989+ | { e = EOp (OpSub, { e = EFixed 0.0 ; _ } , e2 ); _ } -> reapply state, { e with e = EUnOp (UOpNeg , e2) }
990+ (* ========== DIVISION BY 1 OPTIMIZATIONS ========== *)
991+ (* x / 1 -> x (for all numeric types) *)
992+ | { e = EOp (OpDiv, e1 , { e = EInt 1 ; _ } ); _ } -> reapply state, e1
993+ | { e = EOp (OpDiv, e1 , { e = EReal 1.0 ; _ } ); _ } -> reapply state, e1
994+ | { e = EOp (OpDiv, e1 , { e = EFixed 1.0 ; _ } ); _ } -> reapply state, e1
948995 (* ========== FUNCTION CALL OPTIMIZATIONS ========== *)
949996 (* pow(x, 2) -> x * x *)
950997 | { e = ECall { path = "pow" ; args = [ x; { e = EReal 2.0 ; _ } ] } ; _ } ->
@@ -975,6 +1022,13 @@ module StrengthReduction = struct
9751022 reapply state, { e with e = EOp (OpDiv , C. ereal ~loc 1.0 , x) }
9761023 | { e = ECall { path = "pow" ; args = [ x; { e = EInt - 1 ; _ } ] } ; loc; _ } ->
9771024 reapply state, { e with e = EOp (OpDiv , C. ereal ~loc 1.0 , x) }
1025+ (* pow(x, -2) -> 1.0 / (x * x) *)
1026+ | { e = ECall { path = "pow" ; args = [ x; { e = EReal - 2.0 ; _ } ] } ; loc; _ } ->
1027+ let x_squared = { e with e = EOp (OpMul , x, x) } in
1028+ reapply state, { e with e = EOp (OpDiv , C. ereal ~loc 1.0 , x_squared) }
1029+ | { e = ECall { path = "pow" ; args = [ x; { e = EInt - 2 ; _ } ] } ; loc; _ } ->
1030+ let x_squared = { e with e = EOp (OpMul , x, x) } in
1031+ reapply state, { e with e = EOp (OpDiv , C. ereal ~loc 1.0 , x_squared) }
9781032 (* pow(x, 1) -> x *)
9791033 | { e = ECall { path = "pow" ; args = [ x; { e = EReal 1.0 ; _ } ] } ; _ } -> reapply state, x
9801034 | { e = ECall { path = "pow" ; args = [ x; { e = EInt 1 ; _ } ] } ; _ } -> reapply state, x
@@ -1013,6 +1067,46 @@ module StrengthReduction = struct
10131067 (* x << 0 -> x, x >> 0 -> x *)
10141068 | { e = EOp (OpLsh, e1 , { e = EInt 0 ; _ } ); _ } -> reapply state, e1
10151069 | { e = EOp (OpRsh, e1 , { e = EInt 0 ; _ } ); _ } -> reapply state, e1
1070+ (* x & x -> x, x | x -> x *)
1071+ | { e = EOp (OpBand, e1 , e2 ); _ } when Compare. exp e1 e2 = 0 -> reapply state, e1
1072+ | { e = EOp (OpBor, e1 , e2 ); _ } when Compare. exp e1 e2 = 0 -> reapply state, e1
1073+ (* x & -1 -> x (all bits set) *)
1074+ | { e = EOp (OpBand, e1 , { e = EInt - 1 ; _ } ); _ } -> reapply state, e1
1075+ | { e = EOp (OpBand, { e = EInt - 1 ; _ } , e2 ); _ } -> reapply state, e2
1076+ (* ========== NEGATION OPTIMIZATIONS ========== *)
1077+ (* -(-x) -> x *)
1078+ | { e = EUnOp (UOpNeg, { e = EUnOp (UOpNeg, x ); _ } ); _ } -> reapply state, x
1079+ (* not(not(x)) -> x *)
1080+ | { e = EUnOp (UOpNot, { e = EUnOp (UOpNot, x ); _ } ); _ } -> reapply state, x
1081+ (* ========== BOOLEAN LOGIC OPTIMIZATIONS ========== *)
1082+ (* x && true -> x *)
1083+ | { e = EOp (OpLand, e1 , { e = EBool true ; _ } ); _ } -> reapply state, e1
1084+ | { e = EOp (OpLand, { e = EBool true ; _ } , e2 ); _ } -> reapply state, e2
1085+ (* x && false -> false *)
1086+ | { e = EOp (OpLand, _ , { e = EBool false ; loc; _ } ); _ } -> reapply state, C. ebool ~loc false
1087+ | { e = EOp (OpLand, { e = EBool false ; loc; _ } , _ ); _ } -> reapply state, C. ebool ~loc false
1088+ (* x || false -> x *)
1089+ | { e = EOp (OpLor, e1 , { e = EBool false ; _ } ); _ } -> reapply state, e1
1090+ | { e = EOp (OpLor, { e = EBool false ; _ } , e2 ); _ } -> reapply state, e2
1091+ (* x || true -> true *)
1092+ | { e = EOp (OpLor, _ , { e = EBool true ; loc; _ } ); _ } -> reapply state, C. ebool ~loc true
1093+ | { e = EOp (OpLor, { e = EBool true ; loc; _ } , _ ); _ } -> reapply state, C. ebool ~loc true
1094+ (* ========== COMPARISON SELF-IDENTITIES ========== *)
1095+ (* x == x -> true (int only, floats have NaN) *)
1096+ | { e = EOp (OpEq, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 && e1.t.t = TInt -> reapply state, C. ebool ~loc true
1097+ (* x != x -> false (int only) *)
1098+ | { e = EOp (OpNe, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 && e1.t.t = TInt ->
1099+ reapply state, C. ebool ~loc false
1100+ (* x < x -> false, x > x -> false *)
1101+ | { e = EOp (OpLt, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 -> reapply state, C. ebool ~loc false
1102+ | { e = EOp (OpGt, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 -> reapply state, C. ebool ~loc false
1103+ (* x <= x -> true, x >= x -> true (int only) *)
1104+ | { e = EOp (OpLe, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 && e1.t.t = TInt -> reapply state, C. ebool ~loc true
1105+ | { e = EOp (OpGe, e1 , e2 ); loc; _ } when Compare. exp e1 e2 = 0 && e1.t.t = TInt -> reapply state, C. ebool ~loc true
1106+ (* ========== MIN/MAX OPTIMIZATIONS ========== *)
1107+ (* min(x, x) -> x, max(x, x) -> x *)
1108+ | { e = ECall { path = "min" ; args = [ x1; x2 ] } ; _ } when Compare. exp x1 x2 = 0 -> reapply state, x1
1109+ | { e = ECall { path = "max" ; args = [ x1; x2 ] } ; _ } when Compare. exp x1 x2 = 0 -> reapply state, x1
10161110 (* No optimization found *)
10171111 | _ -> state, e
10181112
0 commit comments