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']
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']
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']