diff --git a/c-opopt.cc b/c-opopt.cc
index 62e76aa..3f68de4 100644
--- a/c-opopt.cc
+++ b/c-opopt.cc
@@ -58,11 +58,11 @@ constexpr uint32_t T_OptData::CFG_END;
 void T_OptData::findInputDecls(
 		T_OpsParserOutput& program ) noexcept
 {
-	if ( inputDecls ) {
+	if ( state & E_StateItem::INPUTS ) {
 		return;
 	}
 
-	inputDecls = T_KeyValueTable< T_String , T_Array< T_InputDecl > >{ };
+	inputDecls.clear( );
 	visitor.visit( program.root , [this]( A_Node& node , const bool exit ) {
 		if ( exit && node.type( ) == A_Node::OP_INPUT ) {
 			auto& input{ (T_InputInstrNode&) node };
@@ -75,6 +75,8 @@ void T_OptData::findInputDecls(
 		}
 		return true;
 	} );
+
+	state = state | E_StateItem::INPUTS;
 }
 
 
@@ -110,6 +112,10 @@ bool ODNIVisitor_(
 void T_OptData::numberInstructions(
 		T_OpsParserOutput& program ) noexcept
 {
+	if ( state & E_StateItem::NUMBERING ) {
+		return;
+	}
+
 	instructions.clear( );
 	instrIndex.clear( );
 
@@ -120,6 +126,8 @@ void T_OptData::numberInstructions(
 				return ODNIVisitor_( node , exit , *this , i );
 			} );
 	}
+
+	state = state | E_StateItem::NUMBERING;
 }
 
 uint32_t T_OptData::indexOf(
@@ -485,6 +493,11 @@ inline T_StringBuilder BCFGDumpAll_(
 void T_OptData::buildControlFlowGraph(
 		T_OpsParserOutput& program ) noexcept
 {
+	if ( state & E_StateItem::CFG ) {
+		return;
+	}
+	numberInstructions( program );
+
 	// Keep the old array, we'll reuse its contents
 	T_Array< P_CtrlFlowNode > old{ std::move( ctrlFlowGraph ) };
 	M_LOGSTR_( "Building control flow graph" , 4 );
@@ -511,6 +524,8 @@ void T_OptData::buildControlFlowGraph(
 	logger( [this](){
 		return BCFGDumpAll_( *this );
 	} , 6 );
+
+	state = state | E_StateItem::CFG;
 }
 
 #undef M_ADDNEW_
@@ -1012,6 +1027,11 @@ void BUDCWalkGraph_(
 void T_OptData::buildUseDefineChains(
 		T_OpsParserOutput& program ) noexcept
 {
+	if ( state & E_StateItem::UDCHAINS ) {
+		return;
+	}
+	buildControlFlowGraph( program );
+
 	M_LOGSTR_( "Building use/define chains" , 4 );
 	varUDChains.clear( );
 
@@ -1060,6 +1080,8 @@ void T_OptData::buildUseDefineChains(
 		    }
 		}
 	}
+
+	state = state | E_StateItem::UDCHAINS;
 }
 
 
@@ -1479,8 +1501,6 @@ bool opopt::PropagateConstants(
 	// updated at the end of the frame function, the value cannot be
 	// propagated.
 
-	oData.numberInstructions( program );
-	oData.buildControlFlowGraph( program );
 	oData.buildUseDefineChains( program );
 	M_LOGSTR_( "... Propagating constants" , 2 );
 
diff --git a/c-opopt.hh b/c-opopt.hh
index 583f817..9830deb 100644
--- a/c-opopt.hh
+++ b/c-opopt.hh
@@ -29,6 +29,19 @@ struct T_OptData
 
 	//----------------------------------------------------------------------
 
+	// Elements of the optimizer's state
+	enum class E_StateItem
+	{
+		INPUTS ,
+		NUMBERING ,
+		CFG ,
+		UDCHAINS
+	};
+	using T_State = T_Flags< E_StateItem >;
+	T_State state{};
+
+	//----------------------------------------------------------------------
+
 	// Table of input declarations; used to fold constant inputs.
 	struct T_InputDecl {
 		ebcl::T_SRDLocation location;