blob: 6eba318c112a476a8dd617c70246e9e7b49b1166 [file] [log] [blame]
/**CFile****************************************************************
FileName [ivyBalance.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [And-Inverter Graph package.]
Synopsis [Algebraic AIG balancing.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - May 11, 2006.]
Revision [$Id: ivyBalance.c,v 1.00 2006/05/11 00:00:00 alanmi Exp $]
***********************************************************************/
#include "ivy.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static int Ivy_NodeBalance_rec( Ivy_Man_t * pNew, Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level, int fUpdateLevel );
static Vec_Ptr_t * Ivy_NodeBalanceCone( Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level );
static int Ivy_NodeBalanceFindLeft( Vec_Ptr_t * vSuper );
static void Ivy_NodeBalancePermute( Ivy_Man_t * p, Vec_Ptr_t * vSuper, int LeftBound, int fExor );
static void Ivy_NodeBalancePushUniqueOrderByLevel( Vec_Ptr_t * vStore, Ivy_Obj_t * pObj );
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Performs algebraic balancing of the AIG.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Ivy_Man_t * Ivy_ManBalance( Ivy_Man_t * p, int fUpdateLevel )
{
Ivy_Man_t * pNew;
Ivy_Obj_t * pObj, * pDriver;
Vec_Vec_t * vStore;
int i, NewNodeId;
// clean the old manager
Ivy_ManCleanTravId( p );
// create the new manager
pNew = Ivy_ManStart();
// map the nodes
Ivy_ManConst1(p)->TravId = Ivy_EdgeFromNode( Ivy_ManConst1(pNew) );
Ivy_ManForEachPi( p, pObj, i )
pObj->TravId = Ivy_EdgeFromNode( Ivy_ObjCreatePi(pNew) );
// if HAIG is defined, trasfer the pointers to the PIs/latches
// if ( p->pHaig )
// Ivy_ManHaigTrasfer( p, pNew );
// balance the AIG
vStore = Vec_VecAlloc( 50 );
Ivy_ManForEachPo( p, pObj, i )
{
pDriver = Ivy_ObjReal( Ivy_ObjChild0(pObj) );
NewNodeId = Ivy_NodeBalance_rec( pNew, Ivy_Regular(pDriver), vStore, 0, fUpdateLevel );
NewNodeId = Ivy_EdgeNotCond( NewNodeId, Ivy_IsComplement(pDriver) );
Ivy_ObjCreatePo( pNew, Ivy_EdgeToNode(pNew, NewNodeId) );
}
Vec_VecFree( vStore );
if ( (i = Ivy_ManCleanup( pNew )) )
{
// printf( "Cleanup after balancing removed %d dangling nodes.\n", i );
}
// check the resulting AIG
if ( !Ivy_ManCheck(pNew) )
printf( "Ivy_ManBalance(): The check has failed.\n" );
return pNew;
}
/**Function*************************************************************
Synopsis [Procedure used for sorting the nodes in decreasing order of levels.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeCompareLevelsDecrease( Ivy_Obj_t ** pp1, Ivy_Obj_t ** pp2 )
{
int Diff = Ivy_Regular(*pp1)->Level - Ivy_Regular(*pp2)->Level;
if ( Diff > 0 )
return -1;
if ( Diff < 0 )
return 1;
Diff = Ivy_Regular(*pp1)->Id - Ivy_Regular(*pp2)->Id;
if ( Diff > 0 )
return -1;
if ( Diff < 0 )
return 1;
return 0;
}
/**Function*************************************************************
Synopsis [Returns the ID of new node constructed.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeBalance_rec( Ivy_Man_t * pNew, Ivy_Obj_t * pObjOld, Vec_Vec_t * vStore, int Level, int fUpdateLevel )
{
Ivy_Obj_t * pObjNew;
Vec_Ptr_t * vSuper;
int i, NewNodeId;
assert( !Ivy_IsComplement(pObjOld) );
assert( !Ivy_ObjIsBuf(pObjOld) );
// return if the result is known
if ( Ivy_ObjIsConst1(pObjOld) )
return pObjOld->TravId;
if ( pObjOld->TravId )
return pObjOld->TravId;
assert( Ivy_ObjIsNode(pObjOld) );
// get the implication supergate
vSuper = Ivy_NodeBalanceCone( pObjOld, vStore, Level );
if ( vSuper->nSize == 0 )
{ // it means that the supergate contains two nodes in the opposite polarity
pObjOld->TravId = Ivy_EdgeFromNode( Ivy_ManConst0(pNew) );
return pObjOld->TravId;
}
if ( vSuper->nSize < 2 )
printf( "BUG!\n" );
// for each old node, derive the new well-balanced node
for ( i = 0; i < vSuper->nSize; i++ )
{
NewNodeId = Ivy_NodeBalance_rec( pNew, Ivy_Regular((Ivy_Obj_t *)vSuper->pArray[i]), vStore, Level + 1, fUpdateLevel );
NewNodeId = Ivy_EdgeNotCond( NewNodeId, Ivy_IsComplement((Ivy_Obj_t *)vSuper->pArray[i]) );
vSuper->pArray[i] = Ivy_EdgeToNode( pNew, NewNodeId );
}
// build the supergate
pObjNew = Ivy_NodeBalanceBuildSuper( pNew, vSuper, Ivy_ObjType(pObjOld), fUpdateLevel );
vSuper->nSize = 0;
// make sure the balanced node is not assigned
assert( pObjOld->TravId == 0 );
pObjOld->TravId = Ivy_EdgeFromNode( pObjNew );
// assert( pObjOld->Level >= Ivy_Regular(pObjNew)->Level );
return pObjOld->TravId;
}
/**Function*************************************************************
Synopsis [Builds implication supergate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Ivy_Obj_t * Ivy_NodeBalanceBuildSuper( Ivy_Man_t * p, Vec_Ptr_t * vSuper, Ivy_Type_t Type, int fUpdateLevel )
{
Ivy_Obj_t * pObj1, * pObj2;
int LeftBound;
assert( vSuper->nSize > 1 );
// sort the new nodes by level in the decreasing order
Vec_PtrSort( vSuper, (int (*)(void))Ivy_NodeCompareLevelsDecrease );
// balance the nodes
while ( vSuper->nSize > 1 )
{
// find the left bound on the node to be paired
LeftBound = (!fUpdateLevel)? 0 : Ivy_NodeBalanceFindLeft( vSuper );
// find the node that can be shared (if no such node, randomize choice)
Ivy_NodeBalancePermute( p, vSuper, LeftBound, Type == IVY_EXOR );
// pull out the last two nodes
pObj1 = (Ivy_Obj_t *)Vec_PtrPop(vSuper);
pObj2 = (Ivy_Obj_t *)Vec_PtrPop(vSuper);
Ivy_NodeBalancePushUniqueOrderByLevel( vSuper, Ivy_Oper(p, pObj1, pObj2, Type) );
}
return (Ivy_Obj_t *)Vec_PtrEntry(vSuper, 0);
}
/**Function*************************************************************
Synopsis [Collects the nodes of the supergate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeBalanceCone_rec( Ivy_Obj_t * pRoot, Ivy_Obj_t * pObj, Vec_Ptr_t * vSuper )
{
int RetValue1, RetValue2, i;
// check if the node is visited
if ( Ivy_Regular(pObj)->fMarkB )
{
// check if the node occurs in the same polarity
for ( i = 0; i < vSuper->nSize; i++ )
if ( vSuper->pArray[i] == pObj )
return 1;
// check if the node is present in the opposite polarity
for ( i = 0; i < vSuper->nSize; i++ )
if ( vSuper->pArray[i] == Ivy_Not(pObj) )
return -1;
assert( 0 );
return 0;
}
// if the new node is complemented or a PI, another gate begins
if ( pObj != pRoot && (Ivy_IsComplement(pObj) || Ivy_ObjType(pObj) != Ivy_ObjType(pRoot) || Ivy_ObjRefs(pObj) > 1 || Vec_PtrSize(vSuper) > 10000) )
{
Vec_PtrPush( vSuper, pObj );
Ivy_Regular(pObj)->fMarkB = 1;
return 0;
}
assert( !Ivy_IsComplement(pObj) );
assert( Ivy_ObjIsNode(pObj) );
// go through the branches
RetValue1 = Ivy_NodeBalanceCone_rec( pRoot, Ivy_ObjReal( Ivy_ObjChild0(pObj) ), vSuper );
RetValue2 = Ivy_NodeBalanceCone_rec( pRoot, Ivy_ObjReal( Ivy_ObjChild1(pObj) ), vSuper );
if ( RetValue1 == -1 || RetValue2 == -1 )
return -1;
// return 1 if at least one branch has a duplicate
return RetValue1 || RetValue2;
}
/**Function*************************************************************
Synopsis [Collects the nodes of the supergate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Ivy_NodeBalanceCone( Ivy_Obj_t * pObj, Vec_Vec_t * vStore, int Level )
{
Vec_Ptr_t * vNodes;
int RetValue, i;
assert( !Ivy_IsComplement(pObj) );
// extend the storage
if ( Vec_VecSize( vStore ) <= Level )
Vec_VecPush( vStore, Level, 0 );
// get the temporary array of nodes
vNodes = Vec_VecEntry( vStore, Level );
Vec_PtrClear( vNodes );
// collect the nodes in the implication supergate
RetValue = Ivy_NodeBalanceCone_rec( pObj, pObj, vNodes );
assert( vNodes->nSize > 1 );
// unmark the visited nodes
Vec_PtrForEachEntry( Ivy_Obj_t *, vNodes, pObj, i )
Ivy_Regular(pObj)->fMarkB = 0;
// if we found the node and its complement in the same implication supergate,
// return empty set of nodes (meaning that we should use constant-0 node)
if ( RetValue == -1 )
vNodes->nSize = 0;
return vNodes;
}
/**Function*************************************************************
Synopsis [Finds the left bound on the next candidate to be paired.]
Description [The nodes in the array are in the decreasing order of levels.
The last node in the array has the smallest level. By default it would be paired
with the next node on the left. However, it may be possible to pair it with some
other node on the left, in such a way that the new node is shared. This procedure
finds the index of the left-most node, which can be paired with the last node.]
SideEffects []
SeeAlso []
***********************************************************************/
int Ivy_NodeBalanceFindLeft( Vec_Ptr_t * vSuper )
{
Ivy_Obj_t * pObjRight, * pObjLeft;
int Current;
// if two or less nodes, pair with the first
if ( Vec_PtrSize(vSuper) < 3 )
return 0;
// set the pointer to the one before the last
Current = Vec_PtrSize(vSuper) - 2;
pObjRight = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, Current );
// go through the nodes to the left of this one
for ( Current--; Current >= 0; Current-- )
{
// get the next node on the left
pObjLeft = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, Current );
// if the level of this node is different, quit the loop
if ( Ivy_Regular(pObjLeft)->Level != Ivy_Regular(pObjRight)->Level )
break;
}
Current++;
// get the node, for which the equality holds
pObjLeft = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, Current );
assert( Ivy_Regular(pObjLeft)->Level == Ivy_Regular(pObjRight)->Level );
return Current;
}
/**Function*************************************************************
Synopsis [Moves closer to the end the node that is best for sharing.]
Description [If there is no node with sharing, randomly chooses one of
the legal nodes.]
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_NodeBalancePermute( Ivy_Man_t * p, Vec_Ptr_t * vSuper, int LeftBound, int fExor )
{
Ivy_Obj_t * pObj1, * pObj2, * pObj3, * pGhost;
int RightBound, i;
// get the right bound
RightBound = Vec_PtrSize(vSuper) - 2;
assert( LeftBound <= RightBound );
if ( LeftBound == RightBound )
return;
// get the two last nodes
pObj1 = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, RightBound + 1 );
pObj2 = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, RightBound );
if ( Ivy_Regular(pObj1) == p->pConst1 || Ivy_Regular(pObj2) == p->pConst1 )
return;
// find the first node that can be shared
for ( i = RightBound; i >= LeftBound; i-- )
{
pObj3 = (Ivy_Obj_t *)Vec_PtrEntry( vSuper, i );
if ( Ivy_Regular(pObj3) == p->pConst1 )
{
Vec_PtrWriteEntry( vSuper, i, pObj2 );
Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
return;
}
pGhost = Ivy_ObjCreateGhost( p, pObj1, pObj3, fExor? IVY_EXOR : IVY_AND, IVY_INIT_NONE );
if ( Ivy_TableLookup( p, pGhost ) )
{
if ( pObj3 == pObj2 )
return;
Vec_PtrWriteEntry( vSuper, i, pObj2 );
Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
return;
}
}
/*
// we did not find the node to share, randomize choice
{
int Choice = rand() % (RightBound - LeftBound + 1);
pObj3 = Vec_PtrEntry( vSuper, LeftBound + Choice );
if ( pObj3 == pObj2 )
return;
Vec_PtrWriteEntry( vSuper, LeftBound + Choice, pObj2 );
Vec_PtrWriteEntry( vSuper, RightBound, pObj3 );
}
*/
}
/**Function*************************************************************
Synopsis [Inserts a new node in the order by levels.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ivy_NodeBalancePushUniqueOrderByLevel( Vec_Ptr_t * vStore, Ivy_Obj_t * pObj )
{
Ivy_Obj_t * pObj1, * pObj2;
int i;
if ( Vec_PtrPushUnique(vStore, pObj) )
return;
// find the p of the node
for ( i = vStore->nSize-1; i > 0; i-- )
{
pObj1 = (Ivy_Obj_t *)vStore->pArray[i ];
pObj2 = (Ivy_Obj_t *)vStore->pArray[i-1];
if ( Ivy_Regular(pObj1)->Level <= Ivy_Regular(pObj2)->Level )
break;
vStore->pArray[i ] = pObj2;
vStore->pArray[i-1] = pObj1;
}
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END