class DataPermuteTrans(Transformation): __slots__=('reordering_name','_data_reordering','data_arrays','iter_sub_space_relation','target_data_arrays','erg_func_name') _relation_fields=('iter_sub_space_relation',) _data_arrays_fields=('data_arrays','target_data_arrays') def __init__(self,name,reordering_name,data_arrays,iter_sub_space_relation,target_data_arrays,erg_func_name): Transformation.__init__(self,name) self.reordering_name=reordering_name self.data_arrays=data_arrays self.iter_sub_space_relation=iter_sub_space_relation self.target_data_arrays=target_data_arrays self.erg_func_name=erg_func_name #Calculate the data reordering relation self._data_reordering=Relation('{[%s_in]->[%s_out]: %s_out=%s(%s_in)}'%(5*(self.reordering_name,))) #Make sure the target data arrays all have the same bounds #We do this by unioning all bounds and simply checking that there is a single conjunction in the disjunction target_bounds=[data_array.bounds for data_array in self.target_data_arrays] unioned_bounds=reduce(lambda da1,da2: da1.union(da2),target_bounds) if len(unioned_bounds)!=1: raise ValueError('All target data arrays must have the same bounds') def __repr__(self): return 'DataPermuteTrans(%s,%s,%s,%s,%s)'%(self.data_reordering,self.data_arrays,self.iter_sub_space_relation,self.target_data_arrays,self.erg_func_name) def __str__(self): return self._get_string(0) def _get_string(self,indent): if indent>0: indent+=1 spaces=' '*indent inputs_string=StringIO() if len(self.inputs)>0: for input in self.inputs: print >>inputs_string,input._get_string(indent+5) inputs_string=inputs_string.getvalue()[:-1] if len(inputs_string)>0: inputs_string='\n'+inputs_string outputs_string=StringIO() if len(self.outputs)>0: for output in self.outputs: print >>outputs_string,output._get_string(indent+5) outputs_string=outputs_string.getvalue()[:-1] if len(outputs_string)>0: outputs_string='\n'+outputs_string data_arrays_string=StringIO() if len(self.data_arrays)>0: for data_array in self.data_arrays: print >>data_arrays_string,data_array._get_string(indent+13) data_arrays_string=data_arrays_string.getvalue()[:-1] if len(data_arrays_string)>0: data_arrays_string='\n'+data_arrays_string target_data_arrays_string=StringIO() if len(self.target_data_arrays)>0: for data_array in self.target_data_arrays: print >>target_data_arrays_string,data_array._get_string(indent+13) target_data_arrays_string=target_data_arrays_string.getvalue()[:-1] if len(target_data_arrays_string)>0: target_data_arrays_string='\n'+target_data_arrays_string return '''%sDataPermuteTrans: %s|-name: %s %s|-inputs: %s %s|-outputs: %s %s|-reordering_name: %s %s|-_data_reordering: %s %s|-data_arrays: %s %s|-iter_sub_space_relation: %s %s|-target_data_arrays: %s %s|-erg_func_name: %s'''%(spaces,spaces,self.name, spaces,inputs_string, spaces,outputs_string, spaces,self.reordering_name, spaces,self._data_reordering, spaces,data_arrays_string, spaces,self.iter_sub_space_relation, spaces,target_data_arrays_string, spaces,self.erg_func_name) #Calculate a specification for the explicit relation that is input to # the data reordering algorithm. #This input is a relation from the iteration sub space to the # the target data space. def calc_input(self,mapir): #Iteration Sub Space Relation issr=self.iter_sub_space_relation #Calculate the full iteration space to data space relation #Collect all iter_to_data relations in all access relations access_relations=[ar.iter_to_data for stmt in mapir.get_statements() for ar in stmt.get_access_relations() if set()!=set([ar.data_array]).intersection(set(self.target_data_arrays))] #Union all the relations that were collected into a single relation iter_to_data=reduce(lambda form1,form2: form1.union(form2),access_relations) #Compose the unioned access relation with the iteration subspace # relation to remove conjunctions we are not interested in iter_to_data=self.iter_sub_space_relation.compose(iter_to_data.inverse()).inverse() #Create the ERSpec for the relation that is input to the reordering self.inputs.append(ERSpec( name='%s_input'%(self.name), input_bounds=mapir.full_iter_space.apply(self.iter_sub_space_relation), output_bounds=self.target_data_arrays[0].bounds.copy(), relation=iter_to_data, is_function=True, er_type='er_u1d')) print 'In DataPermuteTrans, input type %s.is_er_u1d()=%s'%(self.inputs[-1].get_var_name(),self.inputs[-1].is_er_u1d()) #Add the ERSpec to the MapIR mapir.add_er_spec(self.inputs[0]) self.print_progress("Calculated input ERSpec '%s' for transformation '%s'..."%(self.inputs[0].name,self.name)) self.print_detail(self.inputs[0]) #Calculate a specification for the explicit relation that is the # output of this data reordering. #This relation is a permutation of the original data space, permuted # based on the heuristics of the reordering algorithm. def calc_output(self,mapir): #Need to create a static description of the output of the reordering self.outputs.append(ERSpec( name=self.reordering_name, input_bounds=self.target_data_arrays[0].bounds.copy(), output_bounds=self.target_data_arrays[0].bounds.copy(), relation=self._data_reordering.copy(), is_permutation=True)) #Add the ERSpec to the MapIR mapir.add_er_spec(self.outputs[0]) self.print_progress("Calculated output ERSpec '%s' for transformation '%s'..."%(self.outputs[0].name,self.name)) self.print_detail(self.outputs[0]) #Update the MapIR based on this transformation def update_mapir(self,mapir): #Data spaces are not changed #Scattering functions are not changed #Update the access relations of all statements that access # the reordered data array(s) self.print_progress('Updating access relations...') for statement in mapir.get_statements(): for access_relation in statement.get_access_relations(): if access_relation.data_array in self.data_arrays: access_relation.iter_to_data=self._data_reordering.compose(access_relation.iter_to_data) #Update the idg based on this transformation def update_idg(self,mapir): #Add the ERG call node to the IDG erg_call_node=mapir.idg.get_node(IDGCall,calc_erg_call(self.name,self.erg_func_name,self.inputs,self.outputs)) #Collection of reorder call nodes reorder_call_nodes=[] #Add the input ERSpecs to the IDG for input_er_spec in self.inputs: #Get a node for the ERSpec input_er_spec_node=mapir.idg.get_node(IDGERSpec,input_er_spec) #Get a gen node for the ERSpec gen_input_er_spec_node=mapir.idg.get_node(IDGGenERSpec,input_er_spec) #Add dependence of the GenERSpec node to ERSpec node input_er_spec_node.add_dep(gen_input_er_spec_node) #Add dependence of the call to the input erg_call_node.add_dep(input_er_spec_node) #Add reorder call nodes for each data array to be reordered for data_array in self.data_arrays: #Build the list of arguments to the function call #Add the reorder call node for this data array to the IDG reorder_call_node=mapir.idg.get_node(IDGCall,calc_reorder_call(self.name,data_array,self.reordering_name,mapir)) #Add the reorder call node to the collection of reorder call nodes reorder_call_nodes.append(reorder_call_node) #Get the data array node before the reordering before_data_array_node=mapir.idg.get_node(IDGDataArray,VersionedDataArray(data_array)) #Add the dependence of the reorder call on the before data array reorder_call_node.add_dep(before_data_array_node) #Get the data array node after the reordering after_data_array_node=mapir.idg.get_node(IDGDataArray,VersionedDataArray(data_array)) #Add the dependence of the after data array node on the reorder call after_data_array_node.add_dep(reorder_call_node) #Add the output ERSpecs to the IDG for output_er_spec in self.outputs: #Get a node for the ERSpec output_er_spec_node=mapir.idg.get_node(IDGOutputERSpec,output_er_spec) #Add dependence of the output on the call output_er_spec_node.add_dep(erg_call_node) #Add dependences of the reorder calls on the output for reorder_call_node in reorder_call_nodes: reorder_call_node.add_dep(output_er_spec_node)
class IterPermuteTrans(Transformation): __slots__=('reordering_name','iter_sub_space_relation','target_data_arrays','erg_func_name','iter_space_trans','_data_reordering') _relation_fields=('iter_sub_space_relation',) _data_arrays_fields=('target_data_arrays',) def __init__(self,name,reordering_name,iter_sub_space_relation,target_data_arrays,erg_func_name,iter_space_trans): Transformation.__init__(self,name) self.reordering_name=reordering_name self.iter_sub_space_relation=iter_sub_space_relation self.target_data_arrays=target_data_arrays self.erg_func_name=erg_func_name self.iter_space_trans=iter_space_trans #Calculate the data reordering relation self._data_reordering=Relation('{[%s_in]->[%s_out]: %s_out=%s(%s_in)}'%(5*(self.reordering_name,))) #Make sure the target data arrays all have the same bounds #We do this by unioning all bounds and simply checking that there is a single conjunction in the disjunction target_bounds=[data_array.bounds for data_array in self.target_data_arrays] unioned_bounds=reduce(lambda da1,da2: da1.union(da2),target_bounds) if len(unioned_bounds)!=1: raise ValueError('All target data arrays must have the same bounds') def __repr__(self): return 'IterPermuteTrans(%s,%s,%s,%s,%s)'%(self.reordering_name,self.iter_sub_space_relation,self.target_data_arrays,self.erg_func_name,self.iter_space_trans) def __str__(self): return self._get_string(0) def _get_string(self,indent): if indent>0: indent+=1 spaces=' '*indent inputs_string=StringIO() if len(self.inputs)>0: for input in self.inputs: print >>inputs_string,input._get_string(indent+5) inputs_string=inputs_string.getvalue()[:-1] if len(inputs_string)>0: inputs_string='\n'+inputs_string outputs_string=StringIO() if len(self.outputs)>0: for output in self.outputs: print >>outputs_string,output._get_string(indent+5) outputs_string=outputs_string.getvalue()[:-1] if len(outputs_string)>0: outputs_string='\n'+outputs_string target_data_arrays_string=StringIO() if len(self.target_data_arrays)>0: for data_array in self.target_data_arrays: print >>target_data_arrays_string,data_array._get_string(indent+13) target_data_arrays_string=target_data_arrays_string.getvalue()[:-1] if len(target_data_arrays_string)>0: target_data_arrays_string='\n'+target_data_arrays_string return '''%sIterPermuteTrans: %s|-name: %s %s|-reordering_name: %s %s|-iter_sub_space_relation: %s %s|-inputs: %s %s|-outputs: %s %s|-target_data_arrays: %s %s|-erg_func_name: %s %s|-iter_space_trans: %s %s|-_data_reordering: %s'''%(spaces,spaces,self.name, spaces,self.reordering_name, spaces,self.iter_sub_space_relation, spaces,inputs_string, spaces,outputs_string, spaces,target_data_arrays_string, spaces,self.erg_func_name, spaces,self.iter_space_trans, spaces,self._data_reordering) #Calculate a specification for the explicit relation that is input to # the data reordering algorithm. #This input is a relation from the iteration sub space to the # the target data space. #It is a relation of how the the loop to be permuted accesses the # target data arrays. def calc_input(self,mapir): #Iteration Sub Space Relation issr=self.iter_sub_space_relation #Calculate the full iteration space to data space relation #Collect all iter_to_data relations in all access relations self.print_detail("Filtering access relations...") access_relations=[ar.iter_to_data for stmt in mapir.get_statements() for ar in stmt.get_access_relations() if set()!=set([ar.data_array]).intersection(set(self.target_data_arrays))] #Union all the relations that were collected into a single relation self.print_detail("Unioning access relations...") iter_to_data=reduce(lambda form1,form2: form1.union(form2),access_relations) #Compose the unioned access relation with the iteration subspace # relation to remove conjunctions we are not interested in self.print_detail("Calculating final iteration to data relation...") iter_to_data=self.iter_sub_space_relation.compose(iter_to_data.inverse()).inverse() #Create the ERSpec for the relation that is input to the reordering self.inputs.append(ERSpec( name='%s_input'%(self.name), input_bounds=mapir.full_iter_space.apply(self.iter_sub_space_relation), output_bounds=self.target_data_arrays[0].bounds.copy(), relation=iter_to_data)) #Add the ERSpec to the MapIR mapir.add_er_spec(self.inputs[0]) self.print_progress("Calculated input ERSpec '%s' for transformation '%s'..."%(self.inputs[0].name,self.name)) self.print_detail(self.inputs[0]) #Create an ERSpec for the output of the reordering function def calc_output(self,mapir): #Need to create a static description of the output of the reordering self.outputs.append(ERSpec( name=self.reordering_name, input_bounds=mapir.full_iter_space.apply(self.iter_sub_space_relation), output_bounds=mapir.full_iter_space.apply(self.iter_sub_space_relation), relation=self._data_reordering.copy(), is_permutation=True)) #Add the ERSpec to the MapIR mapir.add_er_spec(self.outputs[0]) self.print_progress("Calculated output ERSpec '%s' for transformation '%s'..."%(self.outputs[0].name,self.name)) self.print_detail(self.outputs[0]) #Modify access relations and data deps def update_mapir(self,mapir): #Update the access relations of all statements self.print_progress('Updating access relations...') for statement in mapir.get_statements(): for access_relation in statement.get_access_relations(): self.print_detail("Updating access relation '%s'..."%(access_relation.name)) access_relation.iter_to_data=access_relation.iter_to_data.compose(self.iter_space_trans.inverse()) #Update the data dependences self.print_progress('Updating data dependences for IterPermuteTrans...') for data_dependence in mapir.get_data_dependences(): self.print_detail("Updating data dependence '%s'..."%(data_dependence.name)) data_dependence.dep_rel=self.iter_space_trans.compose(data_dependence.dep_rel.compose(self.iter_space_trans.inverse())) #Add output ER and ERG call node to IDG def update_idg(self,mapir): #Add the ERG call node to the IDG erg_call_node=mapir.idg.get_node(IDGCall,calc_erg_call(self.name,self.erg_func_name,self.inputs,self.outputs)) #Add the input ERSpecs to the IDG for input_er_spec in self.inputs: #Get a node for the ERSpec input_er_spec_node=mapir.idg.get_node(IDGERSpec,input_er_spec) #Get a gen node for the ERSpec gen_input_er_spec_node=mapir.idg.get_node(IDGGenERSpec,input_er_spec) #Add dependence of the GenERSpec node to ERSpec node input_er_spec_node.add_dep(gen_input_er_spec_node) #Add dependence of the call to the input erg_call_node.add_dep(input_er_spec_node) #Add the output ERSpecs to the IDG for output_er_spec in self.outputs: #Get a node for the ERSpec output_er_spec_node=mapir.idg.get_node(IDGOutputERSpec,output_er_spec) #Add dependence of the output on the call output_er_spec_node.add_dep(erg_call_node)