def calc_unupdate_scatter(mapir): from iegen import Relation iegen.print_progress("Un-updating scattering functions...") for statement in mapir.get_statements(): #TODO: This approach is a HACK due to the lack of an intersect operation with set/relation #Get a string of the constraints for the statement's scattering function scatter_constrs=str(list(list(statement.scatter.range())[0].disjunction.conjunctions)[0]) #Get the output tuple from the scattering function scatter_tuple_out=statement.scatter.tuple_out #Get just the iterators and not interleaved constants from the scattering function scatter_iters=[tuple_var for pos,tuple_var in enumerate(statement.scatter.tuple_out) if pos%2==1] #Get the statement's iteration space iterators iters=statement.iter_space.tuple_set #Get pairs of scatter iters/iteration space iters #If there are more scattering iters than in the iteration space, zip handles it iter_pairs=zip(iters,scatter_iters) #Create equality constraint strings for the pairs of iterators eq_constraints=[] for iter_space_iter,scatter_iter in iter_pairs: eq_constraints.append('%s=%s'%(iter_space_iter,scatter_iter)) eq_constraints=' and '.join(eq_constraints) #Make comma separated lists iters=','.join(iters) scatter_tuple_out=','.join(scatter_tuple_out) new_scatter=Relation('{[%s]->[%s]: %s and %s}'%(iters,scatter_tuple_out,scatter_constrs,eq_constraints),symbolics=statement.scatter.symbolics) statement.scatter=new_scatter
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_update_iter_spaces(mapir): iegen.print_progress('Updating iteration spaces...') #Update each statement's iteration space to be within the context of the full iteration space #rather than just iterators for statement in mapir.get_statements(): statement.iter_space=statement.iter_space.apply(statement.scatter)
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 gen_call(call_spec): iegen.print_progress("Generating code for call to '%s'..."%(call_spec.function_name)) stmts=[] stmts.append(Comment('Call the %s routine'%(call_spec.function_name))) stmts.append(Statement(call_spec.function_name+'('+','.join(call_spec.arguments)+');')) #Generate the proper output argument assignments, if any for output_arg in call_spec.output_args: stmts.append(Statement('*%s=%s;'%(output_arg.name,output_arg.get_var_name()))) stmts.append(Statement()) return stmts
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 calc_unupdate_iter_spaces(mapir): from iegen import Relation iegen.print_progress('Un-updating iteration spaces...') full_to_iter={} #Update each statement's iteration space to be only iterators and no interleaved constants for statement in mapir.get_statements(): #Extract the iterators and not the constant positions (iterators are the odd positions) iters=[tuple_var for pos,tuple_var in enumerate(statement.iter_space.tuple_set) if pos%2==1] #Create a new set with just the extracted iterators extract_iters_rel=Relation('{[%s]->[%s]}'%(','.join(statement.iter_space.tuple_set),','.join(iters))) temp_iter=statement.iter_space.apply(extract_iters_rel) #Determine the dimensions of the new iteration space that are not constant non_const_vars=[] for var in temp_iter.tuple_set: try: #Try to determine what the current variable is equal to val=calc_equality_value(var,temp_iter,mapir) except ValueError as e: #The current variable wasn't equal to a single value, i.e. not constant non_const_vars.append(var) else: try: #The current variable was equal to a single value, try to convert it to an integer val=int(val) except ValueError as e: #The current variable was equal to a single value but not an integer #TODO: This checking doesn't check for transitivity (i.e. a=b and b=0) non_const_vars.append(var) #Construct a relation for taking the full iteration space down to just the non-constant iterators full_to_iter_rel=Relation('{[%s]->[%s]}'%(','.join(iters[:len(non_const_vars)]),','.join(statement.iter_space.tuple_set))).inverse() full_to_iter[statement.name]=full_to_iter_rel #Un-update the statement's iteration space using the full_to_iter relation statement.iter_space=statement.iter_space.apply(full_to_iter_rel) return full_to_iter
def do_gen(mapir): import iegen from iegen.codegen import Program,gen_preamble,gen_inspector,gen_executor,gen_main iegen.print_progress('Starting the code generation phase...') program=Program() #Create the program if iegen.settings.gen_preamble: iegen.print_progress('Generating the preamble...') program.preamble.extend(gen_preamble()) #Generate the inspector iegen.print_progress('Generating the inspector...') program.functions.append(gen_inspector(mapir)) #Generate the executor iegen.print_progress('Generating the executor...') program.functions.append(gen_executor(mapir)) #Generate the main code if iegen.settings.gen_main: iegen.print_progress('Generating main()...') program.functions.append(gen_main(mapir)) iegen.print_progress('Code generation phase completed...') return program
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...')