예제 #1
0
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
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
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]
예제 #5
0
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))
예제 #6
0
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))
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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...')