1 /**CFile****************************************************************
2
3 FileName [giaBalance.c]
4
5 SystemName [ABC: Logic synthesis and verification system.]
6
7 PackageName [Scalable AIG package.]
8
9 Synopsis [AIG balancing.]
10
11 Author [Alan Mishchenko]
12
13 Affiliation [UC Berkeley]
14
15 Date [Ver. 1.0. Started - June 20, 2005.]
16
17 Revision [$Id: giaBalance.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
18
19 ***********************************************************************/
20
21 #include "gia.h"
22 #include "misc/vec/vecHash.h"
23 #include "misc/vec/vecQue.h"
24 #include "opt/dau/dau.h"
25
26 ABC_NAMESPACE_IMPL_START
27
28
29 ////////////////////////////////////////////////////////////////////////
30 /// DECLARATIONS ///
31 ////////////////////////////////////////////////////////////////////////
32
33 #define BAL_LEAF_MAX 6
34 #define BAL_CUT_MAX 8
35 #define BAL_SUPER 50
36 #define BAL_NO_LEAF 31
37 #define BAL_NO_FUNC 134217727 // (1<<27)-1
38
39 typedef struct Bal_Cut_t_ Bal_Cut_t;
40 struct Bal_Cut_t_
41 {
42 word Sign; // signature
43 int Delay; // delay
44 unsigned iFunc : 27; // function (BAL_NO_FUNC)
45 unsigned nLeaves : 5; // leaf number (Bal_NO_LEAF)
46 int pLeaves[BAL_LEAF_MAX]; // leaves
47 };
48
49 // operation manager
50 typedef struct Bal_Man_t_ Bal_Man_t;
51 struct Bal_Man_t_
52 {
53 Gia_Man_t * pGia; // user AIG
54 int nLutSize; // LUT size
55 int nCutNum; // cut number
56 int fCutMin; // cut minimization
57 int fVerbose; // verbose
58 Gia_Man_t * pNew; // derived AIG
59 Vec_Int_t * vCosts; // cost of supergate nodes
60 Vec_Ptr_t * vCutSets; // object cutsets
61 abctime clkStart; // starting the clock
62 };
63
Bal_GiaMan(Gia_Man_t * p)64 static inline Bal_Man_t * Bal_GiaMan( Gia_Man_t * p ) { return (Bal_Man_t *)p->pData; }
65
Bal_ObjCost(Bal_Man_t * p,int i)66 static inline int Bal_ObjCost( Bal_Man_t * p, int i ) { return Vec_IntEntry(p->vCosts, i); }
Bal_LitCost(Bal_Man_t * p,int i)67 static inline int Bal_LitCost( Bal_Man_t * p, int i ) { return Bal_ObjCost(p, Abc_Lit2Var(i)); }
Bal_ObjDelay(Bal_Man_t * p,int i)68 static inline int Bal_ObjDelay( Bal_Man_t * p, int i ) { return Bal_ObjCost(p, i) >> 4; }
Bal_LitDelay(Bal_Man_t * p,int i)69 static inline int Bal_LitDelay( Bal_Man_t * p, int i ) { return Bal_ObjDelay(p, Abc_Lit2Var(i)); }
70
71 ////////////////////////////////////////////////////////////////////////
72 /// FUNCTION DEFINITIONS ///
73 ////////////////////////////////////////////////////////////////////////
74
75 /**Function*************************************************************
76
77 Synopsis []
78
79 Description []
80
81 SideEffects []
82
83 SeeAlso []
84
85 ***********************************************************************/
Bal_ManAlloc(Gia_Man_t * pGia,Gia_Man_t * pNew,int nLutSize,int nCutNum,int fVerbose)86 Bal_Man_t * Bal_ManAlloc( Gia_Man_t * pGia, Gia_Man_t * pNew, int nLutSize, int nCutNum, int fVerbose )
87 {
88 Bal_Man_t * p;
89 p = ABC_CALLOC( Bal_Man_t, 1 );
90 p->clkStart = Abc_Clock();
91 p->pGia = pGia;
92 p->pNew = pNew;
93 p->nLutSize = nLutSize;
94 p->nCutNum = nCutNum;
95 p->fVerbose = fVerbose;
96 p->vCosts = Vec_IntAlloc( 3 * Gia_ManObjNum(pGia) / 2 );
97 p->vCutSets = Vec_PtrAlloc( 3 * Gia_ManObjNum(pGia) / 2 );
98 Vec_IntFill( p->vCosts, Gia_ManObjNum(pNew), 0 );
99 Vec_PtrFill( p->vCutSets, Gia_ManObjNum(pNew), NULL );
100 pNew->pData = p;
101 return p;
102 }
Bal_ManFree(Bal_Man_t * p)103 void Bal_ManFree( Bal_Man_t * p )
104 {
105 Vec_PtrFreeFree( p->vCutSets );
106 Vec_IntFree( p->vCosts );
107 ABC_FREE( p );
108 }
109
110 /**Function*************************************************************
111
112 Synopsis []
113
114 Description []
115
116 SideEffects []
117
118 SeeAlso []
119
120 ***********************************************************************/
Bal_CutCountBits(word i)121 static inline int Bal_CutCountBits( word i )
122 {
123 i = i - ((i >> 1) & 0x5555555555555555);
124 i = (i & 0x3333333333333333) + ((i >> 2) & 0x3333333333333333);
125 i = ((i + (i >> 4)) & 0x0F0F0F0F0F0F0F0F);
126 return (i*(0x0101010101010101))>>56;
127 }
Bal_CutGetSign(int * pLeaves,int nLeaves)128 static inline word Bal_CutGetSign( int * pLeaves, int nLeaves )
129 {
130 word Sign = 0; int i;
131 for ( i = 0; i < nLeaves; i++ )
132 Sign |= ((word)1) << (pLeaves[i] & 0x3F);
133 return Sign;
134 }
Bal_CutCreateUnit(Bal_Cut_t * p,int i,int Delay)135 static inline int Bal_CutCreateUnit( Bal_Cut_t * p, int i, int Delay )
136 {
137 p->iFunc = 2;
138 p->Delay = Delay;
139 p->nLeaves = 1;
140 p->pLeaves[0] = i;
141 p->Sign = ((word)1) << (i & 0x3F);
142 return 1;
143 }
Bal_ManPrepareSet(Bal_Man_t * p,int iObj,int Index,int fUnit,Bal_Cut_t ** ppCutSet)144 static inline int Bal_ManPrepareSet( Bal_Man_t * p, int iObj, int Index, int fUnit, Bal_Cut_t ** ppCutSet )
145 {
146 static Bal_Cut_t CutTemp[3]; int i;
147 if ( Vec_PtrEntry(p->vCutSets, iObj) == NULL || fUnit )
148 return Bal_CutCreateUnit( (*ppCutSet = CutTemp + Index), iObj, Bal_ObjDelay(p, iObj)+1 );
149 *ppCutSet = (Bal_Cut_t *)Vec_PtrEntry(p->vCutSets, iObj);
150 for ( i = 0; i < p->nCutNum; i++ )
151 if ( (*ppCutSet)[i].nLeaves == BAL_NO_LEAF )
152 return i;
153 return i;
154 }
155
156
157 /**Function*************************************************************
158
159 Synopsis [Check correctness of cuts.]
160
161 Description []
162
163 SideEffects []
164
165 SeeAlso []
166
167 ***********************************************************************/
Bal_CutCheck(Bal_Cut_t * pBase,Bal_Cut_t * pCut)168 static inline int Bal_CutCheck( Bal_Cut_t * pBase, Bal_Cut_t * pCut ) // check if pCut is contained in pBase
169 {
170 int nSizeB = pBase->nLeaves;
171 int nSizeC = pCut->nLeaves;
172 int i, * pB = pBase->pLeaves;
173 int k, * pC = pCut->pLeaves;
174 for ( i = 0; i < nSizeC; i++ )
175 {
176 for ( k = 0; k < nSizeB; k++ )
177 if ( pC[i] == pB[k] )
178 break;
179 if ( k == nSizeB )
180 return 0;
181 }
182 return 1;
183 }
Bal_SetCheckArray(Bal_Cut_t ** ppCuts,int nCuts)184 static inline int Bal_SetCheckArray( Bal_Cut_t ** ppCuts, int nCuts )
185 {
186 Bal_Cut_t * pCut0, * pCut1;
187 int i, k, m, n, Value;
188 assert( nCuts > 0 );
189 for ( i = 0; i < nCuts; i++ )
190 {
191 pCut0 = ppCuts[i];
192 assert( pCut0->nLeaves <= BAL_LEAF_MAX );
193 assert( pCut0->Sign == Bal_CutGetSign(pCut0->pLeaves, pCut0->nLeaves) );
194 // check duplicates
195 for ( m = 0; m < (int)pCut0->nLeaves; m++ )
196 for ( n = m + 1; n < (int)pCut0->nLeaves; n++ )
197 assert( pCut0->pLeaves[m] < pCut0->pLeaves[n] );
198 // check pairs
199 for ( k = 0; k < nCuts; k++ )
200 {
201 pCut1 = ppCuts[k];
202 if ( pCut0 == pCut1 )
203 continue;
204 // check containments
205 Value = Bal_CutCheck( pCut0, pCut1 );
206 assert( Value == 0 );
207 }
208 }
209 return 1;
210 }
211
212 /**Function*************************************************************
213
214 Synopsis []
215
216 Description []
217
218 SideEffects []
219
220 SeeAlso []
221
222 ***********************************************************************/
Bal_CutMergeOrder(Bal_Cut_t * pCut0,Bal_Cut_t * pCut1,Bal_Cut_t * pCut,int nLutSize)223 static inline int Bal_CutMergeOrder( Bal_Cut_t * pCut0, Bal_Cut_t * pCut1, Bal_Cut_t * pCut, int nLutSize )
224 {
225 int nSize0 = pCut0->nLeaves;
226 int nSize1 = pCut1->nLeaves;
227 int i, * pC0 = pCut0->pLeaves;
228 int k, * pC1 = pCut1->pLeaves;
229 int c, * pC = pCut->pLeaves;
230 // the case of the largest cut sizes
231 if ( nSize0 == nLutSize && nSize1 == nLutSize )
232 {
233 for ( i = 0; i < nSize0; i++ )
234 {
235 if ( pC0[i] != pC1[i] ) return 0;
236 pC[i] = pC0[i];
237 }
238 pCut->nLeaves = nLutSize;
239 pCut->iFunc = BAL_NO_FUNC;
240 pCut->Sign = pCut0->Sign | pCut1->Sign;
241 pCut->Delay = Abc_MaxInt( pCut0->Delay, pCut1->Delay );
242 return 1;
243 }
244 // compare two cuts with different numbers
245 i = k = c = 0;
246 while ( 1 )
247 {
248 if ( c == nLutSize ) return 0;
249 if ( pC0[i] < pC1[k] )
250 {
251 pC[c++] = pC0[i++];
252 if ( i >= nSize0 ) goto FlushCut1;
253 }
254 else if ( pC0[i] > pC1[k] )
255 {
256 pC[c++] = pC1[k++];
257 if ( k >= nSize1 ) goto FlushCut0;
258 }
259 else
260 {
261 pC[c++] = pC0[i++]; k++;
262 if ( i >= nSize0 ) goto FlushCut1;
263 if ( k >= nSize1 ) goto FlushCut0;
264 }
265 }
266
267 FlushCut0:
268 if ( c + nSize0 > nLutSize + i ) return 0;
269 while ( i < nSize0 )
270 pC[c++] = pC0[i++];
271 pCut->nLeaves = c;
272 pCut->iFunc = BAL_NO_FUNC;
273 pCut->Sign = pCut0->Sign | pCut1->Sign;
274 pCut->Delay = Abc_MaxInt( pCut0->Delay, pCut1->Delay );
275 return 1;
276
277 FlushCut1:
278 if ( c + nSize1 > nLutSize + k ) return 0;
279 while ( k < nSize1 )
280 pC[c++] = pC1[k++];
281 pCut->nLeaves = c;
282 pCut->iFunc = BAL_NO_FUNC;
283 pCut->Sign = pCut0->Sign | pCut1->Sign;
284 pCut->Delay = Abc_MaxInt( pCut0->Delay, pCut1->Delay );
285 return 1;
286 }
Bal_CutMergeOrderMux(Bal_Cut_t * pCut0,Bal_Cut_t * pCut1,Bal_Cut_t * pCut2,Bal_Cut_t * pCut,int nLutSize)287 static inline int Bal_CutMergeOrderMux( Bal_Cut_t * pCut0, Bal_Cut_t * pCut1, Bal_Cut_t * pCut2, Bal_Cut_t * pCut, int nLutSize )
288 {
289 int x0, i0 = 0, nSize0 = pCut0->nLeaves, * pC0 = pCut0->pLeaves;
290 int x1, i1 = 0, nSize1 = pCut1->nLeaves, * pC1 = pCut1->pLeaves;
291 int x2, i2 = 0, nSize2 = pCut2->nLeaves, * pC2 = pCut2->pLeaves;
292 int xMin, c = 0, * pC = pCut->pLeaves;
293 while ( 1 )
294 {
295 x0 = (i0 == nSize0) ? ABC_INFINITY : pC0[i0];
296 x1 = (i1 == nSize1) ? ABC_INFINITY : pC1[i1];
297 x2 = (i2 == nSize2) ? ABC_INFINITY : pC2[i2];
298 xMin = Abc_MinInt( Abc_MinInt(x0, x1), x2 );
299 if ( xMin == ABC_INFINITY ) break;
300 if ( c == nLutSize ) return 0;
301 pC[c++] = xMin;
302 if (x0 == xMin) i0++;
303 if (x1 == xMin) i1++;
304 if (x2 == xMin) i2++;
305 }
306 pCut->nLeaves = c;
307 pCut->iFunc = BAL_NO_FUNC;
308 pCut->Sign = pCut0->Sign | pCut1->Sign | pCut2->Sign;
309 pCut->Delay = Abc_MaxInt( pCut0->Delay, Abc_MaxInt(pCut1->Delay, pCut2->Delay) );
310 return 1;
311 }
Bal_SetCutIsContainedOrder(Bal_Cut_t * pBase,Bal_Cut_t * pCut)312 static inline int Bal_SetCutIsContainedOrder( Bal_Cut_t * pBase, Bal_Cut_t * pCut ) // check if pCut is contained in pBase
313 {
314 int i, nSizeB = pBase->nLeaves;
315 int k, nSizeC = pCut->nLeaves;
316 if ( nSizeB == nSizeC )
317 {
318 for ( i = 0; i < nSizeB; i++ )
319 if ( pBase->pLeaves[i] != pCut->pLeaves[i] )
320 return 0;
321 return 1;
322 }
323 assert( nSizeB > nSizeC );
324 if ( nSizeC == 0 )
325 return 1;
326 for ( i = k = 0; i < nSizeB; i++ )
327 {
328 if ( pBase->pLeaves[i] > pCut->pLeaves[k] )
329 return 0;
330 if ( pBase->pLeaves[i] == pCut->pLeaves[k] )
331 {
332 if ( ++k == nSizeC )
333 return 1;
334 }
335 }
336 return 0;
337 }
Bal_SetLastCutIsContained(Bal_Cut_t ** pCuts,int nCuts)338 static inline int Bal_SetLastCutIsContained( Bal_Cut_t ** pCuts, int nCuts )
339 {
340 int i;
341 for ( i = 0; i < nCuts; i++ )
342 if ( pCuts[i]->nLeaves <= pCuts[nCuts]->nLeaves && (pCuts[i]->Sign & pCuts[nCuts]->Sign) == pCuts[i]->Sign && Bal_SetCutIsContainedOrder(pCuts[nCuts], pCuts[i]) )
343 return 1;
344 return 0;
345 }
Bal_SetLastCutContains(Bal_Cut_t ** pCuts,int nCuts)346 static inline int Bal_SetLastCutContains( Bal_Cut_t ** pCuts, int nCuts )
347 {
348 int i, k, fChanges = 0;
349 for ( i = 0; i < nCuts; i++ )
350 if ( pCuts[nCuts]->nLeaves < pCuts[i]->nLeaves && (pCuts[nCuts]->Sign & pCuts[i]->Sign) == pCuts[nCuts]->Sign && Bal_SetCutIsContainedOrder(pCuts[i], pCuts[nCuts]) )
351 pCuts[i]->nLeaves = BAL_NO_LEAF, fChanges = 1;
352 if ( !fChanges )
353 return nCuts;
354 for ( i = k = 0; i <= nCuts; i++ )
355 {
356 if ( pCuts[i]->nLeaves == BAL_NO_LEAF )
357 continue;
358 if ( k < i )
359 ABC_SWAP( Bal_Cut_t *, pCuts[k], pCuts[i] );
360 k++;
361 }
362 return k - 1;
363 }
Bal_CutCompareArea(Bal_Cut_t * pCut0,Bal_Cut_t * pCut1)364 static inline int Bal_CutCompareArea( Bal_Cut_t * pCut0, Bal_Cut_t * pCut1 )
365 {
366 if ( pCut0->Delay < pCut1->Delay ) return -1;
367 if ( pCut0->Delay > pCut1->Delay ) return 1;
368 if ( pCut0->nLeaves < pCut1->nLeaves ) return -1;
369 if ( pCut0->nLeaves > pCut1->nLeaves ) return 1;
370 return 0;
371 }
Bal_SetSortByDelay(Bal_Cut_t ** pCuts,int nCuts)372 static inline void Bal_SetSortByDelay( Bal_Cut_t ** pCuts, int nCuts )
373 {
374 int i;
375 for ( i = nCuts; i > 0; i-- )
376 {
377 if ( Bal_CutCompareArea(pCuts[i - 1], pCuts[i]) < 0 )//!= 1 )
378 return;
379 ABC_SWAP( Bal_Cut_t *, pCuts[i - 1], pCuts[i] );
380 }
381 }
Bal_SetAddCut(Bal_Cut_t ** pCuts,int nCuts,int nCutNum)382 static inline int Bal_SetAddCut( Bal_Cut_t ** pCuts, int nCuts, int nCutNum )
383 {
384 if ( nCuts == 0 )
385 return 1;
386 nCuts = Bal_SetLastCutContains(pCuts, nCuts);
387 Bal_SetSortByDelay( pCuts, nCuts );
388 return Abc_MinInt( nCuts + 1, nCutNum - 1 );
389 }
390
391 /**Function*************************************************************
392
393 Synopsis []
394
395 Description []
396
397 SideEffects []
398
399 SeeAlso []
400
401 ***********************************************************************/
Bal_ManDeriveCuts(Bal_Man_t * p,int iFan0,int iFan1,int iFan2,int fCompl0,int fCompl1,int fCompl2,int fUnit0,int fUnit1,int fUnit2,int fIsXor,int Target,int fSave)402 int Bal_ManDeriveCuts( Bal_Man_t * p, int iFan0, int iFan1, int iFan2, int fCompl0, int fCompl1, int fCompl2, int fUnit0, int fUnit1, int fUnit2, int fIsXor, int Target, int fSave )
403 {
404 Bal_Cut_t pCutSet[BAL_CUT_MAX], * pCutsR[BAL_CUT_MAX];
405 Bal_Cut_t * pCutSet0, * pCutSet1, * pCutSet2;
406 int nCuts0 = Bal_ManPrepareSet( p, iFan0, 0, fUnit0, &pCutSet0 );
407 int nCuts1 = Bal_ManPrepareSet( p, iFan1, 1, fUnit1, &pCutSet1 );
408 Bal_Cut_t * pCut0, * pCut0Lim = pCutSet0 + nCuts0;
409 Bal_Cut_t * pCut1, * pCut1Lim = pCutSet1 + nCuts1;
410 int i, Cost, nCutsR = 0;
411 memset( pCutSet, 0, sizeof(Bal_Cut_t) * p->nCutNum );
412 for ( i = 0; i < p->nCutNum; i++ )
413 pCutsR[i] = pCutSet + i;
414 // enumerate cuts
415 if ( iFan2 > 0 )
416 {
417 int nCuts2 = Bal_ManPrepareSet( p, iFan2, 2, fUnit2, &pCutSet2 );
418 Bal_Cut_t * pCut2, * pCut2Lim = pCutSet2 + nCuts2;
419 for ( pCut0 = pCutSet0; pCut0 < pCut0Lim; pCut0++ )
420 for ( pCut1 = pCutSet1; pCut1 < pCut1Lim; pCut1++ )
421 for ( pCut2 = pCutSet2; pCut2 < pCut2Lim; pCut2++ )
422 {
423 if ( Bal_CutCountBits(pCut0->Sign | pCut1->Sign | pCut2->Sign) > p->nLutSize )
424 continue;
425 if ( !Bal_CutMergeOrderMux(pCut0, pCut1, pCut2, pCutsR[nCutsR], p->nLutSize) )
426 continue;
427 assert( pCutsR[nCutsR]->Delay == Target );
428 if ( Bal_SetLastCutIsContained(pCutsR, nCutsR) )
429 continue;
430 // if ( p->fCutMin && Bal_CutComputeTruthMux(p, pCut0, pCut1, pCut2, fCompl0, fCompl1, fCompl2, pCutsR[nCutsR]) )
431 // pCutsR[nCutsR]->Sign = Bal_CutGetSign(pCutsR[nCutsR]->pLeaves, pCutsR[nCutsR]->nLeaves);
432 nCutsR = Bal_SetAddCut( pCutsR, nCutsR, p->nCutNum );
433 }
434 }
435 else
436 {
437 for ( pCut0 = pCutSet0; pCut0 < pCut0Lim; pCut0++ )
438 for ( pCut1 = pCutSet1; pCut1 < pCut1Lim; pCut1++ )
439 {
440 if ( Bal_CutCountBits(pCut0->Sign | pCut1->Sign) > p->nLutSize )
441 continue;
442 if ( !Bal_CutMergeOrder(pCut0, pCut1, pCutsR[nCutsR], p->nLutSize) )
443 continue;
444 assert( pCutsR[nCutsR]->Delay == Target );
445 if ( Bal_SetLastCutIsContained(pCutsR, nCutsR) )
446 continue;
447 // if ( p->fCutMin && Bal_CutComputeTruth(p, pCut0, pCut1, fCompl0, fCompl1, pCutsR[nCutsR], fIsXor) )
448 // pCutsR[nCutsR]->Sign = Bal_CutGetSign(pCutsR[nCutsR]->pLeaves, pCutsR[nCutsR]->nLeaves);
449 nCutsR = Bal_SetAddCut( pCutsR, nCutsR, p->nCutNum );
450 }
451 }
452 if ( nCutsR == 0 )
453 return -1;
454 //printf( "%d ", nCutsR );
455 Cost = ((pCutsR[0]->Delay << 4) | pCutsR[0]->nLeaves);
456 // verify
457 assert( nCutsR > 0 && nCutsR < p->nCutNum );
458 assert( Bal_SetCheckArray(pCutsR, nCutsR) );
459 // save cuts
460 if ( fSave && Cost >= 0 )
461 {
462 pCutSet0 = ABC_CALLOC( Bal_Cut_t, p->nCutNum );
463 Vec_PtrPush( p->vCutSets, pCutSet0 );
464 assert( Vec_PtrSize(p->vCutSets) == Gia_ManObjNum(p->pNew) );
465 for ( i = 0; i < nCutsR; i++ )
466 pCutSet0[i] = *pCutsR[i];
467 for ( ; i < p->nCutNum; i++ )
468 pCutSet0[i].nLeaves = BAL_NO_LEAF;
469 Vec_IntPush( p->vCosts, Cost );
470 assert( Vec_IntSize(p->vCosts) == Gia_ManObjNum(p->pNew) );
471 }
472 return Cost;
473 }
474
475 /**Function*************************************************************
476
477 Synopsis []
478
479 Description []
480
481 SideEffects []
482
483 SeeAlso []
484
485 ***********************************************************************/
Bal_ManSetGateLevel(Bal_Man_t * p,Gia_Obj_t * pObjOld,int iLitNew)486 int Bal_ManSetGateLevel( Bal_Man_t * p, Gia_Obj_t * pObjOld, int iLitNew )
487 {
488 int iFan0, iFan1, iFan2, Cost;
489 int fCompl0, fCompl1, fCompl2;
490 int fUnit0, fUnit1, fUnit2;
491 int Delay0, Delay1, Delay2, DelayMax;
492 int iObjNew = Abc_Lit2Var(iLitNew);
493 Gia_Obj_t * pObjNew = Gia_ManObj( p->pNew, iObjNew );
494 int fMux = Gia_ObjIsMux(p->pNew, pObjNew);
495 if ( iObjNew < Vec_PtrSize(p->vCutSets) )
496 return -1;
497 iFan0 = Gia_ObjFaninId0( pObjNew, iObjNew );
498 iFan1 = Gia_ObjFaninId1( pObjNew, iObjNew );
499 iFan2 = fMux ? Gia_ObjFaninId2(p->pNew, iObjNew) : 0;
500 fCompl0 = Gia_ObjFaninC0( pObjNew );
501 fCompl1 = Gia_ObjFaninC1( pObjNew );
502 fCompl2 = fMux ? Gia_ObjFaninC2(p->pNew, pObjNew) : 0;
503 Delay0 = Bal_ObjDelay( p, iFan0 );
504 Delay1 = Bal_ObjDelay( p, iFan1 );
505 Delay2 = Bal_ObjDelay( p, iFan2 );
506 DelayMax = Abc_MaxInt( Delay0, Abc_MaxInt(Delay1, Delay2) );
507 fUnit0 = (int)(Delay0 != DelayMax);
508 fUnit1 = (int)(Delay1 != DelayMax);
509 fUnit2 = (int)(Delay2 != DelayMax);
510 if ( DelayMax > 0 )
511 {
512 //printf( "A" );
513 Cost = Bal_ManDeriveCuts(p, iFan0, iFan1, iFan2, fCompl0, fCompl1, fCompl2, fUnit0, fUnit1, fUnit2, Gia_ObjIsXor(pObjNew), DelayMax, 1 );
514 //printf( "B" );
515 if ( Cost >= 0 )
516 return Cost;
517 }
518 DelayMax++;
519 fUnit0 = fUnit1 = fUnit2 = 1;
520 //printf( "A" );
521 Cost = Bal_ManDeriveCuts(p, iFan0, iFan1, iFan2, fCompl0, fCompl1, fCompl2, fUnit0, fUnit1, fUnit2, Gia_ObjIsXor(pObjNew), DelayMax, 1 );
522 //printf( "B" );
523 assert( Cost >= 0 );
524 return Cost;
525 }
Bal_ManEvalTwo(Bal_Man_t * p,int iLitNew0,int iLitNew1,int iLitNew2,int fIsXor)526 int Bal_ManEvalTwo( Bal_Man_t * p, int iLitNew0, int iLitNew1, int iLitNew2, int fIsXor )
527 {
528 int iFan0 = Abc_Lit2Var( iLitNew0 );
529 int iFan1 = Abc_Lit2Var( iLitNew1 );
530 int iFan2 = Abc_Lit2Var( iLitNew2 );
531 int fCompl0 = Abc_LitIsCompl( iLitNew0 );
532 int fCompl1 = Abc_LitIsCompl( iLitNew1 );
533 int fCompl2 = Abc_LitIsCompl( iLitNew2 );
534 int Delay0 = Bal_ObjDelay( p, iFan0 );
535 int Delay1 = Bal_ObjDelay( p, iFan1 );
536 int Delay2 = Bal_ObjDelay( p, iFan2 );
537 int DelayMax = Abc_MaxInt( Delay0, Abc_MaxInt(Delay1, Delay2) );
538 int fUnit0 = (int)(Delay0 != DelayMax);
539 int fUnit1 = (int)(Delay1 != DelayMax);
540 int fUnit2 = (int)(Delay2 != DelayMax);
541 if ( DelayMax == 0 )
542 return -1;
543 return Bal_ManDeriveCuts(p, iFan0, iFan1, iFan2, fCompl0, fCompl1, fCompl2, fUnit0, fUnit1, fUnit2, fIsXor, DelayMax, 0 );
544 }
545
546 /**Function*************************************************************
547
548 Synopsis [Sort literals by their cost.]
549
550 Description []
551
552 SideEffects []
553
554 SeeAlso []
555
556 ***********************************************************************/
Vec_IntSelectSortCostLit(Vec_Int_t * vSuper,Vec_Int_t * vCosts)557 static inline void Vec_IntSelectSortCostLit( Vec_Int_t * vSuper, Vec_Int_t * vCosts )
558 {
559 int * pArray = Vec_IntArray(vSuper);
560 int nSize = Vec_IntSize(vSuper);
561 int i, j, best_i;
562 for ( i = 0; i < nSize-1; i++ )
563 {
564 best_i = i;
565 for ( j = i+1; j < nSize; j++ )
566 if ( Vec_IntEntry(vCosts, Abc_Lit2Var(pArray[j])) > Vec_IntEntry(vCosts, Abc_Lit2Var(pArray[best_i])) )
567 best_i = j;
568 ABC_SWAP( int, pArray[i], pArray[best_i] );
569 }
570 }
Vec_IntPushOrderCost2(Vec_Int_t * vSuper,Vec_Int_t * vCosts,int iLit)571 static inline void Vec_IntPushOrderCost2( Vec_Int_t * vSuper, Vec_Int_t * vCosts, int iLit )
572 {
573 int i, nSize, * pArray;
574 Vec_IntPush( vSuper, iLit );
575 pArray = Vec_IntArray(vSuper);
576 nSize = Vec_IntSize(vSuper);
577 for ( i = nSize-1; i > 0; i-- )
578 {
579 if ( Vec_IntEntry(vCosts, Abc_Lit2Var(pArray[i])) <= Vec_IntEntry(vCosts, Abc_Lit2Var(pArray[i - 1])) )
580 return;
581 ABC_SWAP( int, pArray[i], pArray[i - 1] );
582 }
583 }
Vec_IntFindFirstSameDelayAsLast(Bal_Man_t * p,Vec_Int_t * vSuper)584 static inline int Vec_IntFindFirstSameDelayAsLast( Bal_Man_t * p, Vec_Int_t * vSuper )
585 {
586 int i, DelayCur, Delay = Bal_LitDelay( p, Vec_IntEntryLast(vSuper) );
587 assert( Vec_IntSize(vSuper) > 1 );
588 for ( i = Vec_IntSize(vSuper)-1; i > 0; i-- )
589 {
590 DelayCur = Bal_LitDelay( p, Vec_IntEntry(vSuper, i-1) );
591 assert( DelayCur >= Delay );
592 if ( DelayCur > Delay )
593 return i;
594 }
595 return i;
596 }
597
598
599 /**Function*************************************************************
600
601 Synopsis [Select the best pair to merge.]
602
603 Description []
604
605 SideEffects []
606
607 SeeAlso []
608
609 ***********************************************************************/
Bal_ManFindBestPair(Bal_Man_t * p,Vec_Int_t * vSuper,Gia_Obj_t * pObj)610 static inline int Bal_ManFindBestPair( Bal_Man_t * p, Vec_Int_t * vSuper, Gia_Obj_t * pObj )
611 {
612 int * pSuper = Vec_IntArray(vSuper);
613 int iBeg = Vec_IntFindFirstSameDelayAsLast( p, vSuper );
614 int iEnd = Vec_IntSize(vSuper)-1;
615 int i, k, iBest = -1, kBest = -1, BestCost = ABC_INFINITY, Cost;
616 assert( iBeg <= iEnd );
617 // check if we can add to the higher levels without increasing cost
618 for ( k = iBeg-1; k >= 0; k-- )
619 for ( i = iEnd; i >= iBeg; i-- )
620 {
621 Cost = Bal_ManEvalTwo( p, pSuper[i], pSuper[k], 0, Gia_ObjIsXor(pObj) );
622 if ( Cost == -1 )
623 continue;
624 if ( Cost == Bal_LitCost(p, pSuper[k]) )
625 {
626 // printf( "A" );
627 return (k << 16)|i;
628 }
629 if ( BestCost > Cost )
630 BestCost = Cost, iBest = i, kBest = k;
631 }
632 if ( BestCost != ABC_INFINITY && (BestCost >> 4) == Bal_LitDelay(p, pSuper[kBest]) )
633 {
634 // printf( "B" );
635 return (kBest << 16)|iBest;
636 }
637 // check if some can be added to lowest level without increasing cost
638 BestCost = ABC_INFINITY;
639 for ( i = iBeg; i <= iEnd; i++ )
640 for ( k = i+1; k <= iEnd; k++ )
641 {
642 Cost = Bal_ManEvalTwo( p, pSuper[i], pSuper[k], 0, Gia_ObjIsXor(pObj) );
643 if ( Cost == -1 )
644 continue;
645 if ( Cost == Abc_MaxInt(Bal_LitCost(p, pSuper[i]), Bal_LitCost(p, pSuper[k])) )
646 {
647 // printf( "C" );
648 return (k << 16)|i;
649 }
650 if ( BestCost > Cost )
651 BestCost = Cost, iBest = i, kBest = k;
652 }
653 if ( BestCost != ABC_INFINITY )
654 {
655 // printf( "D" );
656 return (kBest << 16)|iBest;
657 }
658 // printf( "E" );
659 // group pairs from lowest level based on proximity
660 return (iEnd << 16)|(iEnd-1);
661 }
662
663 /**Function*************************************************************
664
665 Synopsis [Simplify multi-input AND/XOR.]
666
667 Description []
668
669 SideEffects []
670
671 SeeAlso []
672
673 ***********************************************************************/
Gia_ManSimplifyXor(Vec_Int_t * vSuper)674 static inline void Gia_ManSimplifyXor( Vec_Int_t * vSuper )
675 {
676 int i, k = 0, Prev = -1, This, fCompl = 0;
677 Vec_IntForEachEntry( vSuper, This, i )
678 {
679 if ( This == 0 )
680 continue;
681 if ( This == 1 )
682 fCompl ^= 1;
683 else if ( Prev != This )
684 Vec_IntWriteEntry( vSuper, k++, This ), Prev = This;
685 else
686 Prev = -1, k--;
687 }
688 Vec_IntShrink( vSuper, k );
689 if ( Vec_IntSize( vSuper ) == 0 )
690 Vec_IntPush( vSuper, fCompl );
691 else if ( fCompl )
692 Vec_IntWriteEntry( vSuper, 0, Abc_LitNot(Vec_IntEntry(vSuper, 0)) );
693 }
Gia_ManSimplifyAnd(Vec_Int_t * vSuper)694 static inline void Gia_ManSimplifyAnd( Vec_Int_t * vSuper )
695 {
696 int i, k = 0, Prev = -1, This;
697 Vec_IntForEachEntry( vSuper, This, i )
698 {
699 if ( This == 0 )
700 { Vec_IntFill(vSuper, 1, 0); return; }
701 if ( This == 1 )
702 continue;
703 if ( Prev == -1 || Abc_Lit2Var(Prev) != Abc_Lit2Var(This) )
704 Vec_IntWriteEntry( vSuper, k++, This ), Prev = This;
705 else if ( Prev != This )
706 { Vec_IntFill(vSuper, 1, 0); return; }
707 }
708 Vec_IntShrink( vSuper, k );
709 if ( Vec_IntSize( vSuper ) == 0 )
710 Vec_IntPush( vSuper, 1 );
711 }
712
713 /**Function*************************************************************
714
715 Synopsis [Collect multi-input AND/XOR.]
716
717 Description []
718
719 SideEffects []
720
721 SeeAlso []
722
723 ***********************************************************************/
Gia_ManSuperCollectXor_rec(Gia_Man_t * p,Gia_Obj_t * pObj)724 static inline void Gia_ManSuperCollectXor_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
725 {
726 assert( !Gia_IsComplement(pObj) );
727 if ( !Gia_ObjIsXor(pObj) ||
728 // Gia_ObjRefNum(p, pObj) > 1 ||
729 Gia_ObjRefNum(p, pObj) > 3 ||
730 // (Gia_ObjRefNum(p, pObj) == 2 && (Gia_ObjRefNum(p, Gia_ObjFanin0(pObj)) == 1 || Gia_ObjRefNum(p, Gia_ObjFanin1(pObj)) == 1)) ||
731 Vec_IntSize(p->vSuper) > BAL_SUPER )
732 {
733 Vec_IntPush( p->vSuper, Gia_ObjToLit(p, pObj) );
734 return;
735 }
736 assert( !Gia_ObjFaninC0(pObj) && !Gia_ObjFaninC1(pObj) );
737 Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin0(pObj) );
738 Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin1(pObj) );
739 }
Gia_ManSuperCollectAnd_rec(Gia_Man_t * p,Gia_Obj_t * pObj)740 static inline void Gia_ManSuperCollectAnd_rec( Gia_Man_t * p, Gia_Obj_t * pObj )
741 {
742 if ( Gia_IsComplement(pObj) ||
743 !Gia_ObjIsAndReal(p, pObj) ||
744 // Gia_ObjRefNum(p, pObj) > 1 ||
745 Gia_ObjRefNum(p, pObj) > 3 ||
746 // (Gia_ObjRefNum(p, pObj) == 2 && (Gia_ObjRefNum(p, Gia_ObjFanin0(pObj)) == 1 || Gia_ObjRefNum(p, Gia_ObjFanin1(pObj)) == 1)) ||
747 Vec_IntSize(p->vSuper) > BAL_SUPER )
748 {
749 Vec_IntPush( p->vSuper, Gia_ObjToLit(p, pObj) );
750 return;
751 }
752 Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild0(pObj) );
753 Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild1(pObj) );
754 }
Gia_ManSuperCollect(Gia_Man_t * p,Gia_Obj_t * pObj)755 static inline void Gia_ManSuperCollect( Gia_Man_t * p, Gia_Obj_t * pObj )
756 {
757 // int nSize;
758 if ( p->vSuper == NULL )
759 p->vSuper = Vec_IntAlloc( 1000 );
760 else
761 Vec_IntClear( p->vSuper );
762 if ( Gia_ObjIsXor(pObj) )
763 {
764 assert( !Gia_ObjFaninC0(pObj) && !Gia_ObjFaninC1(pObj) );
765 Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin0(pObj) );
766 Gia_ManSuperCollectXor_rec( p, Gia_ObjFanin1(pObj) );
767 // nSize = Vec_IntSize(vSuper);
768 Vec_IntSort( p->vSuper, 0 );
769 Gia_ManSimplifyXor( p->vSuper );
770 // if ( nSize != Vec_IntSize(vSuper) )
771 // printf( "X %d->%d ", nSize, Vec_IntSize(vSuper) );
772 }
773 else if ( Gia_ObjIsAndReal(p, pObj) )
774 {
775 Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild0(pObj) );
776 Gia_ManSuperCollectAnd_rec( p, Gia_ObjChild1(pObj) );
777 // nSize = Vec_IntSize(vSuper);
778 Vec_IntSort( p->vSuper, 0 );
779 Gia_ManSimplifyAnd( p->vSuper );
780 // if ( nSize != Vec_IntSize(vSuper) )
781 // printf( "A %d->%d ", nSize, Vec_IntSize(vSuper) );
782 }
783 else assert( 0 );
784 // if ( nSize > 10 )
785 // printf( "%d ", nSize );
786 assert( Vec_IntSize(p->vSuper) > 0 );
787 }
788
789 /**Function*************************************************************
790
791 Synopsis []
792
793 Description []
794
795 SideEffects []
796
797 SeeAlso []
798
799 ***********************************************************************/
Gia_ManCreateGate(Gia_Man_t * pNew,Gia_Obj_t * pObj,Vec_Int_t * vSuper)800 static inline void Gia_ManCreateGate( Gia_Man_t * pNew, Gia_Obj_t * pObj, Vec_Int_t * vSuper )
801 {
802 int iLit0 = Vec_IntPop(vSuper);
803 int iLit1 = Vec_IntPop(vSuper);
804 int iLit, i;
805 if ( !Gia_ObjIsXor(pObj) )
806 iLit = Gia_ManHashAnd( pNew, iLit0, iLit1 );
807 else if ( pNew->pMuxes )
808 iLit = Gia_ManHashXorReal( pNew, iLit0, iLit1 );
809 else
810 iLit = Gia_ManHashXor( pNew, iLit0, iLit1 );
811 Vec_IntPush( vSuper, iLit );
812 Bal_ManSetGateLevel( Bal_GiaMan(pNew), pObj, iLit );
813 // Gia_ObjSetGateLevel( pNew, Gia_ManObj(pNew, Abc_Lit2Var(iLit)) );
814 // shift to the corrent location
815 for ( i = Vec_IntSize(vSuper)-1; i > 0; i-- )
816 {
817 int iLit1 = Vec_IntEntry(vSuper, i);
818 int iLit2 = Vec_IntEntry(vSuper, i-1);
819 if ( Gia_ObjLevelId(pNew, Abc_Lit2Var(iLit1)) <= Gia_ObjLevelId(pNew, Abc_Lit2Var(iLit2)) )
820 break;
821 Vec_IntWriteEntry( vSuper, i, iLit2 );
822 Vec_IntWriteEntry( vSuper, i-1, iLit1 );
823 }
824 }
Gia_ManBalanceGate(Gia_Man_t * pNew,Gia_Obj_t * pObj,Vec_Int_t * vSuper,int * pLits,int nLits)825 static inline int Gia_ManBalanceGate( Gia_Man_t * pNew, Gia_Obj_t * pObj, Vec_Int_t * vSuper, int * pLits, int nLits )
826 {
827 Vec_IntClear( vSuper );
828 if ( nLits == 1 )
829 Vec_IntPush( vSuper, pLits[0] );
830 else if ( nLits == 2 )
831 {
832 Vec_IntPush( vSuper, pLits[0] );
833 Vec_IntPush( vSuper, pLits[1] );
834 Gia_ManCreateGate( pNew, pObj, vSuper );
835 }
836 else if ( nLits > 2 )
837 {
838 Bal_Man_t * p = Bal_GiaMan(pNew); int i;
839 for ( i = 0; i < nLits; i++ )
840 Vec_IntPush( vSuper, pLits[i] );
841 // sort by level/cut-size
842 Vec_IntSelectSortCostLit( vSuper, p->vCosts );
843 // iterate till everything is grouped
844 while ( Vec_IntSize(vSuper) > 1 )
845 {
846 int iLit, Res = Bal_ManFindBestPair( p, vSuper, pObj );
847 int iBest = Vec_IntEntry( vSuper, Res >> 16 );
848 int kBest = Vec_IntEntry( vSuper, Res & 0xFFFF );
849 Vec_IntRemove( vSuper, iBest );
850 Vec_IntRemove( vSuper, kBest );
851 if ( Gia_ObjIsXor(pObj) )
852 iLit = Gia_ManHashXorReal( pNew, iBest, kBest );
853 else
854 iLit = Gia_ManHashAnd( pNew, iBest, kBest );
855 Bal_ManSetGateLevel( p, pObj, iLit );
856 Vec_IntPushOrderCost2( vSuper, p->vCosts, iLit );
857 }
858 }
859 // consider trivial case
860 assert( Vec_IntSize(vSuper) == 1 );
861 return Vec_IntEntry(vSuper, 0);
862 }
863
864 /**Function*************************************************************
865
866 Synopsis []
867
868 Description []
869
870 SideEffects []
871
872 SeeAlso []
873
874 ***********************************************************************/
Gia_ManBalance_rec(Gia_Man_t * pNew,Gia_Man_t * p,Gia_Obj_t * pObj)875 static inline void Gia_ManBalance_rec( Gia_Man_t * pNew, Gia_Man_t * p, Gia_Obj_t * pObj )
876 {
877 int i, iLit, iBeg, iEnd;
878 if ( ~pObj->Value )
879 return;
880 assert( Gia_ObjIsAnd(pObj) );
881 // handle MUX
882 if ( Gia_ObjIsMux(p, pObj) )
883 {
884 Gia_ManBalance_rec( pNew, p, Gia_ObjFanin0(pObj) );
885 Gia_ManBalance_rec( pNew, p, Gia_ObjFanin1(pObj) );
886 Gia_ManBalance_rec( pNew, p, Gia_ObjFanin2(p, pObj) );
887 pObj->Value = Gia_ManHashMuxReal( pNew, Gia_ObjFanin2Copy(p, pObj), Gia_ObjFanin1Copy(pObj), Gia_ObjFanin0Copy(pObj) );
888 Bal_ManSetGateLevel( Bal_GiaMan(pNew), pObj, pObj->Value );
889 // Gia_ObjSetGateLevel( pNew, Gia_ManObj(pNew, Abc_Lit2Var(pObj->Value)) );
890 return;
891 }
892 // find supergate
893 Gia_ManSuperCollect( p, pObj );
894 // save entries
895 if ( p->vStore == NULL )
896 p->vStore = Vec_IntAlloc( 1000 );
897 iBeg = Vec_IntSize( p->vStore );
898 Vec_IntAppend( p->vStore, p->vSuper );
899 iEnd = Vec_IntSize( p->vStore );
900 // call recursively
901 Vec_IntForEachEntryStartStop( p->vStore, iLit, i, iBeg, iEnd )
902 {
903 Gia_Obj_t * pTemp = Gia_ManObj( p, Abc_Lit2Var(iLit) );
904 Gia_ManBalance_rec( pNew, p, pTemp );
905 Vec_IntWriteEntry( p->vStore, i, Abc_LitNotCond(pTemp->Value, Abc_LitIsCompl(iLit)) );
906 }
907 assert( Vec_IntSize(p->vStore) == iEnd );
908 // consider general case
909 pObj->Value = Gia_ManBalanceGate( pNew, pObj, p->vSuper, Vec_IntEntryP(p->vStore, iBeg), iEnd-iBeg );
910 Vec_IntShrink( p->vStore, iBeg );
911 }
Gia_ManBalanceInt(Gia_Man_t * p,int nLutSize,int nCutNum,int fVerbose)912 static inline Gia_Man_t * Gia_ManBalanceInt( Gia_Man_t * p, int nLutSize, int nCutNum, int fVerbose )
913 {
914 Bal_Man_t * pMan;
915 Gia_Man_t * pNew, * pTemp;
916 Gia_Obj_t * pObj;
917 int i;
918 Gia_ManFillValue( p );
919 Gia_ManCreateRefs( p );
920 // start the new manager
921 pNew = Gia_ManStart( 3*Gia_ManObjNum(p)/2 );
922 pNew->pName = Abc_UtilStrsav( p->pName );
923 pNew->pSpec = Abc_UtilStrsav( p->pSpec );
924 pNew->pMuxes = ABC_CALLOC( unsigned, pNew->nObjsAlloc );
925 pNew->vLevels = Vec_IntStart( pNew->nObjsAlloc );
926 // create constant and inputs
927 Gia_ManConst0(p)->Value = 0;
928 Gia_ManForEachCi( p, pObj, i )
929 pObj->Value = Gia_ManAppendCi( pNew );
930 // create balancing manager
931 pMan = Bal_ManAlloc( p, pNew, nLutSize, nCutNum, fVerbose );
932 // create internal nodes
933 Gia_ManHashStart( pNew );
934 Gia_ManForEachCo( p, pObj, i )
935 Gia_ManBalance_rec( pNew, p, Gia_ObjFanin0(pObj) );
936 Gia_ManForEachCo( p, pObj, i )
937 pObj->Value = Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) );
938 // if ( fVerbose )
939 {
940 int nLevelMax = 0;
941 Gia_ManForEachCo( pNew, pObj, i )
942 {
943 nLevelMax = Abc_MaxInt( nLevelMax, Bal_ObjDelay(pMan, Gia_ObjFaninId0p(pNew, pObj)) );
944 // printf( "%d=%d ", i, Bal_ObjDelay(pMan, Gia_ObjFaninId0p(pNew, pObj)) );
945 }
946 printf( "Best delay = %d\n", nLevelMax );
947 }
948
949 // assert( Gia_ManObjNum(pNew) <= Gia_ManObjNum(p) );
950 Gia_ManHashStop( pNew );
951 Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
952 // delete manager
953 Bal_ManFree( pMan );
954 // perform cleanup
955 pNew = Gia_ManCleanup( pTemp = pNew );
956 Gia_ManStop( pTemp );
957 return pNew;
958 }
Gia_ManBalanceLut(Gia_Man_t * p,int nLutSize,int nCutNum,int fVerbose)959 Gia_Man_t * Gia_ManBalanceLut( Gia_Man_t * p, int nLutSize, int nCutNum, int fVerbose )
960 {
961 Gia_Man_t * pNew, * pNew1, * pNew2;
962 if ( fVerbose ) Gia_ManPrintStats( p, NULL );
963 pNew = Gia_ManDupMuxes( p, 2 );
964 if ( fVerbose ) Gia_ManPrintStats( pNew, NULL );
965 pNew1 = Gia_ManBalanceInt( pNew, nLutSize, nCutNum, fVerbose );
966 if ( fVerbose ) Gia_ManPrintStats( pNew1, NULL );
967 Gia_ManStop( pNew );
968 pNew2 = Gia_ManDupNoMuxes( pNew1, 0 );
969 if ( fVerbose ) Gia_ManPrintStats( pNew2, NULL );
970 Gia_ManStop( pNew1 );
971 return pNew2;
972 }
973
974
975
976 ////////////////////////////////////////////////////////////////////////
977 /// END OF FILE ///
978 ////////////////////////////////////////////////////////////////////////
979
980
981 ABC_NAMESPACE_IMPL_END
982
983