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