Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1098 lines
20 KiB

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
  5. *
  6. * File: tce.cpp
  7. *
  8. * File Comments:
  9. *
  10. * Transitive Comdat Elimination (TCE).
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. #define FPcodeSym(sym) ((sym).Type & IMAGE_SYM_TYPE_PCODE)
  15. PCON pconHeadGraph;
  16. PENT pentHeadImage;
  17. STATIC LHEAP lheap; // local heap for TCE allocation
  18. #define PvNew(cblk, cb) PvAllocLheap(&lheap, (cblk) * (cb))
  19. char *strdup_TCE(const char *szIn)
  20. {
  21. char *szOut = (char *) PvNew(1, strlen(szIn) + 1);
  22. strcpy(szOut, szIn);
  23. return szOut;
  24. }
  25. void
  26. Init_TCE(VOID)
  27. /*++
  28. Routine Description:
  29. Initialize the TCE engine.
  30. Return Value:
  31. None.
  32. --*/
  33. {
  34. // Initialize the local heap
  35. InitLheap(&lheap);
  36. }
  37. void
  38. Cleanup_TCE(VOID)
  39. {
  40. FreeLheap(&lheap);
  41. }
  42. void
  43. InitNodPmod(
  44. IN PMOD pmod)
  45. /*++
  46. Routine Description:
  47. Create NOD array for a module
  48. Arguments:
  49. pmod - module node in image/driver map
  50. Return Value:
  51. pointer to a new TOD
  52. --*/
  53. {
  54. pmod->rgnod = (PNOD) PvNew(pmod->ccon, sizeof(NOD));
  55. }
  56. __inline PNOD
  57. PnodPcon(
  58. PCON pcon)
  59. {
  60. PMOD pmod;
  61. PCON rgcon;
  62. PNOD pnod;
  63. assert(pcon);
  64. pmod = PmodPCON(pcon);
  65. rgcon = RgconPMOD(pmod);
  66. if ((pcon < rgcon) || (pcon > (rgcon + pmod->ccon))) {
  67. // Individually allocated CONs are followed by their NODs
  68. pnod = (PNOD) (pcon+1);
  69. } else {
  70. WORD icon;
  71. icon = (WORD) (pcon - rgcon);
  72. assert(pcon == RgconPMOD(pmod) + icon);
  73. pnod = RgnodPMOD(pmod) + icon;
  74. }
  75. return(pnod);
  76. }
  77. void
  78. InitNodPcon(
  79. PCON pcon,
  80. const char *sz,
  81. BOOL fReferenced)
  82. /*++
  83. Routine Description:
  84. Create a NOD, which is a node in the TCE graph.
  85. Arguments:
  86. pcon - contribution node in image/driver map corresponding to the NOD
  87. to be created
  88. sz - comdat name
  89. --*/
  90. {
  91. PNOD pnod;
  92. pnod = PnodPcon(pcon);
  93. if (PmodPCON(pcon) != pmodLinkerDefined) {
  94. // UNDONE: Is support for >= 64K relocs needed here?
  95. pnod->cedg = CRelocSrcPCON(pcon);
  96. if (pnod->cedg != 0) {
  97. pnod->rgedg = (PEDG) PvNew(pnod->cedg, sizeof(EDG));
  98. }
  99. }
  100. if (sz) {
  101. pnod->sz = strdup_TCE(sz);
  102. }
  103. if (fReferenced) {
  104. pcon->flags |= TCE_Referenced;
  105. }
  106. if (pconHeadGraph) {
  107. pnod->pconNext = pconHeadGraph;
  108. }
  109. pconHeadGraph = pcon;
  110. }
  111. PEDG
  112. PedgNew_TCE(
  113. DWORD isym,
  114. PCON pcon,
  115. PCON pconTarget)
  116. /*++
  117. Routine Description:
  118. Create a EDG, which is an edge in the TCE graph. If an edge is created
  119. from an external reference, then pcon will be NULL and sz will refer to
  120. the symbol name of the external. If the edge is not created from an
  121. external then the target of the reloc is assumed to be a seciton and
  122. sz will be NULL and pcon will be the pcon to resolve with.
  123. Arguments:
  124. sz - symbolic name of edge
  125. pcon - CON to add edge to
  126. pconTarget - contribution in image/driver map to resolve edge with
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. PNOD pnod;
  132. PEDG pedg;
  133. pnod = PnodPcon(pcon);
  134. while (pnod->iedg == pnod->cedg) {
  135. if (pnod->cedg == 0) {
  136. assert(pnod->rgedg == NULL);
  137. // Allocate 8 EDGs
  138. pnod->cedg = 8;
  139. pnod->rgedg = (PEDG) PvNew(8, sizeof(EDG));
  140. break;
  141. }
  142. if (pnod->pnodNext == NULL) {
  143. // Allocate a new NOD and link to end of list
  144. pnod->pnodNext = (PNOD) PvNew(1, sizeof(NOD));
  145. }
  146. pnod = pnod->pnodNext;
  147. }
  148. pedg = &pnod->rgedg[pnod->iedg];
  149. pnod->iedg++;
  150. if (pconTarget != NULL) {
  151. pedg->pcon = pconTarget;
  152. } else {
  153. pedg->Sym.isym = isym;
  154. }
  155. pedg->NEPInfo.pconPcodeNEP = NULL;
  156. return(pedg);
  157. }
  158. void
  159. ProcessRelocForTCE(
  160. PIMAGE pimage,
  161. PCON pcon,
  162. PIMAGE_SYMBOL rgsym,
  163. PIMAGE_RELOCATION prel)
  164. /*++
  165. Routine Description:
  166. Process a relocation for transitive comdat elimination. This involves
  167. creating an edge in the TCE graph for each relocation.
  168. Arguments:
  169. pcon - contribution node in image/driver map
  170. rgsym - COFF symbol table
  171. prel - COFF relocation to process
  172. Return Value:
  173. None.
  174. --*/
  175. {
  176. PMOD pmod;
  177. DWORD isym;
  178. PIMAGE_SYMBOL psym;
  179. PEDG pedg;
  180. SHORT isec;
  181. pmod = PmodPCON(pcon);
  182. isym = prel->SymbolTableIndex;
  183. psym = &rgsym[isym];
  184. if (psym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
  185. psym->StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL ||
  186. psym->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
  187. pedg = PedgNew_TCE(isym, pcon, NULL);
  188. if ((fM68K && !fRelFromMac68KPcode(prel->Type)) ||
  189. (fPowerMac && !FRelFromPpcPcode(prel->Type))) {
  190. pedg->NEPInfo.fFromNative = TRUE;
  191. }
  192. } else if ((isec = psym->SectionNumber) > 0) {
  193. PCON pconTarget = PconPMOD(pmod, isec);
  194. // If reloc is to a static pcode sym from native code, remember the NEP
  195. // comdat since it must be colored.
  196. if (FPcodeSym(*psym) &&
  197. ((fM68K && !fRelFromMac68KPcode(prel->Type)) ||
  198. (fPowerMac && !FRelFromPpcPcode(prel->Type)))) {
  199. PIMAGE_SYMBOL psymPcodeNEP = PsymAlternateStaticPcodeSym(pimage, pcon, TRUE, psym, FALSE);
  200. PCON pconPcodeNEP = PconPMOD(pmod, psymPcodeNEP->SectionNumber);
  201. // UNDONE: Why not create an edge to pconPcodeNEP and allow
  202. // UNDONE: whatever mechanism that maps from the NEP to the
  203. // UNDONE: pcode to drag in the pcode. If there is no such
  204. // UNDONE: mechanism, something should be done to create an
  205. // UNDONE: edge from the NEP to the pcode. This would allow
  206. // UNDONE: the EDG structure to be shrunk by a DWORD.
  207. pedg = PedgNew_TCE(0, pcon, pconTarget);
  208. StorepconPcodeNEP(pedg, pconPcodeNEP);
  209. } else if (pcon != pconTarget) {
  210. PedgNew_TCE(0, pcon, pconTarget);
  211. }
  212. } else {
  213. if (psym->StorageClass != IMAGE_SYM_CLASS_SECTION) {
  214. // Unrecognized fixup (might be erroneous). Ignore here, handle
  215. // elsewhere.
  216. return;
  217. }
  218. // Fixup to an undefined section symbol. This is un-COFF-like
  219. // (normally section symbols map 1-1 to the section headers, so
  220. // they always are defined)
  221. // but it can occur with imports because of the merging of
  222. // objects with the same name. For this case we ignore the
  223. // fixup because the import section will never be eliminated
  224. // by TCE.
  225. assert(psym->N.Name.Short &&
  226. strncmp(SzNameSymPst(*psym, pimage->pst), ".idata", 6) == 0);
  227. }
  228. }
  229. void
  230. MakeEdgePextFromISym(
  231. PMOD pmod)
  232. /*++
  233. Routine Description:
  234. Update the EDG structure by validating the sz field of the sym union.
  235. Before this function is called, the isym field is valid, which is the
  236. index of the symbol in the symbol table. By storing the index and
  237. later updating the string pointer we don't have multiple copies of
  238. all the symbol strings lying around. For macword in pcode (when every
  239. function generates three comdats) this will save and estimated 4 or 5
  240. Meg of RAM.
  241. Arguments:
  242. pmod - module whose contributors' edges are to be updated
  243. pst - external symbol table hash table
  244. Return Value:
  245. None.
  246. --*/
  247. {
  248. ENM_SRC enm_src;
  249. InitEnmSrc(&enm_src, pmod);
  250. // For all cons in this module...
  251. while (FNextEnmSrc(&enm_src)) {
  252. PCON pcon;
  253. PNOD pnod;
  254. ENM_EDG enm_edg;
  255. pcon = enm_src.pcon;
  256. if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
  257. // Ignore removed sections
  258. continue;
  259. }
  260. pnod = PnodPcon(pcon);
  261. // And for all edges in each con, validate the pext field of the
  262. // Sym union.
  263. InitEnmEdg(&enm_edg, pnod);
  264. while (FNextEnmEdg(&enm_edg)) {
  265. PEDG pedg;
  266. pedg = enm_edg.pedg;
  267. if (pedg->pcon == NULL) {
  268. pedg->Sym.pext = rgpExternObj[pedg->Sym.isym];
  269. assert(pedg->Sym.pext);
  270. }
  271. }
  272. }
  273. }
  274. PENT
  275. PentNew_TCE(
  276. const char *sz,
  277. PEXTERNAL pext,
  278. PCON pcon,
  279. PPENT ppentHead)
  280. /*++
  281. Routine Description:
  282. Create a ENT, which is an entry point to the TCE graph. One and only one
  283. of {sz, pext, pcon} must be !NULL.
  284. Arguments:
  285. sz - name of entry point to TCE graph
  286. pext - external for entry point
  287. pcon - contribution of entry point to graph
  288. ppentHead - head entry point in list
  289. Return Value:
  290. None.
  291. --*/
  292. {
  293. PENT pent;
  294. assert(( sz && !pext && !pcon) ||
  295. (!sz && pext && !pcon) ||
  296. (!sz && !pext && pcon));
  297. assert(ppentHead);
  298. pent = (PENT) PvNew(1, sizeof(ENT));
  299. if (sz) {
  300. pent->sz = sz;
  301. pent->e = TCE_sz;
  302. } else if (pext) {
  303. pent->pext = pext;
  304. pent->e = TCE_ext;
  305. } else if (pcon) {
  306. pent->pcon = pcon;
  307. pent->e = TCE_con;
  308. }
  309. if (*ppentHead) {
  310. pent->pentNext = *ppentHead;
  311. }
  312. *ppentHead = pent;
  313. return(pent);
  314. }
  315. void
  316. CreateGraph_TCE(
  317. PST pst)
  318. /*++
  319. Routine Description:
  320. Walk the NOD adjacency list and resolve symbolic edges.
  321. Arguments:
  322. pst - external symbol table hash table
  323. pcodHead - head CON in TCE graph
  324. Return Value:
  325. None.
  326. --*/
  327. {
  328. ENM_NOD enm_nod;
  329. InitEnmNod(&enm_nod, pconHeadGraph);
  330. while (FNextEnmNod(&enm_nod)) {
  331. PNOD pnod;
  332. ENM_EDG enm_edg;
  333. pnod = enm_nod.pnod;
  334. InitEnmEdg(&enm_edg, pnod);
  335. while (FNextEnmEdg(&enm_edg)) {
  336. PEDG pedg;
  337. pedg = enm_edg.pedg;
  338. if (pedg->pcon == NULL) {
  339. PEXTERNAL pext;
  340. pext = pedg->Sym.pext;
  341. assert(pext != NULL);
  342. if ((pext->Flags & EXTERN_DEFINED) == 0) {
  343. pedg->pcon = NULL;
  344. } else {
  345. pedg->pcon = pext->pcon;
  346. // If reloc is to a pcode sym from native code, remember
  347. // the NEP comdat since it must be colored.
  348. if ((fM68K || fPowerMac) && pedg->NEPInfo.fFromNative) {
  349. if (FPcodeSym(pext->ImageSymbol)) {
  350. PEXTERNAL pextNEP = FindExtAlternatePcodeSym(pext, pst, FALSE);
  351. if (pextNEP == NULL && fPowerMac && READ_BIT(pext, sy_WEAKEXT)) {
  352. PEXTERNAL extSymWeakPtr = PextWeakDefaultFind(pext);
  353. assert (extSymWeakPtr);
  354. pextNEP = FindExtAlternatePcodeSym(extSymWeakPtr, pst, FALSE);
  355. }
  356. assert(pextNEP);
  357. assert(pextNEP->pcon);
  358. StorepconPcodeNEP(pedg, pextNEP->pcon);
  359. } else {
  360. pedg->NEPInfo.fFromNative = FALSE;
  361. }
  362. }
  363. }
  364. }
  365. }
  366. }
  367. }
  368. void
  369. ColorPCON(
  370. PCON pcon)
  371. /*++
  372. Routine Description:
  373. Color a NOD's corresponding CON referenced and recurse through the graph.
  374. Arguments:
  375. pcon - node in TCE graph
  376. Return Value:
  377. None.
  378. --*/
  379. {
  380. assert(pcon);
  381. if ((pcon->flags & TCE_Referenced) == 0) {
  382. PNOD pnod;
  383. ENM_EDG enm_edg;
  384. pcon->flags |= TCE_Referenced;
  385. pnod = PnodPcon(pcon);
  386. InitEnmEdg(&enm_edg, pnod);
  387. while (FNextEnmEdg(&enm_edg)) {
  388. PEDG pedg;
  389. pedg = enm_edg.pedg;
  390. if (pedg->pcon != NULL) {
  391. ColorPCON(pedg->pcon);
  392. }
  393. if ((fM68K || fPowerMac) && (pedg->NEPInfo.pconPcodeNEP != NULL)) {
  394. assert(fPCodeInApp);
  395. ColorPCON(pedg->NEPInfo.pconPcodeNEP);
  396. }
  397. }
  398. }
  399. }
  400. void
  401. WalkGraphEntryPoints_TCE(
  402. PENT pentHead,
  403. PST pst)
  404. /*++
  405. Routine Description:
  406. Walk the TCE graph starting at each entry point.
  407. Arguments:
  408. pent - set of entry points
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. ENM_ENT enm_ent;
  414. PEXTERNAL pext;
  415. PENT pent;
  416. PCON pconT;
  417. InitEnmEnt(&enm_ent, pentHead);
  418. while (FNextEnmEnt(&enm_ent)) {
  419. pent = enm_ent.pent;
  420. switch (pent->e) {
  421. case TCE_con:
  422. pconT = pent->pcon;
  423. break;
  424. case TCE_ext:
  425. assert(pent->pext);
  426. if (pent->pext->Flags & EXTERN_DEFINED) {
  427. pconT = pent->pext->pcon;
  428. } else {
  429. // This only happens if -force so we are deliberately
  430. // ignoring unresolved externals ...
  431. pconT = NULL;
  432. }
  433. break;
  434. case TCE_sz:
  435. pext = SearchExternSz(pst, pent->sz);
  436. assert(pext);
  437. pconT = pext->pcon;
  438. break;
  439. default:
  440. assert(0);
  441. break;
  442. }
  443. if (pconT != NULL) {
  444. ColorPCON(pconT);
  445. }
  446. }
  447. }
  448. BOOL
  449. FDiscardPCON_TCE(
  450. PCON pcon)
  451. /*++
  452. Routine Description:
  453. Decide whether to discard a contribution.
  454. Arguments:
  455. pcon - contribution in image/driver map
  456. Return Value:
  457. !0 if we are to discard node, 0 otherwise.
  458. --*/
  459. {
  460. if (pcon->flags & TCE_Referenced) {
  461. return(0);
  462. }
  463. return(1);
  464. }
  465. void
  466. DisplayDiscardedPcon(
  467. PCON pcon,
  468. PNOD pnod)
  469. /*++
  470. Routine Description:
  471. Write to standard out what code will not be included in the image that
  472. would have been had TCE not been invoked.
  473. Arguments:
  474. pnod - head node of TCE graph
  475. Return Value:
  476. None.
  477. --*/
  478. {
  479. UINT MsgNumber;
  480. const char *sz;
  481. char *szOutput;
  482. if (pnod == NULL) {
  483. pnod = PnodPcon(pcon);
  484. }
  485. sz = pnod->sz;
  486. if (sz != NULL) {
  487. MsgNumber = TCESYM;
  488. szOutput = SzOutputSymbolName(sz, TRUE);
  489. } else if (PsecPCON(pcon) != psecDebug) {
  490. MsgNumber = TCEGRP;
  491. sz = szOutput = pcon->pgrpBack->szName;
  492. } else {
  493. szOutput = NULL;
  494. }
  495. if (szOutput != NULL) {
  496. fputs(" ", stdout);
  497. if (PmodPCON(pcon) != pmodLinkerDefined) {
  498. char szBuf[_MAX_PATH * 2];
  499. Message(MsgNumber, szOutput, SzComNamePMOD(PmodPCON(pcon), szBuf));
  500. } else {
  501. assert(MsgNumber == TCESYM);
  502. Message(TCESYMNOMOD, sz);
  503. }
  504. if (szOutput != sz) {
  505. FreePv(szOutput);
  506. }
  507. }
  508. }
  509. void
  510. Verbose_TCE(
  511. VOID)
  512. /*++
  513. Routine Description:
  514. Write to standard out what code will not be included in the image that
  515. would have been had TCE not been invoked.
  516. Arguments:
  517. pnod - head node of TCE graph
  518. Return Value:
  519. None.
  520. --*/
  521. {
  522. ENM_NOD enm_nod;
  523. InitEnmNod(&enm_nod, pconHeadGraph);
  524. while (FNextEnmNod(&enm_nod)) {
  525. PCON pcon;
  526. PNOD pnod;
  527. pcon = enm_nod.pcon;
  528. pnod = enm_nod.pnod;
  529. if (FDiscardPCON_TCE(pcon)) {
  530. DisplayDiscardedPcon(pcon, pnod);
  531. DBEXEC(DB_TCE_DISCARD, DumpPNOD_TCE(pcon, pnod));
  532. }
  533. }
  534. }
  535. /*++
  536. Routine Description:
  537. TCE adjacency list enumerator.
  538. Arguments:
  539. None.
  540. Return Value:
  541. None.
  542. --*/
  543. INIT_ENM(Nod, NOD, (ENM_NOD *penm, PCON pcon)) {
  544. penm->pcon = pcon;
  545. penm->pnod = NULL;
  546. }
  547. NEXT_ENM(Nod, NOD) {
  548. if (penm->pnod != NULL) {
  549. penm->pcon = penm->pnod->pconNext;
  550. }
  551. if (penm->pcon == NULL) {
  552. return(FALSE);
  553. }
  554. penm->pnod = PnodPcon(penm->pcon);
  555. return(TRUE);
  556. }
  557. END_ENM(Nod, NOD) {
  558. }
  559. DONE_ENM
  560. /*++
  561. Routine Description:
  562. TCE graph adjacency edge enumerator.
  563. Arguments:
  564. None.
  565. Return Value:
  566. None.
  567. --*/
  568. INIT_ENM(Edg, EDG, (ENM_EDG *penm, PNOD pnod)) {
  569. assert(penm);
  570. penm->pnod = pnod;
  571. penm->pedg = NULL;
  572. penm->iedg = 0;
  573. }
  574. NEXT_ENM(Edg, EDG) {
  575. assert(penm);
  576. assert(penm->pnod);
  577. assert(penm->pnod->iedg <= penm->pnod->cedg);
  578. penm->pedg = NULL;
  579. if (penm->iedg == penm->pnod->iedg) {
  580. if (penm->pnod->pnodNext == NULL) {
  581. return(FALSE);
  582. }
  583. penm->pnod = penm->pnod->pnodNext;
  584. penm->iedg = 0;
  585. }
  586. if (penm->iedg < penm->pnod->iedg) {
  587. penm->pedg = &penm->pnod->rgedg[penm->iedg];
  588. penm->iedg++;
  589. }
  590. return(penm->pedg != NULL);
  591. }
  592. END_ENM(Edg, EDG) {
  593. }
  594. DONE_ENM
  595. /*++
  596. Routine Description:
  597. TCE graph entry points enumerator.
  598. Arguments:
  599. None.
  600. Return Value:
  601. None.
  602. --*/
  603. INIT_ENM(Ent, ENT, (ENM_ENT *penm, PENT pent)) {
  604. assert(penm);
  605. penm->pentStart = pent;
  606. penm->pent = NULL;
  607. }
  608. NEXT_ENM(Ent, ENT) {
  609. assert(penm);
  610. if (!penm->pent) {
  611. penm->pent = penm->pentStart;
  612. } else {
  613. penm->pent = penm->pent->pentNext;
  614. }
  615. return(penm->pent != NULL);
  616. }
  617. END_ENM(Ent, ENT) {
  618. }
  619. DONE_ENM
  620. void StorepconPcodeNEP(PEDG pedg, PCON pconPcodeNEP)
  621. /*++
  622. Routine Description:
  623. Stores pconPcodeNEP in the pedg structure. This field will later be
  624. used to color the NEP comdat if the pcode symbol is referenced from
  625. native.
  626. Arguments:
  627. pedg - Points to the edg structure to be updated.
  628. pconPcodeNEP - Points to the NEP comdat.
  629. Return Value:
  630. None.
  631. --*/
  632. {
  633. assert(pedg);
  634. assert(pconPcodeNEP);
  635. pedg->NEPInfo.pconPcodeNEP = pconPcodeNEP;
  636. }
  637. #if DBG
  638. const char *
  639. SzRefPCON (
  640. PCON pcon)
  641. /*++
  642. Routine Description:
  643. Output either 'referenced' or 'not referenced'.
  644. Arguments:
  645. pcon - node in TCE graph to check
  646. Return Value:
  647. 'referenced' if pnod was referenced, 'not referenced' otherwise.
  648. --*/
  649. {
  650. static const char * const rgsz[2] = {
  651. "R",
  652. "N"};
  653. assert(pcon);
  654. return((pcon->flags & TCE_Referenced) ? rgsz[0] : rgsz[1]);
  655. }
  656. void
  657. DumpPNOD_TCE(
  658. PCON pcon,
  659. PNOD pnod)
  660. /*++
  661. Routine Description:
  662. Dump a PNOD to standard out. This routine is not #ifndef'ed since it is
  663. used in a release build when -verbose and TCE are on.
  664. Arguments:
  665. pnod - node in TCE graph to dump
  666. Return Value:
  667. None.
  668. --*/
  669. {
  670. assert(pcon != NULL);
  671. assert(pnod != NULL);
  672. DBPRINT("%s", SzRefPCON(pcon));
  673. DBPRINT("|sec=%.8s", PsecPCON(pcon)->szName);
  674. assert(pcon->pgrpBack);
  675. DBPRINT("|grp=%.8s", pcon->pgrpBack->szName);
  676. DBPRINT("|con=0x%p", pcon);
  677. assert(PsecPCON(pcon));
  678. DBPRINT("|mod=%s", SzObjNamePCON(pcon));
  679. if (pnod->sz) {
  680. DBPRINT("|%s", pnod->sz);
  681. }
  682. DBPRINT("\n");
  683. }
  684. void
  685. DumpPEDG_TCE(
  686. PEDG pedg)
  687. /*++
  688. Routine Description:
  689. Dump a PEDG to standard out.
  690. Arguments:
  691. pedg - edge in TCE graph to dump
  692. Return Value:
  693. None.
  694. --*/
  695. {
  696. assert(pedg != NULL);
  697. if (pedg->pcon != NULL) {
  698. DumpPNOD_TCE(pedg->pcon, PnodPcon(pedg->pcon));
  699. }
  700. }
  701. void
  702. DumpGraph_TCE(
  703. VOID)
  704. /*++
  705. Routine Description:
  706. Dump the TCE graph to standard out.
  707. Arguments:
  708. pconHead - root of adjacency list representation of TCE graph
  709. Return Value:
  710. None.
  711. --*/
  712. {
  713. ENM_NOD enm_nod;
  714. DBPRINT("Dump of comdat dependency graph for TCE\n");
  715. DBPRINT("---------------------------------------\n");
  716. InitEnmNod(&enm_nod, pconHeadGraph);
  717. while (FNextEnmNod(&enm_nod)) {
  718. PCON pcon;
  719. PNOD pnod;
  720. ENM_EDG enm_edg;
  721. pcon = enm_nod.pcon;
  722. pnod = enm_nod.pnod;
  723. DBPRINT("PNOD|");
  724. DumpPNOD_TCE(pcon, pnod);
  725. InitEnmEdg(&enm_edg, pnod);
  726. while (FNextEnmEdg(&enm_edg)) {
  727. PEDG pedg;
  728. pedg = enm_edg.pedg;
  729. DBPRINT(" PEDG|");
  730. DumpPEDG_TCE(pedg);
  731. }
  732. DBPRINT("\n");
  733. }
  734. fflush(stdout);
  735. }
  736. #endif // DBG