aboutsummaryrefslogtreecommitdiffstats
path: root/psl/psl-optimize.adb
diff options
context:
space:
mode:
Diffstat (limited to 'psl/psl-optimize.adb')
-rw-r--r--psl/psl-optimize.adb460
1 files changed, 460 insertions, 0 deletions
diff --git a/psl/psl-optimize.adb b/psl/psl-optimize.adb
new file mode 100644
index 000000000..4ca62b89e
--- /dev/null
+++ b/psl/psl-optimize.adb
@@ -0,0 +1,460 @@
+with Types; use Types;
+with PSL.NFAs.Utils; use PSL.NFAs.Utils;
+with PSL.CSE;
+
+package body PSL.Optimize is
+ procedure Push (Head : in out NFA_State; S : NFA_State) is
+ begin
+ Set_State_User_Link (S, Head);
+ Head := S;
+ end Push;
+
+ procedure Pop (Head : in out NFA_State; S : out NFA_State) is
+ begin
+ S := Head;
+ Head := Get_State_User_Link (S);
+ end Pop;
+
+ procedure Remove_Unreachable_States (N : NFA)
+ is
+ Head : NFA_State;
+ Start, Final : NFA_State;
+ E : NFA_Edge;
+ S, N_S : NFA_State;
+ begin
+ -- Remove unreachable states, ie states that can't be reached from
+ -- start state.
+ Start := Get_Start_State (N);
+ Final := Get_Final_State (N);
+
+ Head := No_State;
+
+ -- The start state is reachable.
+ Push (Head, Start);
+ Set_State_Flag (Start, True);
+
+ -- Follow edges and mark reachable states.
+ while Head /= No_State loop
+ Pop (Head, S);
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ S := Get_Edge_Dest (E);
+ if not Get_State_Flag (S) then
+ Push (Head, S);
+ Set_State_Flag (S, True);
+ end if;
+ E := Get_Next_Src_Edge (E);
+ end loop;
+ end loop;
+
+ -- Remove unreachable states.
+ S := Get_First_State (N);
+ while S /= No_State loop
+ N_S := Get_Next_State (S);
+ if Get_State_Flag (S) then
+ -- Clean-up.
+ Set_State_Flag (S, False);
+ elsif S = Final then
+ -- Do not remove final state!
+ -- FIXME: deconnect state?
+ null;
+ else
+ Remove_State (N, S);
+ end if;
+ S := N_S;
+ end loop;
+
+ -- Remove no-where states, ie states that can't reach the final state.
+ Head := No_State;
+
+ -- The final state can reach the final state.
+ Push (Head, Final);
+ Set_State_Flag (Final, True);
+
+ -- Follow edges and mark reachable states.
+ while Head /= No_State loop
+ Pop (Head, S);
+ E := Get_First_Dest_Edge (S);
+ while E /= No_Edge loop
+ S := Get_Edge_Src (E);
+ if not Get_State_Flag (S) then
+ Push (Head, S);
+ Set_State_Flag (S, True);
+ end if;
+ E := Get_Next_Dest_Edge (E);
+ end loop;
+ end loop;
+
+ -- Remove unreachable states.
+ S := Get_First_State (N);
+ while S /= No_State loop
+ N_S := Get_Next_State (S);
+ if Get_State_Flag (S) then
+ -- Clean-up.
+ Set_State_Flag (S, False);
+ elsif S = Start then
+ -- Do not remove start state!
+ -- FIXME: deconnect state?
+ null;
+ else
+ Remove_State (N, S);
+ end if;
+ S := N_S;
+ end loop;
+ end Remove_Unreachable_States;
+
+ procedure Remove_Simple_Prefix (N : NFA)
+ is
+ Start : NFA_State;
+ D : NFA_State;
+ T_Start, T_D, Next_T_D : NFA_Edge;
+ T_Expr : Node;
+ Clean : Boolean := False;
+ begin
+ Start := Get_Start_State (N);
+
+ -- Iterate on edges from the start state.
+ T_Start := Get_First_Src_Edge (Start);
+ while T_Start /= No_Edge loop
+ -- Edge destination.
+ D := Get_Edge_Dest (T_Start);
+ T_Expr := Get_Edge_Expr (T_Start);
+
+ -- Iterate on destination incoming edges.
+ T_D := Get_First_Dest_Edge (D);
+ while T_D /= No_Edge loop
+ Next_T_D := Get_Next_Dest_Edge (T_D);
+ -- Remove parallel edge.
+ if T_D /= T_Start
+ and then Get_Edge_Expr (T_D) = T_Expr
+ then
+ Remove_Edge (T_D);
+ Clean := True;
+ end if;
+ T_D := Next_T_D;
+ end loop;
+ T_Start := Get_Next_Src_Edge (T_Start);
+ end loop;
+ if Clean then
+ Remove_Unreachable_States (N);
+ end if;
+ end Remove_Simple_Prefix;
+
+ -- Return TRUE iff the outgoing or incoming edges of L and R are the same.
+ -- Outgoing edges must be sorted.
+ generic
+ with function Get_First_Edge (S : NFA_State) return NFA_Edge;
+ with function Get_Next_Edge (E : NFA_Edge) return NFA_Edge;
+ with function Get_Edge_State_Reverse (E : NFA_Edge) return NFA_State;
+ function Are_States_Identical_Gen (L, R : NFA_State) return Boolean;
+
+ function Are_States_Identical_Gen (L, R : NFA_State) return Boolean
+ is
+ L_E, R_E : NFA_Edge;
+ L_S, R_S : NFA_State;
+ begin
+ L_E := Get_First_Edge (L);
+ R_E := Get_First_Edge (R);
+ loop
+ if L_E = No_Edge and then R_E = No_Edge then
+ -- End of chain for both L and R -> identical states.
+ return True;
+ elsif L_E = No_Edge or R_E = No_Edge then
+ -- End of chain for either L or R -> non identical states.
+ return False;
+ elsif Get_Edge_Expr (L_E) /= Get_Edge_Expr (R_E) then
+ -- Different edge (different expressions).
+ return False;
+ end if;
+ L_S := Get_Edge_State_Reverse (L_E);
+ R_S := Get_Edge_State_Reverse (R_E);
+ if L_S /= R_S and then (L_S /= L or else R_S /= R) then
+ -- Predecessors are differents and not loop.
+ return False;
+ end if;
+ L_E := Get_Next_Edge (L_E);
+ R_E := Get_Next_Edge (R_E);
+ end loop;
+ end Are_States_Identical_Gen;
+
+ generic
+ with procedure Sort_Edges (N : NFA);
+ with procedure Sort_Edges_Reverse (S : NFA_State);
+ with function Get_First_Edge (S : NFA_State) return NFA_Edge;
+ with function Get_Next_Edge (E : NFA_Edge) return NFA_Edge;
+ with function Get_First_Edge_Reverse (S : NFA_State) return NFA_Edge;
+ with function Get_Next_Edge_Reverse (E : NFA_Edge) return NFA_Edge;
+ with function Get_Edge_State (E : NFA_Edge) return NFA_State;
+ with function Get_Edge_State_Reverse (E : NFA_Edge) return NFA_State;
+ with procedure Merge_State_Reverse (N : NFA;
+ S : NFA_State; S1 : NFA_State);
+ procedure Merge_Identical_States_Gen (N : NFA);
+
+ procedure Merge_Identical_States_Gen (N : NFA)
+ is
+ function Are_States_Identical is new Are_States_Identical_Gen
+ (Get_First_Edge => Get_First_Edge,
+ Get_Next_Edge => Get_Next_Edge,
+ Get_Edge_State_Reverse => Get_Edge_State_Reverse);
+
+ S : NFA_State;
+ E : NFA_Edge;
+ E_State, Next_E_State : NFA_State;
+ Next_E, Next_Next_E : NFA_Edge;
+ begin
+ Sort_Edges (N);
+
+ -- Iterate on states.
+ S := Get_First_State (N);
+ while S /= No_State loop
+ Sort_Edges_Reverse (S);
+
+ -- Iterate on incoming edges.
+ E := Get_First_Edge_Reverse (S);
+ while E /= No_Edge loop
+ E_State := Get_Edge_State (E);
+
+ -- Try to merge E with its successors.
+ Next_E := Get_Next_Edge_Reverse (E);
+ while Next_E /= No_Edge
+ and then Get_Edge_Expr (E) = Get_Edge_Expr (Next_E)
+ loop
+ Next_E_State := Get_Edge_State (Next_E);
+ Next_Next_E := Get_Next_Edge_Reverse (Next_E);
+ if Next_E_State = E_State then
+ -- Identical edge: remove the duplicate.
+ Remove_Edge (Next_E);
+ elsif Are_States_Identical (E_State, Next_E_State) then
+ Merge_State_Reverse (N, E_State, Next_E_State);
+ end if;
+ Next_E := Next_Next_E;
+ end loop;
+
+ E := Get_Next_Edge_Reverse (E);
+ end loop;
+
+ S := Get_Next_State (S);
+ end loop;
+ end Merge_Identical_States_Gen;
+
+ procedure Merge_Identical_States_Src is new Merge_Identical_States_Gen
+ (Sort_Edges => Sort_Src_Edges,
+ Sort_Edges_Reverse => Sort_Dest_Edges,
+ Get_First_Edge => Get_First_Src_Edge,
+ Get_Next_Edge => Get_Next_Src_Edge,
+ Get_First_Edge_Reverse => Get_First_Dest_Edge,
+ Get_Next_Edge_Reverse => Get_Next_Dest_Edge,
+ Get_Edge_State => Get_Edge_Src,
+ Get_Edge_State_Reverse => Get_Edge_Dest,
+ Merge_State_Reverse => Merge_State_Dest);
+
+ procedure Merge_Identical_States_Dest is new Merge_Identical_States_Gen
+ (Sort_Edges => Sort_Dest_Edges,
+ Sort_Edges_Reverse => Sort_Src_Edges,
+ Get_First_Edge => Get_First_Dest_Edge,
+ Get_Next_Edge => Get_Next_Dest_Edge,
+ Get_First_Edge_Reverse => Get_First_Src_Edge,
+ Get_Next_Edge_Reverse => Get_Next_Src_Edge,
+ Get_Edge_State => Get_Edge_Dest,
+ Get_Edge_State_Reverse => Get_Edge_Src,
+ Merge_State_Reverse => Merge_State_Src);
+
+ procedure Merge_Identical_States (N : NFA) is
+ begin
+ Merge_Identical_States_Src (N);
+ Merge_Identical_States_Dest (N);
+ end Merge_Identical_States;
+
+ procedure Merge_Edges (N : NFA)
+ is
+ use PSL.CSE;
+ Nbr_States : Natural;
+ begin
+ Labelize_States (N, Nbr_States);
+ declare
+ Last_State : constant Int32 := Int32 (Nbr_States) - 1;
+ type Edge_Array is array (0 .. Last_State) of NFA_Edge;
+ Edges : Edge_Array;
+ S, D : NFA_State;
+ L_D : Int32;
+ E, Next_E : NFA_Edge;
+ begin
+ -- Iterate on states.
+ S := Get_First_State (N);
+ while S /= No_State loop
+
+ Edges := (others => No_Edge);
+ E := Get_First_Src_Edge (S);
+ while E /= No_Edge loop
+ Next_E := Get_Next_Src_Edge (E);
+ D := Get_Edge_Dest (E);
+ L_D := Get_State_Label (D);
+ if Edges (L_D) /= No_Edge then
+ Set_Edge_Expr
+ (Edges (L_D),
+ Build_Bool_Or (Get_Edge_Expr (Edges (L_D)),
+ Get_Edge_Expr (E)));
+ -- FIXME: reduce expression.
+ Remove_Edge (E);
+ else
+ Edges (L_D) := E;
+ end if;
+ E := Next_E;
+ end loop;
+
+ S := Get_Next_State (S);
+ end loop;
+ end;
+ end Merge_Edges;
+
+ procedure Remove_Identical_Src_Edges (S : NFA_State)
+ is
+ Next_E, E : NFA_Edge;
+ begin
+ Sort_Src_Edges (S);
+ E := Get_First_Src_Edge (S);
+ if E = No_Edge then
+ return;
+ end if;
+ loop
+ Next_E := Get_Next_Src_Edge (E);
+ exit when Next_E = No_Edge;
+ if Get_Edge_Dest (E) = Get_Edge_Dest (Next_E)
+ and then Get_Edge_Expr (E) = Get_Edge_Expr (Next_E)
+ then
+ Remove_Edge (Next_E);
+ else
+ E := Next_E;
+ end if;
+ end loop;
+ end Remove_Identical_Src_Edges;
+
+ procedure Remove_Identical_Dest_Edges (S : NFA_State)
+ is
+ Next_E, E : NFA_Edge;
+ begin
+ Sort_Dest_Edges (S);
+ E := Get_First_Dest_Edge (S);
+ if E = No_Edge then
+ return;
+ end if;
+ loop
+ Next_E := Get_Next_Dest_Edge (E);
+ exit when Next_E = No_Edge;
+ if Get_Edge_Src (E) = Get_Edge_Src (Next_E)
+ and then Get_Edge_Expr (E) = Get_Edge_Expr (Next_E)
+ then
+ Remove_Edge (Next_E);
+ else
+ E := Next_E;
+ end if;
+ end loop;
+ end Remove_Identical_Dest_Edges;
+
+ procedure Find_Partitions (N : NFA; Nbr_States : Natural)
+ is
+ Last_State : constant NFA_State := NFA_State (Nbr_States) - 1;
+ type Part_Offset is new Int32 range -1 .. Nat32 (Nbr_States - 1);
+ type Part_Id is new Part_Offset range 0 .. Part_Offset'Last;
+
+ -- State to partition id.
+ State_Part : array (0 .. Last_State) of Part_Id;
+ pragma Unreferenced (State_Part);
+
+ -- Last partition index.
+ Last_Part : Part_Id;
+
+ -- Partitions content.
+
+ -- To get the states in a partition P, first get the offset OFF
+ -- (from Offsets) of P. States are in Parts (OFF ...). The
+ -- number of states is not known, but they all belong to P
+ -- (check with STATE_PART).
+ Parts : array (Part_Offset) of NFA_State;
+ type Offset_Array is array (Part_Id) of Part_Offset;
+ Start_Offsets : Offset_Array;
+ Last_Offsets : Offset_Array;
+
+ S, Final_State : NFA_State;
+ First_S : NFA_State;
+ Off, Last_Off : Part_Offset;
+
+ Stable, Stable1 : Boolean;
+
+ function Is_Equivalent (L, R : NFA_State) return Boolean is
+ begin
+ raise Program_Error;
+ return False;
+ end Is_Equivalent;
+ begin
+ -- Return now for trivial cases (0 or 1 state).
+ if Nbr_States < 2 then
+ return;
+ end if;
+
+ -- Partition 1 contains the final state.
+ -- Partition 0 contains the other states.
+ Final_State := Get_Final_State (N);
+ Last_Part := 1;
+ State_Part := (others => 0);
+ State_Part (Final_State) := 1;
+ S := Get_First_State (N);
+ Off := -1;
+ while S /= No_State loop
+ if S /= Last_State then
+ Off := Off + 1;
+ Parts (Off) := S;
+ end if;
+ S := Get_Next_State (S);
+ end loop;
+ Start_Offsets (0) := 0;
+ Last_Offsets (0) := Off;
+ Start_Offsets (1) := Off + 1;
+ Last_Offsets (1) := Off + 1;
+ Parts (Off + 1) := Final_State;
+
+ -- Now the hard work.
+ loop
+ Stable := True;
+ -- For every partition
+ for P in 0 .. Last_Part loop
+ Off := Start_Offsets (P);
+ First_S := Parts (Off);
+ Off := Off + 1;
+
+ -- For every S != First_S in P.
+ Last_Off := Last_Offsets (P);
+ Stable1 := True;
+ while Off <= Last_Off loop
+ S := Parts (Off);
+
+ if not Is_Equivalent (First_S, S) then
+ -- Swap S with the last element of the partition.
+ Parts (Off) := Parts (Last_Off);
+ Parts (Last_Off) := S;
+ -- Reduce partition size.
+ Last_Off := Last_Off - 1;
+ Last_Offsets (P) := Last_Off;
+
+ if Stable1 then
+ -- Create a new partition.
+ Last_Part := Last_Part + 1;
+ Last_Offsets (Last_Part) := Last_Off + 1;
+ Stable1 := False;
+ end if;
+ -- Put S in the new partition.
+ Start_Offsets (Last_Part) := Last_Off + 1;
+ State_Part (S) := Last_Part;
+ Stable := False;
+
+ -- And continue with the swapped state.
+ else
+ Off := Off + 1;
+ end if;
+ end loop;
+ end loop;
+ exit when Stable;
+ end loop;
+ end Find_Partitions;
+ pragma Unreferenced (Find_Partitions);
+end PSL.Optimize;