@@ -61,6 +61,8 @@ def top_order(nodes: set[T], graph: dict[T, list[T]]) -> list[T]:
6161 if not cur_round :
6262 remaining_nodes = nodes - set (ret )
6363 raise SemanticError (f'Loop detected for { remaining_nodes } ' )
64+ # Sort for stable build. Allowed since T can only be `str` or `int`
65+ cur_round .sort ()
6466 for n in cur_round :
6567 for n2 in graph [n ]:
6668 in_degs [n2 ] -= 1
@@ -219,7 +221,7 @@ def _gen_pattern_numbers(self):
219221 def _replicate_rules (self ):
220222 self .rep_rules = {}
221223 for rule in self .lvs .rules :
222- sign_cons = [s .id for s in rule .sign_cons ]
224+ sign_cons = sorted ( [s .id for s in rule .sign_cons ])
223225 if not rule .comp_cons :
224226 cur_chains = [self .RuleChain (id = rule .id .id , name = [], cons_set = [], sign_cons = sign_cons )]
225227 else :
@@ -230,6 +232,7 @@ def _replicate_rules(self):
230232 for chain in cur_chains :
231233 chain .name .append (comp )
232234 else :
235+ # Note: this repeats temporary tag numbers, which needs to be fixed before emit.
233236 new_chains = [self .RuleChain (id = rule .id .id ,
234237 name = chain .name + ref_chain .name ,
235238 cons_set = chain .cons_set + ref_chain .cons_set ,
@@ -253,7 +256,8 @@ def _generate_node(self, depth: int, context: list[RuleChain], parent: Optional[
253256 for rc in context :
254257 if depth == len (rc .name ):
255258 node .rule_name .append (rc .id )
256- # Here we violate the type. Will fix it later
259+ # Here we violate the type (expected list[int], actual list[str]).
260+ # Will fix it later in `_fix_signing_references`
257261 node .sign_cons .extend (rc .sign_cons )
258262 if rc .id not in self .rule_node_ids :
259263 self .rule_node_ids [rc .id ] = [node .id ]
@@ -266,7 +270,8 @@ def _generate_node(self, depth: int, context: list[RuleChain], parent: Optional[
266270 v_move = set (rc .name [depth ].c for rc in context
267271 if isinstance (rc .name [depth ], psr .ComponentValue ))
268272 node .v_edges = []
269- for v in v_move :
273+ v_move_list = sorted (list (v_move ))
274+ for v in v_move_list :
270275 new_context = [rc for rc in context
271276 if isinstance (rc .name [depth ], psr .ComponentValue )
272277 and rc .name [depth ].c == v ]
@@ -277,7 +282,7 @@ def _generate_node(self, depth: int, context: list[RuleChain], parent: Optional[
277282 # Pattern movements
278283 p_moves = [rc .pattern_movement (depth , previous_tags ) + (rc ,) for rc in context
279284 if isinstance (rc .name [depth ], psr .Pattern )]
280- p_move_strs = set (pm [2 ] for pm in p_moves )
285+ p_move_strs = sorted ( list ( set (pm [2 ] for pm in p_moves )) )
281286 for pm_str in p_move_strs :
282287 new_context = [pm [3 ] for pm in p_moves if pm [2 ] == pm_str ]
283288 assert len (new_context ) > 0
@@ -294,6 +299,9 @@ def _generate_node(self, depth: int, context: list[RuleChain], parent: Optional[
294299 return node .id
295300
296301 def _fix_signing_references (self ):
302+ """
303+ Convert signing constraints from string node-ID to integer node-ID
304+ """
297305 for node in self .node_pool :
298306 sign_cons = node .sign_cons
299307 if not sign_cons :
@@ -303,28 +311,33 @@ def _fix_signing_references(self):
303311 if rid not in self .rule_node_ids :
304312 raise SemanticError (f'Signed by a non-existing key { rid } ' )
305313 new_sign_cons .extend (self .rule_node_ids [rid ])
306- node .sign_cons = new_sign_cons
314+ node .sign_cons = sorted ( new_sign_cons )
307315
308316 def compile (self ) -> bny .LvsModel :
309317 self ._sort_rule_references ()
310318 self ._gen_pattern_numbers ()
311319 self ._replicate_rules ()
312320 self .node_pool = []
313321 self .rule_node_ids = {}
314- rule_chains = sum (self .rep_rules .values (), [])
322+ # Sort replicated rules for compilation stability
323+ sorted_rep_rules = list (self .rep_rules .items ())
324+ sorted_rep_rules .sort (key = lambda tup : tup [0 ])
325+ rule_chains = sum ([v for (k , v ) in sorted_rep_rules ], start = [])
315326 start_node = self ._generate_node (0 , rule_chains , None , set ())
316327 self ._fix_signing_references ()
317328 ret = bny .LvsModel ()
318329 ret .version = bny .VERSION
319330 ret .start_id = start_node
320331 ret .named_pattern_cnt = len (self .named_pats )
321332 ret .nodes = self .node_pool
322- ret . symbols = []
333+ symbols = []
323334 for pname , number in self .named_pats .items ():
324335 symbol = bny .TagSymbol ()
325336 symbol .ident = pname
326337 symbol .tag = int (number )
327- ret .symbols .append (symbol )
338+ symbols .append (symbol )
339+ symbols .sort (key = lambda sym : sym .tag )
340+ ret .symbols = symbols
328341 return ret
329342
330343
0 commit comments