| Index: src/trusted/validator_mips/dgen/dgen_opt.py | 
| diff --git a/src/trusted/validator_mips/dgen/dgen_opt.py b/src/trusted/validator_mips/dgen/dgen_opt.py | 
| new file mode 100755 | 
| index 0000000000000000000000000000000000000000..7efa35b09a21958d1a04feb532efbb00b1ac0aa1 | 
| --- /dev/null | 
| +++ b/src/trusted/validator_mips/dgen/dgen_opt.py | 
| @@ -0,0 +1,76 @@ | 
| +#!/usr/bin/python | 
| +# | 
| +# Copyright 2012 The Native Client Authors.  All rights reserved. | 
| +# Use of this source code is governed by a BSD-style license that can | 
| +# be found in the LICENSE file. | 
| +# Copyright 2012, Google Inc. | 
| +# | 
| + | 
| +""" | 
| +Table minimization algorithm. | 
| +""" | 
| + | 
| +def optimize_rows(rows): | 
| +    """Breaks rows up into batches, and attempts to minimize each batch, | 
| +    using _optimize_rows_for_single_action. | 
| +    """ | 
| +    rows_by_action = dict() | 
| +    for row in rows: | 
| +        if (row.action, row.arch) in rows_by_action: | 
| +            rows_by_action[(row.action, row.arch)].append(row) | 
| +        else: | 
| +            rows_by_action[(row.action, row.arch)] = [row] | 
| + | 
| +    optimized_rows = [] | 
| +    for row_group in rows_by_action.itervalues(): | 
| +        optimized_rows.extend(_optimize_rows_for_single_action(row_group)) | 
| + | 
| +    _remove_unused_columns(optimized_rows) | 
| +    return optimized_rows | 
| + | 
| +def _optimize_rows_for_single_action(rows): | 
| +    """Performs basic automatic minimization on the given rows. | 
| + | 
| +    Repeatedly selects a pair of rows to merge.  Recurses until no suitable pair | 
| +    can be found.  It's not real smart, and is O(n^2). | 
| + | 
| +    A pair of rows is compatible if all columns are equal, or if exactly one | 
| +    row differs but is_strictly_compatible. | 
| +    """ | 
| +    for (i, j) in each_index_pair(rows): | 
| +        row_i, row_j = rows[i], rows[j] | 
| + | 
| +        if row_i.can_merge(row_j): | 
| +            new_rows = list(rows) | 
| +            del new_rows[j] | 
| +            del new_rows[i] | 
| +            new_rows.append(row_i + row_j) | 
| +            return _optimize_rows_for_single_action(new_rows) | 
| + | 
| +    # No changes made: | 
| +    return rows | 
| + | 
| +def _remove_unused_columns(rows): | 
| +    num_cols = len(rows[0].patterns) | 
| +    used = [False] * num_cols | 
| + | 
| +    for r in rows: | 
| +        for i in range(0, num_cols): | 
| +            if r.patterns[i].mask != 0: | 
| +                used[i] = True | 
| + | 
| +    if not True in used: | 
| +        # Always preserve at least one column | 
| +        used[0] = True | 
| + | 
| +    for col in range(num_cols - 1, 0 - 1, -1): | 
| +        for r in rows: | 
| +            if not used[col]: | 
| +                del r.patterns[col] | 
| + | 
| + | 
| +def each_index_pair(sequence): | 
| +    """Utility function: Generates each unique index pair in sequence.""" | 
| +    for i in range(0, len(sequence)): | 
| +        for j in range(i + 1, len(sequence)): | 
| +            yield (i, j) | 
|  |