Skip to content

Commit 02e70bc

Browse files
committed
LVS: make compilation reproducible
1 parent 80aeeec commit 02e70bc

1 file changed

Lines changed: 21 additions & 8 deletions

File tree

src/ndn/app_support/light_versec/compiler.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)