def gen_er_u1d(er_spec,mapir): from iegen.codegen import Statement,Comment if 0==len(er_spec.relation): raise ValueError("ESpec's relation has no terms in the disjunction") if (1,1)!=er_spec.relation.arity(): raise ValueError("ESpec's relation must have arity (1,1)") iegen.print_progress("Generating code for ERSpec '%s'..."%(er_spec.name)) iegen.print_detail(er_spec) var_in_name=er_spec.relation.tuple_in[0] var_out_name=er_spec.relation.tuple_out[0] stmts=[] stmts.append(Comment('Creation of ER_U1D for abstract relation:')) stmts.append(Comment(str(er_spec.relation))) stmts.append(Statement('%s = %s();'%(er_spec.get_var_name(),er_spec.get_ctor_str()))) stmts.append(Statement()) stmts.append(Comment('Insert relevant EFs into ER_U1D')) #TODO: This assumes the ERSpec we are creading has the form: # {[in]->[out]: out=f1(in)} union ... union {[in]->[out]: out=fn(in)} #Because we assume this here, we can just iterate over the functions # that the relation contains for function_name in er_spec.relation.function_names: #Get the er_spec for the current function function_er_spec=mapir.er_specs[function_name] #Add the function to the ER_U1D stmts.append(Statement('ER_U1D_insert(%s, %s);'%(er_spec.get_var_name(),function_er_spec.get_var_name()))) stmts.append(Statement()) return stmts
def calc_equality_value(var_name,formula,mapir,raw_array=False,only_eqs=False): import iegen iegen.print_detail("Calculating equality value for tuple variable '%s' in relation %s"%(var_name,formula)) bounds=formula.bounds(var_name) if 0==len(bounds): raise ValueError("Tuple variable '%s' is not involved in any equality constraints in formula '%s'"%(var_name,formula)) if len(bounds)>1: raise ValueError("Tuple variable '%s' is equal to multiple values in formula '%s'"%(var_name,formula)) #Ignore inequality constraints? if only_eqs: lower_bounds=[] upper_bounds=[] #Remove any bounds that are only an upper or a lower bound (looking for equalities) for lb in bounds[0][0]: if lb in bounds[0][1]: lower_bounds.append(lb) upper_bounds.append(lb) else: lower_bounds,upper_bounds=bounds[0] if 1!=len(lower_bounds) or 1!=len(upper_bounds): raise ValueError("TupleVariable '%s' is not equal to exactly one value in formula '%s'"%(var_name,formula)) if lower_bounds!=upper_bounds: raise ValueError("TupleVariable '%s' is not equal to one value in formula '%s'"%(var_name,formula)) equal_value=list(lower_bounds)[0] ufs_name_map=mapir.ufs_name_map() iegen.print_detail("-->Equality value for tuple variable '%s' in relation %s: %s"%(var_name,formula,equal_value.value_string(function_name_map=ufs_name_map))) return equal_value.value_string(function_name_map=ufs_name_map)
def gen_output_er_1dto1d(output_er_spec,is_call_input,mapir): import iegen.pycloog from iegen.pycloog import codegen from iegen.codegen import Statement,Comment iegen.print_progress("Generating code for output ERSpec '%s'..."%(output_er_spec.name)) iegen.print_detail(str(output_er_spec)) print 'Abstract relation: %s'%(output_er_spec.relation) print 'Input bounds for abstract relation: %s'%(output_er_spec.input_bounds) print 'Output bounds for abstract relation: %s'%(output_er_spec.output_bounds) #Calculate the necessary information before generating code output_bounds_var_name=output_er_spec.output_bounds.tuple_set[0] output_lower_bound=str(list(output_er_spec.output_bounds.lower_bounds(output_bounds_var_name)[0])[0]) output_upper_bound=str(list(output_er_spec.output_bounds.upper_bounds(output_bounds_var_name)[0])[0]) input_bounds_var_name=output_er_spec.input_bounds.tuple_set[0] input_lower_bound=str(list(output_er_spec.input_bounds.lower_bounds(input_bounds_var_name)[0])[0]) input_upper_bound=str(list(output_er_spec.input_bounds.upper_bounds(input_bounds_var_name)[0])[0]) num_entries=calc_size_string(list(output_er_spec.output_bounds)[0],output_bounds_var_name) input_equal_value=calc_equality_value(input_bounds_var_name,list(output_er_spec.relation)[0],mapir) input_var_name=output_er_spec.relation.tuple_in[0] output_var_name=output_er_spec.relation.tuple_out[0] stmts=[] stmts.append(Comment('Creation of ER_1Dto1D for abstract relation:')) stmts.append(Comment(str(output_er_spec.relation))) stmts.append(Comment('Bounds for output domain: '+str(output_er_spec.output_bounds))) #Generate the call to the constructor stmts.append(Statement('%s=%s(%s,%s,%s,%s,%s);'%(output_er_spec.get_var_name(),output_er_spec.get_ctor_str(),input_lower_bound,input_upper_bound,output_lower_bound,output_upper_bound,num_entries))) #Generate the count loop stmts.append(Statement('#define S0(%s) %s(%s,%s)'%(output_var_name,output_er_spec.get_count_name(),output_er_spec.get_var_name(),input_equal_value))) loop_stmts=codegen([iegen.pycloog.Statement(output_er_spec.output_bounds)]).split('\n') for loop_stmt in loop_stmts: stmts.append(Statement(loop_stmt)) stmts.append(Statement('#undef S0')) #Generate the finalize count call stmts.append(Statement('%s(%s)'%(output_er_spec.get_count_finalize_name(),output_er_spec.get_var_name()))) #Generate the insert loop stmts.append(Statement('#define S0(%s) %s(%s,%s,%s)'%(output_var_name,output_er_spec.get_setter_str(),output_er_spec.get_var_name(),input_equal_value,output_var_name))) loop_stmts=codegen([iegen.pycloog.Statement(output_er_spec.output_bounds)]).split('\n') for loop_stmt in loop_stmts: stmts.append(Statement(loop_stmt)) stmts.append(Statement('#undef S0')) stmts.append(Statement('*%s=%s;'%(output_er_spec.get_param_name(),output_er_spec.get_var_name()))) stmts.append(Statement()) return stmts
def unregister_inverse_pair(function_name,inverse_function_name=None): #Build the inverse_function_name if it was not given if inverse_function_name is None: inverse_function_name=function_name+inverse_suffix() iegen.print_detail('Unregistering inverse function pair (%s,%s)...'%(function_name,inverse_function_name)) #Unregister the names in the dictionary of function name pairs del _inverse_pairs[function_name] del _inverse_pairs[inverse_function_name]
def calc_update_access_relations(mapir): iegen.print_progress('Updating access relations...') #Update each access relation's iteration to data relation to # match its statement's scattering function for statement in mapir.get_statements(): for access_relation in statement.get_access_relations(): iegen.print_detail("Updating iter_to_data of access relation '%s'..."%(access_relation.name)) before=str(access_relation.iter_to_data) #Compose the access relation to be in terms of the statement's scattering function access_relation.iter_to_data=access_relation.iter_to_data.compose(statement.scatter.inverse()) iegen.print_modified("Updated iter_to_data of access relation '%s': %s -> %s"%(access_relation.name,before,access_relation.iter_to_data))
def calc_unupdate_access_relations(mapir,full_to_iter): from iegen import Relation iegen.print_progress('Un-updating access relations...') #Update each access relation's iteration to data relation to # match its statement's iteration space for statement in mapir.get_statements(): for access_relation in statement.get_access_relations(): iegen.print_detail("Un-updating iter_to_data of access relation '%s'..."%(access_relation.name)) before=str(access_relation.iter_to_data) #Compose the access relation to be in terms of the statement's iteration space access_relation.iter_to_data=full_to_iter[statement.name].compose(access_relation.iter_to_data.inverse()).inverse() iegen.print_modified("Un-updated iter_to_data of access relation '%s': %s -> %s"%(access_relation.name,before,access_relation.iter_to_data))
def gen_explicit_er_spec(er_spec,mapir): import iegen.pycloog from iegen.pycloog import codegen from iegen.codegen import Statement,Comment if 0==len(er_spec.relation): raise ValueError("ESpec's relation has no terms in the disjunction") if (1,1)!=er_spec.relation.arity(): raise ValueError("ESpec's relation must have arity (1,1)") iegen.print_progress("Generating code for ERSpec '%s'..."%(er_spec.name)) iegen.print_detail(er_spec) var_in_name=er_spec.relation.tuple_in[0] var_out_name=er_spec.relation.tuple_out[0] #Generate the define/undefine statements cloog_stmts=[] define_stmts=[] undefine_stmts=[] for relation_index,relation in enumerate(er_spec.relation): #Get the value to insert value=calc_equality_value(var_out_name,relation,mapir) define_stmts.append(Statement('#define S%d(%s) ER_in_ordered_insert(%s_ER,Tuple_make(%s),Tuple_make(%s));'%(relation_index,var_in_name,er_spec.name,var_in_name,value))) cloog_stmts.append(iegen.pycloog.Statement(er_spec.input_bounds)) undefine_stmts.append(Statement('#undef S%d'%(relation_index,))) #Generate the whole set of statements stmts=[] in_domain_name='in_domain_%s'%(er_spec.name) stmts.extend(gen_domain(in_domain_name,er_spec.input_bounds)) stmts.append(Statement()) stmts.append(Comment('Creation of ExplicitRelation')) stmts.append(Comment(str(er_spec.relation))) stmts.append(Statement('%s_ER = %s(%d,%d,%s,%s,%s);'%(er_spec.name,er_spec.get_ctor_str(),er_spec.relation.arity_in(),er_spec.relation.arity_out(),in_domain_name,str(er_spec.is_function).lower(),str(er_spec.is_permutation).lower()))) stmts.append(Statement()) stmts.append(Comment('Define loop body statements')) stmts.extend(define_stmts) stmts.append(Statement()) loop_stmts=codegen(cloog_stmts).split('\n') for loop_stmt in loop_stmts: stmts.append(Statement(loop_stmt)) stmts.append(Statement()) stmts.append(Comment('Undefine loop body statements')) stmts.extend(undefine_stmts) return stmts
def gen_output_ef_2d(output_er_spec,is_call_input,mapir): import iegen.pycloog from iegen.pycloog import codegen from iegen.codegen import Statement,Comment iegen.print_progress("Generating code for output ERSpec '%s'..."%(output_er_spec.name)) iegen.print_detail(str(output_er_spec)) stmts=[] stmts.extend(gen_rect_union_domain_2d(output_er_spec.name,'input',output_er_spec.input_bounds)) output_bounds=output_er_spec.output_bounds #Make sure the output tuple is 1D if 1!=output_bounds.arity(): raise ValueError("EF_2D's (%s) output tuple is not 1D"%(output_er_spec.get_param_name())) output_var=output_bounds.tuple_vars[0] #Get the bounds on the single output var output_lbs=output_bounds.lower_bounds(output_var) output_ubs=output_bounds.upper_bounds(output_var) #Make sure the is a single lower and upper bound on the variable if 1!=len(output_lbs) or 1!=len(output_ubs): raise ValueError("Output bounds have more than one upper or lower bound") if 1!=len(output_lbs[0]) or 1!=len(output_ubs[0]): raise ValueError("Output bounds have more than one upper or lower bound") output_lb=list(output_lbs[0])[0] output_ub=list(output_ubs[0])[0] #Variable names for the two RUD2D input_domain_name='%s_input_rud'%(output_er_spec.get_param_name(),) stmts.append(Comment('Creation of ExplicitFunction for abstract relation:')) stmts.append(Comment(str(output_er_spec.relation))) stmts.append(Comment('Input bounds for abstract relation: %s'%(output_er_spec.input_bounds))) stmts.append(Statement('*%s=%s(%s,%s,%s,%s,%s);'%(output_er_spec.get_param_name(),output_er_spec.get_ctor_str(),output_er_spec.relation.arity_in(),output_er_spec.relation.arity_out(),input_domain_name,output_lb,output_ub))) stmts.append(Statement('%s=*%s;'%(output_er_spec.get_var_name(),output_er_spec.get_param_name()))) stmts.append(Statement()) return stmts
def gen_domain(name,set): from iegen.codegen import Statement,Comment iegen.print_detail("Generating RectUnionDomain for set %s"%set) stmts=[] stmts.append(Comment('RectUnionDomain for set %s'%(set))) if 1==len(set): conj_name = '%s_conj0'%(name) stmts.extend(gen_rect_domain(conj_name, list(set)[0])) stmts.append(Statement('RectUnionDomain *%s=RUD_ctor(%s);'%(name,conj_name))) else: stmts.append(Statement('RectUnionDomain *%s=RUD_ctor(%d);'%(name,set.arity()))) count = 0 for conjunct in set: conj_name = '%s_conj%d'%(name,count) stmts.extend(gen_rect_domain(conj_name,conjunct)) stmts.append(Statement('RUD_insert(%s,%s);'%(name,conj_name))) count = count + 1 return stmts
def gen_executor_loop_stmts(mapir): from iegen.codegen import Statement,Comment from iegen.util import trans_equals stmts=[] stmts.append(Comment('Define the executor main loop body statments')) statement_names=mapir.statements.keys() statement_names.sort() for i,statement_name in enumerate(statement_names): statement=mapir.statements[statement_name] for comment_line in statement.text.split('\n'): stmts.append(Comment(comment_line)) ar_dict={} for access_relation in statement.get_access_relations(): iegen.print_detail('Generating code for access relation %s'%(access_relation.name)) stmts.append(Comment('%s: %s'%(access_relation.name,access_relation.iter_to_data))) ar_string_list=[] for out_var_name in access_relation.iter_to_data.tuple_out: ar_string_list.append(calc_equality_value(out_var_name,access_relation.iter_to_data,mapir)) ar_dict[access_relation.name]=']['.join(ar_string_list) #Gather the loop iterators if statement.sparse_sched is None: iterators=','.join(statement.iter_space.tuple_set) else: iterators=','.join(statement.iter_space.tuple_set[:-1]) #If there are any UFS constraints, wrap the statement text in a guard statement_text=statement.text ufs_constraints=statement.iter_space.ufs_constraints() #Make sure there is only a single conjunction in the iteration space if len(ufs_constraints)!=1: raise ValueError('Iteration space has multiple conjunctions') #Check if we need to generate a sparse loop if statement.sparse_sched is not None: sparse_sched_name=statement.sparse_sched sparse_sched_er=mapir.er_specs[sparse_sched_name] iter_name=statement.iter_space.tuple_set[-1] outer_iter_name=statement.iter_space.tuple_set[-2] sparse_loop='''for(%s=%s(*%s,%s);\ %s!=%s(*%s,%s);\ %s=%s(*%s,%s))'''%(iter_name,sparse_sched_er.get_begin_iter(),sparse_sched_name,outer_iter_name,iter_name,sparse_sched_er.get_end_iter(),sparse_sched_name,outer_iter_name,iter_name,sparse_sched_er.get_next_iter(),sparse_sched_name,outer_iter_name) statement_text='''%s{\ %s\ }'''%(sparse_loop,statement_text) #Check if there are any UFS constraints that we need to generate guards for elif len(ufs_constraints[0])>0: ufs_constraints_strs=[trans_equals(str(constraint.value_string(function_name_map=mapir.ufs_name_map()))) for constraint in ufs_constraints[0]] statement_text='if(%s){%s}'%(' && '.join(ufs_constraints_strs),statement_text) stmt_string='#define S%d(%s) %s'%(i,iterators,statement_text) stmt_string=stmt_string.replace('\n','\\\n') stmts.append(Statement(stmt_string%ar_dict)) stmts.append(Statement()) return stmts
def gen_output_er_u1d(output_er_spec,is_call_input,mapir): import iegen.pycloog from iegen.pycloog import codegen from iegen.codegen import Statement,Comment iegen.print_progress("Generating code for output ERSpec '%s'..."%(output_er_spec.name)) iegen.print_detail(str(output_er_spec)) stmts=[] #TODO: Make this routine more general so it can handle generation for # general relations in addition to functions # Currently it just generates code for explicit functions #TODO: Generalize the bounds expression calculations to handle # more than a single expression (with min/max) input_var_name=output_er_spec.input_bounds.tuple_set[0] input_lower_bound=str(list(output_er_spec.input_bounds.lower_bounds(input_var_name)[0])[0]) input_upper_bound=str(list(output_er_spec.input_bounds.upper_bounds(input_var_name)[0])[0]) output_var_name=output_er_spec.output_bounds.tuple_set[0] output_lower_bound=str(list(output_er_spec.output_bounds.lower_bounds(output_var_name)[0])[0]) output_upper_bound=str(list(output_er_spec.output_bounds.upper_bounds(output_var_name)[0])[0]) stmts.append(Comment('Creation of ExplicitFunction for abstract relation:')) stmts.append(Comment(str(output_er_spec.relation))) stmts.append(Comment('Input bounds for abstract relation: %s'%(output_er_spec.input_bounds))) stmts.append(Comment('Output bounds for abstract relation: %s'%(output_er_spec.output_bounds))) stmts.append(Statement('*%s=%s(%s,%s,%s,%s,%s);'%(output_er_spec.get_param_name(),output_er_spec.get_ctor_str(),input_lower_bound,input_upper_bound,output_lower_bound,output_upper_bound,str(output_er_spec.is_permutation).lower()))) stmts.append(Statement('%s=*%s;'%(output_er_spec.get_var_name(),output_er_spec.get_param_name()))) stmts.append(Statement()) if not is_call_input: #Generate the define/undefine statements cloog_stmts=[] define_stmts=[] undefine_stmts=[] var_in_name=output_er_spec.relation.tuple_in[0] var_out_name=output_er_spec.relation.tuple_out[0] for relation_index,single_relation in enumerate(output_er_spec.relation): #Get the value to insert value=calc_equality_value(var_out_name,single_relation,mapir) define_stmts.append(Statement('#define S%d(%s) %s(%s,%s,%s);'%(relation_index,var_in_name,output_er_spec.get_setter_str(),output_er_spec.get_var_name(),var_in_name,value))) cloog_stmts.append(iegen.pycloog.Statement(output_er_spec.input_bounds)) undefine_stmts.append(Statement('#undef S%d'%(relation_index,))) #Generate the whole set of statements stmts.append(Comment('Define loop body statements')) stmts.extend(define_stmts) stmts.append(Statement()) loop_stmts=codegen(cloog_stmts).split('\n') for loop_stmt in loop_stmts: stmts.append(Statement(loop_stmt)) stmts.append(Statement()) stmts.append(Comment('Undefine loop body statements')) stmts.extend(undefine_stmts) stmts.append(Statement()) #TODO: This is the old code that generates an ER rather than an EF ##Create a domain for the ERSpec #in_domain_name='in_domain_%s'%(output_er_spec.name) #stmts.extend(gen_domain(in_domain_name,output_er_spec.input_bounds)) #stmts.append(Statement('*%s=ER_ctor(%d,%d,%s,%s,%s);'%(output_er_spec.name,output_er_spec.input_bounds.arity(),output_er_spec.output_bounds.arity(),in_domain_name,str(output_er_spec.is_function).lower(),str(output_er_spec.is_permutation).lower()))) #stmts.append(Statement('%s_ER=*%s;'%(output_er_spec.name,output_er_spec.name))) return stmts
def do_calc(mapir): from iegen.codegen import calc_initial_idg,calc_full_iter_space,calc_update_access_relations,calc_unupdate_access_relations iegen.print_progress('Starting calculation phase...') #Update iteration spaces and access relations before we start calculations calc_update(mapir) #Calculate the initial IDG calc_initial_idg(mapir) iegen.print_progress('Calculating full iteration space...') #Calculate the full iteration space based on the current iteration spaces of the statements mapir.full_iter_space=calc_full_iter_space(mapir.get_statements()) iegen.print_detail('----- Current full iteration space: -----') iegen.print_detail(mapir.full_iter_space) iegen.print_detail('-----------------------------------------') #Do calculations for each reordering for transformation in mapir.transformations: iegen.print_progress("Applying transformation '%s'..."%(transformation.name)) iegen.print_detail('----- Transformation: -----') iegen.print_detail(transformation) iegen.print_detail('------------------------------------') #Determine if the current transformation is a transformation or an ITO is_transformation=False is_ito=False #Assume the current transformation is a transformation, not an ITO try: #Ensure the transformation has the four expected methods calc_input=transformation.calc_input calc_output=transformation.calc_output update_mapir=transformation.update_mapir update_idg=transformation.update_idg is_transformation=True except AttributeError as e1: #Try the current transformation as an ITO try: #Ensure the ito has the single 'apply' method apply=transformation.apply is_ito=True except AttributeError as e2: pass if is_transformation: iegen.print_progress('Calculating inputs to transformation...') #Tell the transformation to calculate the inputs that it will need at runtime transformation.calc_input(mapir) iegen.print_progress('Calculating outputs from transformation...') #Tell the transformation to calculate the outputs it will produce at runtime transformation.calc_output(mapir) iegen.print_progress('Updating the MapIR...') #Tell the transformation to update the access relations, scattering functions and other components of the MapIR transformation.update_mapir(mapir) iegen.print_progress('Updating the IDG...') #Tell the transformation to update the IDG transformation.update_idg(mapir) elif is_ito: iegen.print_progress("Applying intertransopt '%s'..."%(transformation.name)) iegen.print_detail('----- InterTransOpt: -----') iegen.print_detail(transformation) iegen.print_detail('------------------------------------') transformation.apply(mapir) else: raise ValueError("Current transformation '%s' is neither a transformation nor an ITO"%(transformation.name)) #Calculate IDG dependences calc_idg_deps(mapir) iegen.print_modified("----- Updated statements (after transformation '%s'): -----"%(transformation.name)) for statement in mapir.get_statements(): iegen.print_modified(statement) iegen.print_modified("\n") iegen.print_modified('-----------------------------------------') iegen.print_progress('Calculating full iteration space...') #Calculate the full iteration space based on the current iteration spaces of the statements mapir.full_iter_space=calc_full_iter_space(mapir.get_statements()) iegen.print_detail('----- Current full iteration space: -----') iegen.print_detail(mapir.full_iter_space) iegen.print_detail('-----------------------------------------') #Un-update iteration spaces and access relations now that the calculation phase is over calc_unupdate(mapir) from iegen.idg.visitor import DotVisitor v=DotVisitor().visit(mapir.idg) v.write_dot('test.dot') iegen.print_progress('Calculation phase completed...')