Esempio n. 1
0
    def optimize(self, options):
        if len(self.basicblocks) == 0:
            print 'Tape %s is empty' % self.name
            return

        if self.if_states:
            raise CompilerError('Unclosed if/else blocks')

        print 'Processing tape', self.name, 'with %d blocks' % len(
            self.basicblocks)

        for block in self.basicblocks:
            al.determine_scope(block, options)

        # merge open instructions
        # need to do this if there are several blocks
        if (options.merge_opens
                and self.merge_opens) or options.dead_code_elimination:
            for i, block in enumerate(self.basicblocks):
                if len(block.instructions) > 0:
                    print 'Processing basic block %s, %d/%d, %d instructions' % \
                        (block.name, i, len(self.basicblocks), \
                         len(block.instructions))
                # the next call is necessary for allocation later even without merging
                merger = al.Merger(block, options, \
                                   tuple(self.program.to_merge))
                if options.dead_code_elimination:
                    if len(block.instructions) > 10000:
                        print 'Eliminate dead code...'
                    merger.eliminate_dead_code()
                if options.merge_opens and self.merge_opens:
                    if len(block.instructions) == 0:
                        block.used_from_scope = set()
                        block.defined_registers = set()
                        continue
                    if len(block.instructions) > 10000:
                        print 'Merging instructions...'
                    numrounds = merger.longest_paths_merge()
                    if numrounds > 0:
                        print 'Program requires %d rounds of communication' % numrounds
                    if merger.counter:
                        print 'Block requires', \
                            ', '.join('%d %s' % (y, x.__name__) \
                                     for x, y in merger.counter.items())
                # free memory
                merger = None
                if options.dead_code_elimination:
                    block.instructions = filter(lambda x: x is not None,
                                                block.instructions)
        if not (options.merge_opens and self.merge_opens):
            print 'Not merging instructions in tape %s' % self.name

        # add jumps
        offset = 0
        for block in self.basicblocks:
            if block.exit_condition is not None:
                block.add_jump()
            block.offset = offset
            offset += len(block.instructions)
        for block in self.basicblocks:
            if block.exit_block is not None:
                block.adjust_jump()
            if block.previous_block is not None:
                block.adjust_return()

        # now remove any empty blocks (must be done after setting jumps)
        self.basicblocks = filter(lambda x: len(x.instructions) != 0,
                                  self.basicblocks)

        # allocate registers
        reg_counts = self.count_regs()
        if not options.noreallocate:
            print 'Tape register usage:', dict(reg_counts)
            print 'modp: %d clear, %d secret' % (
                reg_counts[RegType.ClearModp], reg_counts[RegType.SecretModp])
            print 'GF2N: %d clear, %d secret' % (
                reg_counts[RegType.ClearGF2N], reg_counts[RegType.SecretGF2N])
            print 'Re-allocating...'
            allocator = al.StraightlineAllocator(REG_MAX)

            def alloc_loop(block):
                for reg in block.used_from_scope:
                    allocator.alloc_reg(reg, block.alloc_pool)
                for child in block.children:
                    if child.instructions:
                        alloc_loop(child)

            for i, block in enumerate(reversed(self.basicblocks)):
                if len(block.instructions) > 10000:
                    print 'Allocating %s, %d/%d' % \
                        (block.name, i, len(self.basicblocks))
                if block.exit_condition is not None:
                    jump = block.exit_condition.get_relative_jump()
                    if isinstance(jump, (int,long)) and jump < 0 and \
                            block.exit_block.scope is not None:
                        alloc_loop(block.exit_block.scope)
                allocator.process(block.instructions, block.alloc_pool)

        # offline data requirements
        print 'Compile offline data requirements...'
        self.req_num = self.req_tree.aggregate()
        print 'Tape requires', self.req_num
        for req, num in self.req_num.items():
            if num == float('inf'):
                num = -1
            if req[1] in data_types:
                self.basicblocks[-1].instructions.append(
                    Compiler.instructions.use(field_types[req[0]], \
                                                  data_types[req[1]], num, \
                                                  add_to_prog=False))
            elif req[1] == 'input':
                self.basicblocks[-1].instructions.append(
                    Compiler.instructions.use_inp(field_types[req[0]], \
                                                      req[2], num, \
                                                      add_to_prog=False))
            elif req[0] == 'modp':
                self.basicblocks[-1].instructions.append(
                    Compiler.instructions.use_prep(req[1], num, \
                                                   add_to_prog=False))
            elif req[0] == 'gf2n':
                self.basicblocks[-1].instructions.append(
                    Compiler.instructions.guse_prep(req[1], num, \
                                                    add_to_prog=False))

        if not self.is_empty():
            # bit length requirement
            for x in ('p', '2'):
                if self.req_bit_length[x]:
                    bl = self.req_bit_length[x]
                    if self.program.options.ring:
                        bl = -int(self.program.options.ring)
                    self.basicblocks[-1].instructions.append(
                        Compiler.instructions.reqbl(bl, add_to_prog=False))
            print 'Tape requires prime bit length', self.req_bit_length['p']
            print 'Tape requires galois bit length', self.req_bit_length['2']
Esempio n. 2
0
    def optimize(self, options):
        if len(self.basicblocks) == 0:
            print 'Tape %s is empty' % self.name
            return

        if self.if_states:
            raise CompilerError('Unclosed if/else blocks')

        print 'Processing tape', self.name, 'with %d blocks' % len(
            self.basicblocks)

        for block in self.basicblocks:
            al.determine_scope(block, options)

        # merge open instructions
        # need to do this if there are several blocks
        if (options.merge_opens
                and self.merge_opens) or options.dead_code_elimination:
            for i, block in enumerate(self.basicblocks):
                if len(block.instructions) > 0:
                    print 'Processing basic block %s, %d/%d, %d instructions ' % (
                        block.name, i, len(
                            self.basicblocks), len(block.instructions))
                    sys.stdout.flush()
                # the next call is necessary for allocation later even without merging
                merger = al.Merger(block, options)
                if options.dead_code_elimination:
                    if len(block.instructions) > 10000:
                        print 'Eliminate dead code...'
                        sys.stdout.flush()
                    merger.eliminate_dead_code()
                if options.merge_opens and self.merge_opens:
                    if len(block.instructions) == 0:
                        block.used_from_scope = set()
                        block.defined_registers = set()
                        continue
                    if len(block.instructions) > 10000:
                        print 'Merging open instructions...'
                        sys.stdout.flush()
                    numrounds = merger.longest_paths_merge()
                    if numrounds > 0:
                        print 'Program requires %d rounds of communication' % numrounds
                        sys.stdout.flush()
                    numinv = sum(
                        len(i.args) for i in block.instructions if isinstance(
                            i, Compiler.instructions.startopen_class))
                    if numinv > 0:
                        print 'Program requires %d invocations' % numinv
                        sys.stdout.flush()
                if options.dead_code_elimination:
                    block.instructions = filter(lambda x: x is not None,
                                                block.instructions)
        if not (options.merge_opens and self.merge_opens):
            print 'Not merging open instructions in tape %s' % self.name
            sys.stdout.flush()

        # add jumps
        offset = 0
        for block in self.basicblocks:
            if block.exit_condition is not None:
                block.add_jump()
            block.offset = offset
            offset += len(block.instructions)
        for block in self.basicblocks:
            if block.exit_block is not None:
                block.adjust_jump()

        # now remove any empty blocks (must be done after setting jumps)
        self.basicblocks = filter(lambda x: len(x.instructions) != 0,
                                  self.basicblocks)

        # allocate registers
        reg_counts = self.count_regs()
        if not options.noreallocate:
            print 'Tape register usage:', reg_counts
            print 'modp: %d clear, %d secret' % (
                reg_counts[RegType.ClearModp], reg_counts[RegType.SecretModp])
            print 'Re-allocating...'
            sys.stdout.flush()
            allocator = al.StraightlineAllocator(REG_MAX)

            def alloc_loop(block):
                for reg in block.used_from_scope:
                    allocator.alloc_reg(reg, block.alloc_pool)
                for child in block.children:
                    if child.instructions:
                        alloc_loop(child)

            for i, block in enumerate(reversed(self.basicblocks)):
                if len(block.instructions) > 10000:
                    print 'Allocating %s, %d/%d' % \
                        (block.name, i, len(self.basicblocks))
                    sys.stdout.flush()
                if block.exit_condition is not None:
                    jump = block.exit_condition.get_relative_jump()
                    if jump != -1 and  \
                            isinstance(jump, (int,long)) and \
                            jump < 0 and \
                            block.exit_block.scope is not None:
                        alloc_loop(block.exit_block.scope)
                allocator.process(block.instructions, block.alloc_pool)

        # offline data requirements
        print 'Compile offline data requirements...'
        self.req_num = self.req_tree.aggregate()
        print 'Tape requires', self.req_num
        for req, num in self.req_num.items():
            if num == float('inf'):
                num = -1

        if not self.is_empty():
            # bit length requirement
            for x in ('p', '2'):
                if self.req_bit_length['p']:
                    self.basicblocks[-1].instructions.append(
                        Compiler.instructions.reqbl(self.req_bit_length['p'],
                                                    add_to_prog=False))
            print 'Tape requires prime bit length', self.req_bit_length['p']