mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Optimize in case this is SSA.
This commit is contained in:
		
							parent
							
								
									96e2a6d3fe
								
							
						
					
					
						commit
						6bbef64034
					
				| @ -33,6 +33,11 @@ using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::yul; | ||||
| 
 | ||||
| KnowledgeBase::KnowledgeBase(map<YulString, AssignedValue> const& _ssaValues): | ||||
| 	m_valuesAreSSA(true), | ||||
| 	m_variableValues([_ssaValues](YulString _var) { return util::valueOrNullptr(_ssaValues, _var); }) | ||||
| {} | ||||
| 
 | ||||
| bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b) | ||||
| { | ||||
| 	if (optional<u256> difference = differenceIfKnownConstant(_a, _b)) | ||||
| @ -85,11 +90,23 @@ optional<u256> KnowledgeBase::valueIfKnownConstant(Expression const& _expression | ||||
| 
 | ||||
| KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var) | ||||
| { | ||||
| 	// We query the value first so that the variable is reset if it has changed
 | ||||
| 	// since the last call.
 | ||||
| 	Expression const* value = valueOf(_var); | ||||
| 	if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var)) | ||||
| 		return *varOff; | ||||
| 	Expression const* value = nullptr; | ||||
| 	if (m_valuesAreSSA) | ||||
| 	{ | ||||
| 		// In SSA, a once determined offset is always valid, so we first see
 | ||||
| 		// if we already computed it.
 | ||||
| 		if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var)) | ||||
| 			return *varOff; | ||||
| 		value = valueOf(_var); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// For non-SSA, we query the value first so that the variable is reset if it has changed
 | ||||
| 		// since the last call.
 | ||||
| 		value = valueOf(_var); | ||||
| 		if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var)) | ||||
| 			return *varOff; | ||||
| 	} | ||||
| 
 | ||||
| 	if (value) | ||||
| 		if (optional<VariableOffset> offset = explore(*value)) | ||||
| @ -129,9 +146,12 @@ optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const& | ||||
| 
 | ||||
| Expression const* KnowledgeBase::valueOf(YulString _var) | ||||
| { | ||||
| 	Expression const* lastValue = m_lastKnownValue[_var]; | ||||
| 	AssignedValue const* assignedValue = m_variableValues(_var); | ||||
| 	Expression const* currentValue = assignedValue ? assignedValue->value : nullptr; | ||||
| 	if (m_valuesAreSSA) | ||||
| 		return currentValue; | ||||
| 
 | ||||
| 	Expression const* lastValue = m_lastKnownValue[_var]; | ||||
| 	if (lastValue != currentValue) | ||||
| 		reset(_var); | ||||
| 	m_lastKnownValue[_var] = currentValue; | ||||
| @ -140,6 +160,8 @@ Expression const* KnowledgeBase::valueOf(YulString _var) | ||||
| 
 | ||||
| void KnowledgeBase::reset(YulString _var) | ||||
| { | ||||
| 	yulAssert(!m_valuesAreSSA); | ||||
| 
 | ||||
| 	m_lastKnownValue.erase(_var); | ||||
| 	if (VariableOffset const* offset = util::valueOrNullptr(m_offsets, _var)) | ||||
| 	{ | ||||
|  | ||||
| @ -47,6 +47,9 @@ struct AssignedValue; | ||||
|  * form. | ||||
|  * The only requirement is that the assigned values are movable expressions. | ||||
|  * | ||||
|  * There is a constructor to provide all SSA values right at the beginning. | ||||
|  * If you use this, the KnowledgeBase will be slightly more efficient. | ||||
|  * | ||||
|  * Internally, tries to find groups of variables that have a mutual constant | ||||
|  * difference and stores these differences always relative to a specific | ||||
|  * representative variable of the group. | ||||
| @ -57,9 +60,13 @@ struct AssignedValue; | ||||
| class KnowledgeBase | ||||
| { | ||||
| public: | ||||
| 	/// Constructor for arbitrary value callback that allows for variable values
 | ||||
| 	/// to change in between calls to functions of this class.
 | ||||
| 	KnowledgeBase(std::function<AssignedValue const*(YulString)> _variableValues): | ||||
| 		m_variableValues(std::move(_variableValues)) | ||||
| 	{} | ||||
| 	/// Constructor to use if source code is in SSA form and values are constant.
 | ||||
| 	KnowledgeBase(std::map<YulString, AssignedValue> const& _ssaValues); | ||||
| 
 | ||||
| 	bool knownToBeDifferent(YulString _a, YulString _b); | ||||
| 	std::optional<u256> differenceIfKnownConstant(YulString _a, YulString _b); | ||||
| @ -91,6 +98,8 @@ private: | ||||
| 
 | ||||
| 	VariableOffset setOffset(YulString _variable, VariableOffset _value); | ||||
| 
 | ||||
| 	/// If true, we can assume that variable values never change and skip some steps.
 | ||||
| 	bool m_valuesAreSSA = false; | ||||
| 	/// Callback to retrieve the current value of a variable.
 | ||||
| 	std::function<AssignedValue const*(YulString)> m_variableValues; | ||||
| 
 | ||||
|  | ||||
| @ -104,7 +104,7 @@ UnusedStoreEliminator::UnusedStoreEliminator( | ||||
| 	m_functionSideEffects(_functionSideEffects), | ||||
| 	m_controlFlowSideEffects(_controlFlowSideEffects), | ||||
| 	m_ssaValues(_ssaValues), | ||||
| 	m_knowledgeBase([this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); }) | ||||
| 	m_knowledgeBase(_ssaValues) | ||||
| {} | ||||
| 
 | ||||
| void UnusedStoreEliminator::operator()(FunctionCall const& _functionCall) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user