예제 #1
0
파일: _mapir.py 프로젝트: lamielle/iegen
	def __init__(self):
		self.symbolics={}
		self.data_arrays={}
		self.index_arrays={}
		self.er_specs={}
		self.statements={}
		self.data_dependences={}
		self.transformations=[]
		self.intertransopts=[]
		self.idg=IDG()

		#Register this instance's inverse_simplify_fired as a listener
		iegen.simplify.register_inverse_simplify_listener(MapIR.inverse_simplify_fired,self)
예제 #2
0
파일: _mapir.py 프로젝트: lamielle/iegen
class MapIR(IEGenObject):
	__slots__=('symbolics','data_arrays','er_specs','index_arrays','statements','data_dependences','transformations','intertransopts','full_iter_space','idg')

	def __init__(self):
		self.symbolics={}
		self.data_arrays={}
		self.index_arrays={}
		self.er_specs={}
		self.statements={}
		self.data_dependences={}
		self.transformations=[]
		self.intertransopts=[]
		self.idg=IDG()

		#Register this instance's inverse_simplify_fired as a listener
		iegen.simplify.register_inverse_simplify_listener(MapIR.inverse_simplify_fired,self)

	#---------- Symbolics ----------
	#Returns the symbolics that are present in the MapIR
	def get_symbolics(self): return self.symbolics.values()

	#Adds a symbolic constructed from the given arguments to the MapIR
	def add_symbolic(self,**kwargs):
		self.print_progress("Adding symbolic '%s'..."%kwargs['name'])
		self._convert_create_add(Symbolic,[self.symbolics],**kwargs)
	#-------------------------------

	#---------- Data Arrays ----------
	#Returns the data arrays that are present in the MapIR
	def get_data_arrays(self): return self.data_arrays.values()

	#Adds a data array constructed from the given arguments to the MapIR
	def add_data_array(self,**kwargs):
		self.print_progress("Adding data array '%s'..."%kwargs['name'])
		self._convert_create_add(DataArray,[self.data_arrays],**kwargs)
	#---------------------------------

	#---------- ERSpecs ----------
	#Returns the ERSpecs that are present in the MapIR
	def get_er_specs(self): return self.er_specs.values()

	#Adds the given ERSpec to the collection of ERSpecs
	def add_er_spec(self,er_spec):
		self.print_progress("Adding ERSpec '%s'..."%er_spec.name)
		#Register this function and its inverse if it is a permutation
		# and if it is not already part of a a pair of inverses
		if er_spec.is_permutation and er_spec.name not in iegen.simplify.inverse_pairs():
			self.print_progress("Registering function '%s' as an inverse..."%(er_spec.name))
			iegen.simplify.register_inverse_pair(er_spec.name)
		self.er_specs[er_spec.name]=er_spec

	#Returns true if an ERSpec with the given name exists in the MapIR
	def contains_er_spec(self,er_spec_name):
		contains=False
		for er_spec in self.get_er_specs():
			if er_spec_name==er_spec.name:
				contains=True
				break
		return contains

	#Returns the ERSpec in the MapIR of the given name, or dies
	def get_er_spec(self,er_spec_name):
		for er_spec in self.get_er_specs():
			if er_spec_name==er_spec.name:
				break
		if er_spec_name!=er_spec.name:
			raise ValueError("No ERSpec exists in the MapIR that corresponds to function '%s'"%(er_spec_name))
		return er_spec

	#Listener callback called when the inverse simplification rule fires
	def inverse_simplify_fired(self,func_name,func_inv_name):
		#Make sure an ERSpec exists for the function
		if not self.contains_er_spec(func_name):
			raise ValueError("Inverse simplification rule fired on function '%s' but no ERSpec exists in the MapIR that corresponds to this function"%(func_name))

		#Process this notification if the inverse ERSpec doesn't already exist
		if not self.contains_er_spec(func_inv_name):
			#Get the ERSpec associated with func_name
			er_spec=self.get_er_spec(func_name)

			#Create the corresponding inverse ERSpec
			er_spec_inv=ERSpec(func_inv_name,
			  input_bounds=er_spec.output_bounds.copy(),
			  output_bounds=er_spec.input_bounds.copy(),
			  relation=None,
			  is_function=er_spec.is_function,
			  is_permutation=er_spec.is_permutation,
			  is_inverse=True,
			  inverse_of=func_name)

			#Add the inverse ERSpec to the MapIR
			self.add_er_spec(er_spec_inv)

			#Set the relation now that we have added the ERSpec to the MapIR
			self.er_specs[func_inv_name].relation=er_spec.relation.inverse()

			#Get the IDG nodes
			er_spec_node=self.idg.get_node(IDGOutputERSpec,er_spec)
			er_spec_inv_node=self.idg.get_node(IDGOutputERSpec,er_spec_inv)
			gen_er_spec_inv_node=self.idg.get_node(IDGGenERSpec,er_spec_inv)

			#Setup the dependences
			gen_er_spec_inv_node.add_dep(er_spec_node)
			er_spec_inv_node.add_dep(gen_er_spec_inv_node)
	#-----------------------------

	#---------- Index Arrays ----------
	#Returns the index arrays that are present in the MapIR
	def get_index_arrays(self): return self.index_arrays.values()

	#Adds a index array constructed from the given arguments to the MapIR
	def add_index_array(self,**kwargs):
		self.print_progress("Adding index array '%s'..."%kwargs['name'])
		self._convert_create_add(IndexArray,[self.index_arrays,self.er_specs],**kwargs)
	#----------------------------------

	#---------- Statements ----------
	#Returns the statements that are present in the MapIR
	def get_statements(self): return self.statements.values()

	#Adds a statement constructed from the given arguments to the MapIR
	def add_statement(self,**kwargs):
		self.print_progress("Adding statement '%s'..."%kwargs['name'])
		self._convert_create_add(Statement,[self.statements],**kwargs)
	#--------------------------------

	#---------- Access Relations ----------
	def get_access_relations(self,statement_name): return self.statements[statement_name].get_access_relations()

	#Adds an access relation to the named statement constructed from the given arguments to the MapIR
	def add_access_relation(self,statement_name,**kwargs):
		self.print_progress("Adding access relation '%s'..."%kwargs['name'])

		#Create the access relation
		access_relation=self._convert_create_add(AccessRelation,**kwargs)

		#Add the access relation to the specified statement
		self.statements[statement_name].add_access_relation(access_relation)
	#--------------------------------------

	#---------- Data Dependences ----------
	#Returns the data dependences that are present in the MapIR
	def get_data_dependences(self): return self.data_dependences.values()

	def add_data_dependence(self,**kwargs):
		self.print_progress("Adding data dependence '%s'..."%kwargs['name'])

		#Create the data dependence
		data_dependence=self._convert_create_add(DataDependence,[self.data_dependences],**kwargs)
	#--------------------------------------

	#---------- Transformations ----------
	#Adds a transformation to the MapIR of the given type and constructs it 
	#from the given arguments.
	#Transformations are not stored as a dictionary as the ordering
	# is meaningful (they will be applied in the order they are added)
	def add_transformation(self,type,**kwargs):
		self.print_progress("Adding transformation '%s'..."%kwargs['name'])

		#Create the transformation
		transformation=self._convert_create_add(type,**kwargs)

		#Add the transformation to the list of transformations
		self.transformations.append(transformation)
	#-------------------------------------

	#---------- InterTransOpts ----------
	#Adds an inter transformation optimization to the MapIR of the given type
	# and constructs it from the given arguments.
	#ITOs are not stored as a dictionary as the ordering
	# is meaningful (they will be applied in the order they are added along with the transformations)
	def add_intertransopt(self,type,**kwargs):
		self.print_progress("Adding ITO '%s'..."%kwargs['name'])

		#Create the ITO
		ito=self._convert_create_add(type,**kwargs)

		#Add the ITO to the list of ITOs
		self.transformations.append(ito)
	#-------------------------------------


	#---------- Main 'action' method ---------
	#This is the main interface that starts the whole code generation process
	#Given is a filled-in MapIR data structure
	#Code is generated based upon this data
	def codegen(self):

		self.print_progress('Spec file read, starting processing...')

		#Create a string buffer to hold the code that is generated
		code=StringIO()

		#Run code generation
		iegen.codegen.codegen(self,code)

		#Return the generated code
		return code.getvalue()
	#---------------------------------------

	#---------- Utility methods ----------
	#Returns a mapping from the name of each UFS (ERSpec and index array) to that UFS's getter string
	def ufs_name_map(self):
		ufs_name_map={}
		for er_spec in self.get_er_specs():
			ufs_name_map[er_spec.name]=er_spec.get_getter_pair()
		return ufs_name_map

	#Returns a dict that maps the name of each UFS (ERSpec and index array) to that UFS's range
	def ufs_range_dict(self):
		range_dict={}

		for er_spec in self.get_er_specs():
			range_dict[er_spec.name]=er_spec.output_bounds

		return range_dict
	#-------------------------------------

	#---------- Private Utility methods ----------
	#Creates an object and adds it to each of the given dictionaries
	#This method does three things:
	#-Creates Sets/Relations for certain fields in kwargs
	#-Creates an object using the given class and arguments
	#-Adds the object to the given dictionaries, if any are given
	#In case it is needed, the created object is returned
	def _convert_create_add(self,CreateClass,add_dicts=None,**kwargs):
		#Convert all set/relation strings to Sets/Relations
		self._generic_convert(CreateClass,kwargs)

		#Create the object using the modified kwargs and the given class
		obj=self._generic_create(CreateClass,**kwargs)

		#Add the created object to the add_dicts
		if add_dicts: self._generic_add(obj,add_dicts)

		return obj

	#Convert all elements in kwargs named in CreateClass._{set,relation}_fields to a Set or Relation
	def _generic_convert(self,CreateClass,kwargs):
		try:
			#Convert all set_fields into Sets
			try:
				self._create_sets(CreateClass._set_fields,kwargs)
			except AttributeError,e: pass

			#Convert all relation_fields into Relations
			try:
				self._create_relations(CreateClass._relation_fields,kwargs)
			except AttributeError,e: pass

			#Convert all data_array_fields into DataArrays
			try:
				self._convert_data_arrays(CreateClass._data_array_fields,kwargs)
			except AttributeError,e: pass

			#Convert all data_arrays_fields into collections of DataArrays
			try:
				self._convert_data_arrays_collection(CreateClass._data_arrays_fields,kwargs)
			except AttributeError,e: pass
		except KeyError,e: raise AttributeError("Field %s was not specified when adding object of type '%s'."%(e,CreateClass))

	#Add the given object to the given dicts based on the objects 'name' field
	def _generic_add(self,obj,add_dicts):
		for add_dict in add_dicts:
			add_dict[obj.name]=obj

	#Return the result of creating an object using the given class and constructor arguments
	def _generic_create(self,CreateClass,**kwargs):
		return CreateClass(**kwargs)

	#Converts dict entries named in set_fields into Set objects
	def _create_sets(self,set_fields,dict):
		#Convert any fields named in set_fields from set strings to Set objects
		for field_name in set_fields:
			dict[field_name]=self._create_set(dict[field_name])

	#Creates a Set from the given set string and passing in the current symbolics
	def _create_set(self,set_string):
		return Set(set_string,self.get_symbolics())

	#Converts dict entries named in relation_fields into Relation objects
	def _create_relations(self,relation_fields,dict):
		#Convert any fields named in relation_fields from relation strings to Relation objects
		for field_name in relation_fields:
			dict[field_name]=self._create_relation(dict[field_name])

	#Creates a Relation from the given relation string and passing in the current symbolics
	def _create_relation(self,rel_string):
		return Relation(rel_string,self.get_symbolics())

	#Converts dict entries named in data_array_fields into existing DataArray objects in the MapIR
	#If a data array with the name found in the dict is not in the MapIR, a NameError is raised
	def _convert_data_arrays(self,data_array_fields,dict):
		#Convert any fields named in data_array_fields from strings to data arrays from the MapIR
		for field_name in data_array_fields:
			try:
				dict[field_name]=self.data_arrays[dict[field_name]]
			except KeyError,e:
				raise NameError("Data array '%s' does not exist in the MapIR"%(dict[field_name]))