home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 June (DVD) / DPPRO0605DVD.iso / dotNETSDK / SETUP.EXE / netfxsd1.cab / FL_genIL_cpp________.3643236F_FC70_11D3_A536_0090278A1BB8 < prev    next >
Encoding:
Text File  |  2001-09-10  |  192.2 KB  |  7,443 lines

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. #include "genIL.h"
  7.  
  8. #include <float.h>
  9.  
  10. /*****************************************************************************/
  11. #ifndef __SMC__
  12.  
  13. extern
  14. ILencoding          ILopcodeCodes[];
  15. extern
  16. signed  char        ILopcodeStack[];
  17.  
  18. #if     DISP_IL_CODE
  19. extern
  20. const   char *      opcodeNames[];
  21. #endif
  22.  
  23. #endif//__SMC__
  24. /*****************************************************************************
  25.  *
  26.  *  The max. size of each "blob" of MSIL opcodes is given by the following value.
  27.  */
  28.  
  29. const
  30. size_t              genBuffSize = 1000;
  31.  
  32. /*****************************************************************************
  33.  *
  34.  *  We need to patch the "ptr" flavors of loads/stores to
  35.  *  use I8 instead of I4 in 64-bit mode.
  36.  */
  37.  
  38. #ifndef __SMC__
  39. extern
  40. unsigned            opcodesIndLoad[];
  41. extern
  42. unsigned            opcodesIndStore[];
  43. extern
  44. unsigned            opcodesArrLoad[];
  45. extern
  46. unsigned            opcodesArrStore[];
  47. #endif
  48.  
  49. /*****************************************************************************
  50.  *
  51.  *  Initialize the MSIL generator.
  52.  */
  53.  
  54. bool                genIL::genInit(Compiler comp, WritePE writer, norls_allocator *alloc)
  55. {
  56.     genComp     = comp;
  57.     genAlloc    = alloc;
  58.     genPEwriter = writer;
  59.  
  60.     genBuffAddr = (BYTE *)comp->cmpAllocPerm.nraAlloc(genBuffSize);
  61.  
  62.     genTempLabInit();
  63.     genTempVarInit();
  64.  
  65.     genStrPoolInit();
  66.  
  67.     if  (genComp->cmpConfig.ccTgt64bit)
  68.     {
  69.         assert(opcodesIndLoad [TYP_PTR] == CEE_LDIND_I4);
  70.                opcodesIndLoad [TYP_PTR] =  CEE_LDIND_I8;
  71.         assert(opcodesIndStore[TYP_PTR] == CEE_STIND_I4);
  72.                opcodesIndStore[TYP_PTR] =  CEE_STIND_I8;
  73.         assert(opcodesArrLoad [TYP_PTR] == CEE_LDELEM_I4);
  74.                opcodesArrLoad [TYP_PTR] =  CEE_LDELEM_I8;
  75.         assert(opcodesArrStore[TYP_PTR] == CEE_STELEM_I4);
  76.                opcodesArrStore[TYP_PTR] =  CEE_STELEM_I8;
  77.     }
  78.  
  79.     return  false;
  80. }
  81.  
  82. /*****************************************************************************
  83.  *
  84.  *  Shutdown the MSIL generator.
  85.  */
  86.  
  87. void                genIL::genDone(bool errors)
  88. {
  89.     /* If we had no errors, it's worth finishing the job */
  90.  
  91.     if  (!errors)
  92.     {
  93.         size_t          strSize;
  94.  
  95.         /* Allocate space for the string pool */
  96.  
  97.         strSize = genStrPoolSize();
  98.  
  99.         /* Did we have any strings? */
  100.  
  101.         if  (strSize)
  102.         {
  103.             memBuffPtr      strBuff;
  104.  
  105.             /* Allocate the space in the appropriate section of the PE file */
  106.  
  107.             genPEwriter->WPEallocString(strSize, sizeof(wchar), strBuff);
  108.  
  109.             /* Output the contents of the string pool */
  110.  
  111.             genStrPoolWrt(strBuff);
  112.         }
  113.     }
  114.  
  115.     genTempVarDone();
  116. }
  117.  
  118. /*****************************************************************************
  119.  *
  120.  *  Return a methoddef/ref for the given function symbol.
  121.  */
  122.  
  123. mdToken             genIL::genMethodRef(SymDef fncSym, bool isVirt)
  124. {
  125.     if  (fncSym->sdIsImport)
  126.     {
  127.         if  (!fncSym->sdFnc.sdfMDfnref)
  128.         {
  129.             assert(fncSym->sdReferenced == false);
  130.                    fncSym->sdReferenced = true;
  131.  
  132.             genComp->cmpMakeMDimpFref(fncSym);
  133.         }
  134.  
  135.          assert(fncSym->sdFnc.sdfMDfnref);
  136.         return  fncSym->sdFnc.sdfMDfnref;
  137.     }
  138.     else
  139.     {
  140.         if  (!fncSym->sdFnc.sdfMDtoken)
  141.         {
  142.             assert(fncSym->sdReferenced == false);
  143.                    fncSym->sdReferenced = true;
  144.  
  145.             genComp->cmpGenFncMetadata(fncSym);
  146.         }
  147.  
  148.          assert(fncSym->sdFnc.sdfMDtoken);
  149.         return  fncSym->sdFnc.sdfMDtoken;
  150.     }
  151. }
  152.  
  153. /*****************************************************************************
  154.  *
  155.  *  Return a methodref for the given function type (this is used to generate
  156.  *  signatures for an indirect function calls).
  157.  */
  158.  
  159. mdToken             genIL::genInfFncRef(TypDef fncTyp, TypDef thisArg)
  160. {
  161.     assert(fncTyp->tdTypeKind == TYP_FNC);
  162.  
  163.     if  (!fncTyp->tdFnc.tdfPtrSig)
  164.     {
  165.         genComp->cmpGenSigMetadata(fncTyp, thisArg);
  166.         assert(fncTyp->tdFnc.tdfPtrSig);
  167.     }
  168.  
  169.     return  fncTyp->tdFnc.tdfPtrSig;
  170. }
  171.  
  172. /*****************************************************************************
  173.  *
  174.  *  Generate a signature for a varargs call that has extra arguments.
  175.  */
  176.  
  177. mdToken             genIL::genVarargRef(SymDef fncSym, Tree call)
  178. {
  179.     TypDef          fncTyp = fncSym->sdType;
  180.     unsigned        fixCnt;
  181.     Tree            argExp;
  182.  
  183.     assert(call->tnOper == TN_FNC_SYM);
  184.     assert(call->tnFlags & TNF_CALL_VARARG);
  185.  
  186.     /* Find the first "extra" argument */
  187.  
  188.     assert(fncTyp->tdTypeKind == TYP_FNC);
  189.  
  190.     argExp = call->tnFncSym.tnFncArgs; assert(argExp);
  191.     fixCnt = fncTyp->tdFnc.tdfArgs.adCount;
  192.  
  193.     while (fixCnt)
  194.     {
  195.         assert(argExp && argExp->tnOper == TN_LIST);
  196.  
  197.         argExp = argExp->tnOp.tnOp2;
  198.         fixCnt--;
  199.     }
  200.  
  201.     /* force a methodref to be created */
  202.  
  203.     if  (!argExp)
  204.     {
  205.         argExp = call->tnFncSym.tnFncArgs->tnOp.tnOp1; assert(argExp->tnOper != TN_LIST);
  206.     }
  207.  
  208.     assert(argExp);
  209.  
  210.     return  genComp->cmpGenFncMetadata(fncSym, argExp);
  211. }
  212.  
  213. /*****************************************************************************
  214.  *
  215.  *  Return a memberdef/ref for the given static data member.
  216.  */
  217.  
  218. mdToken             genIL::genMemberRef(SymDef fldSym)
  219. {
  220.     assert(fldSym->sdSymKind == SYM_VAR);
  221.  
  222.     if  (fldSym->sdIsImport)
  223.     {
  224.         if  (!fldSym->sdVar.sdvMDsdref)
  225.         {
  226.             genComp->cmpMakeMDimpDref(fldSym);
  227.             assert(fldSym->sdVar.sdvMDsdref);
  228.         }
  229.  
  230.         return  fldSym->sdVar.sdvMDsdref;
  231.     }
  232.     else
  233.     {
  234.         if  (fldSym->sdVar.sdvGenSym && !fldSym->sdIsStatic)
  235.             fldSym = fldSym->sdVar.sdvGenSym;
  236.  
  237.         if  (!fldSym->sdVar.sdvMDtoken)
  238.         {
  239.             genComp->cmpGenFldMetadata(fldSym);
  240.             assert(fldSym->sdVar.sdvMDtoken);
  241.         }
  242.  
  243.         return  fldSym->sdVar.sdvMDtoken;
  244.     }
  245. }
  246.  
  247. /*****************************************************************************
  248.  *
  249.  *  Return a token for the specified type (for intrinsic types we return
  250.  *  a reference to the corresponding value type, such as "Integer2").
  251.  */
  252.  
  253. mdToken             genIL::genTypeRef(TypDef type)
  254. {
  255.     var_types       vtp = type->tdTypeKindGet();
  256.  
  257.     if  (vtp <= TYP_lastIntrins)
  258.     {
  259.         /* Locate the appropriate built-in value type */
  260.  
  261.         type = genComp->cmpFindStdValType(vtp);
  262.         if  (!type)
  263.             return  0;
  264.  
  265.         vtp = TYP_CLASS; assert(vtp == type->tdTypeKind);
  266.     }
  267.  
  268.     switch (vtp)
  269.     {
  270.     case TYP_REF:
  271.         type = type->tdRef.tdrBase;
  272.     case TYP_ENUM:
  273.     case TYP_CLASS:
  274.         return  genComp->cmpClsEnumToken(type);
  275.  
  276.     case TYP_ARRAY:
  277.         return  genComp->cmpArrayTpToken(type, true);
  278.  
  279.     case TYP_PTR:
  280.         return  genComp->cmpPtrTypeToken(type);
  281.  
  282.     default:
  283. #ifdef  DEBUG
  284.         printf("Type '%s': ", genStab->stIntrinsicTypeName(vtp));
  285. #endif
  286.         UNIMPL(!"unexpected type");
  287.         return 0;
  288.     }
  289. }
  290.  
  291. /*****************************************************************************
  292.  *
  293.  *  Return a token for the specified unmanaged class/struct/union type.
  294.  */
  295.  
  296. inline
  297. mdToken             genIL::genValTypeRef(TypDef type)
  298. {
  299.     return  genComp->cmpClsEnumToken(type);
  300. }
  301.  
  302. /*****************************************************************************
  303.  *
  304.  *  Return the encoding for the given MSIL opcode.
  305.  */
  306.  
  307. unsigned            genIL::genOpcodeEnc(unsigned op)
  308. {
  309.     const
  310.     ILencoding  *   opc;
  311.  
  312.     assert(op <  CEE_count);
  313.     assert(op != CEE_ILLEGAL);
  314.     assert(op != CEE_UNREACHED);
  315.  
  316.     opc = ILopcodeCodes + op;
  317.  
  318.     switch (opc->ILopcL)
  319.     {
  320.     case 1:
  321.         assert(opc->ILopc1 == 0xFF);
  322.         return opc->ILopc2;
  323.  
  324.     case 2:
  325.         UNIMPL(!"return 2-byte opcode");
  326.         return  0;
  327.  
  328.     default:
  329.         NO_WAY(!"unexpected encoding length");
  330.         return  0;
  331.     }
  332. }
  333.  
  334. /*****************************************************************************
  335.  *
  336.  *  Return the size (in bytes) of the encoding for the given MSIL opcode.
  337.  */
  338.  
  339. inline
  340. size_t              genIL::genOpcodeSiz(unsigned op)
  341. {
  342.     assert(op <  CEE_count);
  343.     assert(op != CEE_ILLEGAL);
  344.     assert(op != CEE_UNREACHED);
  345.  
  346.     return  ILopcodeCodes[op].ILopcL;
  347. }
  348.  
  349. /*****************************************************************************
  350.  *
  351.  *  The following returns the current MSIL block and offset within it.
  352.  */
  353.  
  354. ILblock             genIL::genBuffCurAddr()
  355. {
  356.     return genILblockCur;
  357. }
  358.  
  359. size_t              genIL::genBuffCurOffs()
  360. {
  361.     return genBuffNext - genBuffAddr;
  362. }
  363.  
  364. /*****************************************************************************
  365.  *
  366.  *  Given an MSIL block and offset within in, return the actual MSIL offset
  367.  *  within the function body.
  368.  */
  369.  
  370. unsigned            genIL::genCodeAddr(genericRef block, size_t offset)
  371. {
  372.     assert(((ILblock)block)->ILblkSelf == block);
  373.     return ((ILblock)block)->ILblkOffs + offset;
  374. }
  375.  
  376. /*****************************************************************************
  377.  *
  378.  *  Initialize the emit buffer logic.
  379.  */
  380.  
  381. void                genIL::genBuffInit()
  382. {
  383.     genBuffNext    = genBuffAddr;
  384.     genBuffLast    = genBuffAddr + genBuffSize - 10;
  385. }
  386.  
  387. /*****************************************************************************
  388.  *
  389.  *  Allocate and clear an MSIL block descriptor.
  390.  */
  391.  
  392. ILblock             genIL::genAllocBlk()
  393. {
  394.     ILblock         block;
  395.  
  396. #if MGDDATA
  397.  
  398.     block = new ILblock;
  399.  
  400. #else
  401.  
  402.     block =    (ILblock)genAlloc->nraAlloc(sizeof(*block));
  403.  
  404.     // ISSUE: Using memset() is simple and safe, but pretty slow....
  405.  
  406.     memset(block, 0, sizeof(*block));
  407.  
  408. #endif
  409.  
  410. //  if  ((int)genFncSym == 0xCD1474 && (int)block == 0xCF016C) forceDebugBreak();
  411.  
  412. #ifndef NDEBUG
  413.     block->ILblkSelf     = block;
  414. #endif
  415. #if DISP_IL_CODE
  416.     block->ILblkNum      = ++genILblockLabNum;
  417. #endif
  418.     block->ILblkJumpCode = CEE_NOP;
  419.  
  420.     /* Make sure the jump opcode didn't get truncated */
  421.  
  422.     assert(block->ILblkJumpCode == CEE_NOP);
  423.  
  424.     return block;
  425. }
  426.  
  427. /*****************************************************************************
  428.  *
  429.  *  Return non-zero if the current emit block is non-empty.
  430.  */
  431.  
  432. inline
  433. bool                genIL::genCurBlkNonEmpty()
  434. {
  435.     assert(genILblockCur);
  436.  
  437.     return  (bool)(genBuffNext != genBuffAddr);
  438. }
  439.  
  440. /*****************************************************************************
  441.  *
  442.  *  Return the MSIL offset of the current instruction.
  443.  */
  444.  
  445. inline
  446. size_t              genIL::genCurOffset()
  447. {
  448.     return  genILblockOffs + (genBuffNext - genBuffAddr);
  449. }
  450.  
  451. /*****************************************************************************
  452.  *
  453.  *  Start a new block of code; return a code block 'cookie' which the caller
  454.  *  promises to store with the basic block this code clump corresponds to.
  455.  */
  456.  
  457. genericRef          genIL::genBegBlock(ILblock block)
  458. {
  459.     assert(genILblockCur == NULL);
  460.  
  461.     /* Initialize the bufferring logic */
  462.  
  463.     genBuffInit();
  464.  
  465.     /* Allocate a new code block if the caller didn't supply one */
  466.  
  467.     if  (!block)
  468.     {
  469.         /* Is the previous block empty? */
  470.  
  471.         block = genILblockLast;
  472.  
  473.         if  (block->ILblkCodeSize == 0 &&
  474.              block->ILblkJumpCode == CEE_NOP)
  475.         {
  476.             /* The previous block is empty - simply 'reopen' it */
  477.  
  478.             goto GOT_BLK;
  479.         }
  480.  
  481.         block = genAllocBlk();
  482.     }
  483.  
  484. //  if ((int)block == 0x03421ff0) forceDebugBreak();
  485.  
  486.     /* Append the block to the list */
  487.  
  488.     genILblockLast->ILblkNext = block;
  489.                                 block->ILblkPrev = genILblockLast;
  490.                                                    genILblockLast = block;
  491.  
  492. GOT_BLK:
  493.  
  494.     /* The block will be the new current block */
  495.  
  496.     genILblockCur      = block;
  497.  
  498.     /* This block has no fixups yet */
  499.  
  500.     block->ILblkFixups = NULL;
  501.  
  502.     /* Record the code offset */
  503.  
  504.     block->ILblkOffs   = genILblockOffs;
  505.  
  506. //  printf("Beg MSIL block %08X\n", block);
  507.  
  508.     return block;
  509. }
  510.  
  511. /*****************************************************************************
  512.  *
  513.  *  Return a conservative estimate of the max. size of the given jump (or 0
  514.  *  if the opcode doesn't designate a jump).
  515.  */
  516.  
  517. size_t              genIL::genJumpMaxSize(unsigned opcode)
  518. {
  519.     if  (opcode == CEE_NOP || opcode == CEE_UNREACHED)
  520.     {
  521.         return  0;
  522.     }
  523.     else
  524.     {
  525.         return  5;
  526.     }
  527. }
  528.  
  529. /*****************************************************************************
  530.  *
  531.  *  Return the short form of the given jump opcode along with the smaller size.
  532.  */
  533.  
  534. unsigned            genIL::genShortenJump(unsigned opcode, size_t *newSize)
  535. {
  536.     *newSize = 2;
  537.  
  538.     if (opcode == CEE_LEAVE)
  539.         return CEE_LEAVE_S;
  540.  
  541.     assert(opcode == CEE_BEQ    ||
  542.            opcode == CEE_BNE_UN ||
  543.            opcode == CEE_BLE    ||
  544.            opcode == CEE_BLE_UN ||
  545.            opcode == CEE_BLT    ||
  546.            opcode == CEE_BLT_UN ||
  547.            opcode == CEE_BGE    ||
  548.            opcode == CEE_BGE_UN ||
  549.            opcode == CEE_BGT    ||
  550.            opcode == CEE_BGT_UN ||
  551.            opcode == CEE_BR     ||
  552.            opcode == CEE_BRTRUE ||
  553.            opcode == CEE_BRFALSE);
  554.  
  555.     /* Make sure we can get away with a simple increment */
  556.  
  557.     assert(CEE_BRFALSE+ (CEE_BR_S - CEE_BR) == CEE_BRFALSE_S);
  558.     assert(CEE_BRTRUE + (CEE_BR_S - CEE_BR) == CEE_BRTRUE_S);
  559.     assert(CEE_BEQ    + (CEE_BR_S - CEE_BR) == CEE_BEQ_S   );
  560.     assert(CEE_BNE_UN + (CEE_BR_S - CEE_BR) == CEE_BNE_UN_S);
  561.     assert(CEE_BLE    + (CEE_BR_S - CEE_BR) == CEE_BLE_S   );
  562.     assert(CEE_BLE_UN + (CEE_BR_S - CEE_BR) == CEE_BLE_UN_S);
  563.     assert(CEE_BLT    + (CEE_BR_S - CEE_BR) == CEE_BLT_S   );
  564.     assert(CEE_BLT_UN + (CEE_BR_S - CEE_BR) == CEE_BLT_UN_S);
  565.     assert(CEE_BGE    + (CEE_BR_S - CEE_BR) == CEE_BGE_S   );
  566.     assert(CEE_BGE_UN + (CEE_BR_S - CEE_BR) == CEE_BGE_UN_S);
  567.     assert(CEE_BGT    + (CEE_BR_S - CEE_BR) == CEE_BGT_S   );
  568.     assert(CEE_BGT_UN + (CEE_BR_S - CEE_BR) == CEE_BGT_UN_S);
  569.  
  570.     return  opcode + (CEE_BR_S - CEE_BR);
  571. }
  572.  
  573. /*****************************************************************************
  574.  *
  575.  *  Finish the current code block; when 'jumpCode' is not equal to CEE_NOP,
  576.  *  there is an implied jump following the block and the jump target is given
  577.  *  by 'jumpDest'.
  578.  */
  579.  
  580. ILblock             genIL::genEndBlock(unsigned jumpCode, ILblock jumpDest)
  581. {
  582.     size_t          size;
  583.     ILblock         block;
  584.  
  585.     size_t          jumpSize;
  586.  
  587.     /* Get hold of the current block */
  588.  
  589.     block = genILblockCur; assert(block);
  590.  
  591.     /* Compute the size of the block */
  592.  
  593.     size = block->ILblkCodeSize = genBuffNext - genBuffAddr;
  594.  
  595.     /* Is the block non-empty? */
  596.  
  597.     if  (size)
  598.     {
  599.         /* Allocate a more permanent home for the code */
  600.  
  601. #if MGDDATA
  602.  
  603.         BYTE    []      codeBuff;
  604.  
  605.         codeBuff = new managed BYTE[size];
  606.         UNIMPL(!"need to call arraycopy or some such");
  607.  
  608. #else
  609.  
  610.         BYTE    *       codeBuff;
  611.  
  612.         codeBuff = (BYTE *)genAlloc->nraAlloc(roundUp(size));
  613.         memcpy(codeBuff, genBuffAddr, size);
  614.  
  615. #endif
  616.  
  617.         block->ILblkCodeAddr = codeBuff;
  618.     }
  619.  
  620. #ifndef NDEBUG
  621.     genILblockCur = NULL;
  622. #endif
  623.  
  624.     /* Record the jump that follows the block */
  625.  
  626.     jumpSize = genJumpMaxSize(jumpCode);
  627.  
  628.     block->ILblkJumpCode = jumpCode;
  629.     block->ILblkJumpDest = jumpDest;
  630.     block->ILblkJumpSize = jumpSize;
  631.  
  632.     /* Make sure the jump opcode/size didn't get truncated */
  633.  
  634.     assert(block->ILblkJumpCode == jumpCode);
  635.     assert(block->ILblkJumpSize == jumpSize);
  636.  
  637.     /* Update the current code offset */
  638.  
  639.     genILblockOffs += size + block->ILblkJumpSize;
  640.  
  641.     return block;
  642. }
  643.  
  644. /*****************************************************************************
  645.  *
  646.  *  Finish the current code block, it ends with a switch opcode.
  647.  */
  648.  
  649. void                genIL::genSwitch(var_types      caseTyp,
  650.                                      unsigned       caseSpn,
  651.                                      unsigned       caseCnt,
  652.                                      __uint64       caseMin,
  653.                                      vectorTree     caseTab,
  654.                                      ILblock        caseBrk)
  655. {
  656.     size_t          size;
  657.     ILswitch        sdesc;
  658.     ILblock         block;
  659.  
  660.     /* Subtract minimum value if non-zero */
  661.  
  662.     if  (caseMin)
  663.     {
  664.         genAnyConst(caseMin, caseTyp);
  665.         genOpcode(CEE_SUB);
  666.     }
  667.  
  668.     /* End the current block and attach a switch "jump" */
  669.  
  670.     block = genEndBlock(CEE_NOP);
  671.  
  672. #if DISP_IL_CODE
  673.     genDispILinsBeg(CEE_SWITCH);
  674.     genDispILinsEnd("(%u entries)", caseCnt);
  675. #endif
  676.  
  677.     /* Allocate the switch descriptor */
  678.  
  679. #if MGDDATA
  680.     sdesc = new ILswitch;
  681. #else
  682.     sdesc =    (ILswitch)genAlloc->nraAlloc(sizeof(*sdesc));
  683. #endif
  684.  
  685.     sdesc->ILswtSpan     = caseSpn;
  686.     sdesc->ILswtCount    = caseCnt;
  687.     sdesc->ILswtTable    = caseTab;
  688.     sdesc->ILswtBreak    = caseBrk;
  689.  
  690.     /* Compute the size of the switch opcode */
  691.  
  692.     size = genOpcodeSiz(CEE_SWITCH) + (caseSpn + 1) * sizeof(int);
  693.  
  694.     /* Store the case label info in the block */
  695.  
  696.     block->ILblkJumpCode = CEE_SWITCH;
  697.     block->ILblkSwitch   = sdesc;
  698.  
  699.     /* Set the jump size of the block and update the current offset */
  700.  
  701.     block->ILblkJumpSize = size;
  702.     genILblockOffs      += size;
  703.  
  704.     /* Make sure the jump opcode/size didn't get truncated */
  705.  
  706.     assert(block->ILblkJumpCode == CEE_SWITCH);
  707.     assert(block->ILblkJumpSize == size);
  708.  
  709.     /* The switch opcode pops the value from the stack */
  710.  
  711.     genCurStkLvl--;
  712.  
  713.     /* Start a new block for code that follows */
  714.  
  715.     genBegBlock();
  716. }
  717.  
  718. /*****************************************************************************
  719.  *
  720.  *  Record a fixup for a RVA for the specified section at the current point
  721.  *  in the MSIL stream.
  722.  */
  723.  
  724. void                genIL::genILdataFix(WPEstdSects s)
  725. {
  726.     ILfixup         fix;
  727.  
  728.     // ISSUE: Should we reuse fixup entries across method codegen?
  729.  
  730. #if MGDDATA
  731.     fix = new ILfixup;
  732. #else
  733.     fix =    (ILfixup)genAlloc->nraAlloc(sizeof(*fix));
  734. #endif
  735.  
  736.     fix->ILfixOffs = genBuffCurOffs();
  737.     fix->ILfixSect = s;
  738.     fix->ILfixNext = genILblockCur->ILblkFixups;
  739.                      genILblockCur->ILblkFixups = fix;
  740. }
  741.  
  742. /*****************************************************************************
  743.  *
  744.  *  The emit buffer is full. Simply end the current block and start a new one.
  745.  */
  746.  
  747. void                genIL::genBuffFlush()
  748. {
  749.     genEndBlock(CEE_NOP);
  750.     genBegBlock();
  751. }
  752.  
  753. /*****************************************************************************
  754.  *
  755.  *  Start emitting code for a function.
  756.  */
  757.  
  758. void                genIL::genSectionBeg()
  759. {
  760.     genMaxStkLvl    =
  761.     genCurStkLvl    = 0;
  762.  
  763.     genLclCount     =
  764.     genArgCount     = 0;
  765.  
  766.     /* Create the initial block - it will remain empty */
  767.  
  768.     genILblockCur   = NULL;
  769.     genILblockList  =
  770.     genILblockLast  = genAllocBlk();
  771.  
  772.     /* Open the initial code block */
  773.  
  774.     genBegBlock();
  775. }
  776.  
  777. /*****************************************************************************
  778.  *
  779.  *  Finish emitting code for a function.
  780.  */
  781.  
  782. size_t              genIL::genSectionEnd()
  783. {
  784.     ILblock         block;
  785.     size_t          size;
  786.  
  787.     /* Close the current block */
  788.  
  789.     genEndBlock(CEE_NOP);
  790.  
  791.     /* Optimize jumps */
  792.  
  793. //  if  (optJumps)
  794. //      genOptJumps();
  795.  
  796. #if VERBOSE_BLOCKS
  797.     genDispBlocks("FINAL GEN");
  798. #endif
  799.  
  800.     /* Compute the total size of the code */
  801.  
  802.     for (block = genILblockList, size = 0;
  803.          block;
  804.          block = block->ILblkNext)
  805.     {
  806.         block->ILblkOffs = size;
  807.  
  808. //      printf("Block at %04X has size %02X\n", size, block->ILblkCodeSize);
  809.  
  810.         size += block->ILblkCodeSize;
  811.  
  812.         if      (block->ILblkJumpCode == CEE_NOP ||
  813.                  block->ILblkJumpCode == CEE_UNREACHED)
  814.         {
  815.             assert(block->ILblkJumpSize == 0);
  816.         }
  817.         else if (block->ILblkJumpCode == CEE_SWITCH)
  818.         {
  819.             // The size of a switch opcode doesn't change
  820.  
  821.             size += block->ILblkJumpSize;
  822.         }
  823.         else
  824.         {
  825.             int             dist;
  826.  
  827.             /* We need to figure out whether this can be a short jump */
  828.  
  829.             dist = block->ILblkJumpDest->ILblkOffs - (size + 2);
  830.  
  831. //          printf("Block at %08X [1]: src = %u, dst = %u, dist = %d\n", block, size + 2, block->ILblkJumpDest->ILblkOffs, dist);
  832.  
  833.             if  (dist >= -128 && dist < 128)
  834.             {
  835.                 size_t          newSize;
  836.  
  837.                 /* This jump will be a short one */
  838.  
  839.                 block->ILblkJumpCode = genShortenJump(block->ILblkJumpCode, &newSize);
  840.                 block->ILblkJumpSize = newSize;
  841.             }
  842.  
  843. //          printf("           + jump size %02X\n", block->ILblkJumpSize);
  844.  
  845.             size += block->ILblkJumpSize;
  846.         }
  847.     }
  848.  
  849.     return  size;
  850. }
  851.  
  852. /*****************************************************************************
  853.  *
  854.  *  A little helper to generate 32-bit label offsets.
  855.  */
  856.  
  857. inline
  858. BYTE    *           genIL::genJmp32(BYTE *dst, ILblock dest, unsigned offs)
  859. {
  860.     *(int *)dst = dest->ILblkOffs - offs;
  861.     return  dst + sizeof(int);
  862. }
  863.  
  864. /*****************************************************************************
  865.  *
  866.  *  Write the MSIL for the current to the given target address.
  867.  */
  868.  
  869. BYTE    *           genIL::genSectionCopy(BYTE *dst, unsigned baseRVA)
  870. {
  871.     ILblock         block;
  872.  
  873.     BYTE    *       base = dst;
  874.  
  875.     /* Change the base RVA to a simple relative section offset */
  876.  
  877.     baseRVA -= genPEwriter->WPEgetCodeBase(); assert((int)baseRVA >= 0);
  878.  
  879.     /* Walk the block list, emitting each one in turn (along with any fixups) */
  880.  
  881.     for (block = genILblockList;
  882.          block;
  883.          block = block->ILblkNext)
  884.     {
  885.         size_t          csize = block->ILblkCodeSize;
  886.  
  887. #ifdef  DEBUG
  888. //      if  (block->ILblkOffs != (unsigned)(dst - base))
  889. //          printf("block offset predicted at %04X, actual %04X\n", block->ILblkOffs, (unsigned)(dst - base));
  890. #endif
  891.  
  892.         assert(block->ILblkOffs == (unsigned)(dst - base));
  893.  
  894.         /* Copy the code for the block */
  895.  
  896. #if MGDDATA
  897.         UNIMPL(!"need to call arraycopy");
  898. #else
  899.         memcpy(dst, block->ILblkCodeAddr, csize);
  900. #endif
  901.  
  902.         /* Are there any fixups in this block? */
  903.  
  904.         if  (block->ILblkFixups)
  905.         {
  906.             unsigned        ofs;
  907.             ILfixup         fix;
  908.  
  909.             /* Compute the RVA of the block */
  910.  
  911.             ofs = baseRVA + block->ILblkOffs;
  912.  
  913.             /* Now report all the fixups for this code block */
  914.  
  915.             for (fix = block->ILblkFixups; fix; fix = fix->ILfixNext)
  916.             {
  917.  
  918. #ifdef  DEBUG
  919. //              printf("Code fixup at offset %04X for section '%s'\n",
  920. //                  ofs + fix->ILfixOffs,
  921. //                  genPEwriter->WPEsecName(fix->ILfixSect));
  922. #endif
  923.  
  924.                 genPEwriter->WPEsecAddFixup(PE_SECT_text, fix->ILfixSect,
  925.                                                           fix->ILfixOffs + ofs);
  926.             }
  927.         }
  928.  
  929.         /* Update the destination pointer */
  930.  
  931.         dst += csize;
  932.  
  933.         /* Now generate the trailing jump, if there is one */
  934.  
  935.         switch (block->ILblkJumpCode)
  936.         {
  937.         case CEE_NOP:
  938.         case CEE_UNREACHED:
  939.             break;
  940.  
  941.         case CEE_SWITCH:
  942.             {
  943.                 unsigned        opc;
  944.                 size_t          siz;
  945.  
  946.                 unsigned        base;
  947.  
  948.                 __int64         lastv;
  949.                 bool            first;
  950.  
  951.                 ILswitch        sdesc = block->ILblkSwitch;
  952.                 unsigned        count = sdesc->ILswtCount;
  953.                 vectorTree      table = sdesc->ILswtTable;
  954.                 ILblock         brklb = sdesc->ILswtBreak;
  955.                 unsigned        tlcnt = sdesc->ILswtSpan;
  956.                 unsigned        clnum;
  957.  
  958. #ifdef  DEBUG
  959.                 unsigned        tgcnt = 0;
  960. #endif
  961.  
  962.                 /* Output the opcode followed by the count */
  963.  
  964.                 opc = genOpcodeEnc(CEE_SWITCH);
  965.                 siz = genOpcodeSiz(CEE_SWITCH);
  966.  
  967.                 memcpy(dst, &opc, siz); dst += siz;
  968.                 memcpy(dst, &tlcnt, 4); dst += 4;
  969.  
  970.                 assert(siz + 4*(tlcnt+1) == block->ILblkJumpSize);
  971.  
  972.                 /* Figure out the base for the label references */
  973.  
  974.                 base = block->ILblkOffs + block->ILblkCodeSize
  975.                                         + block->ILblkJumpSize;
  976.  
  977.                 /* Now output the offsets of the case labels */
  978.  
  979.                 assert(count);
  980.  
  981.                 clnum = 0;
  982.  
  983.                 do
  984.                 {
  985.                     Tree            clabx;
  986.                     __int64         clabv;
  987.                     ILblock         label;
  988.  
  989.                     /* Grab the next case label entry */
  990.  
  991.                     clabx = table[clnum]; assert(clabx && clabx->tnOper == TN_CASE);
  992.  
  993.                     /* Get hold of the label and the case value */
  994.  
  995.                     label = clabx->tnCase.tncLabel; assert(label);
  996.                     clabx = clabx->tnCase.tncValue; assert(clabx);
  997.  
  998.                     assert(clabx->tnOper == TN_CNS_INT ||
  999.                            clabx->tnOper == TN_CNS_LNG);
  1000.  
  1001.                     clabv = (clabx->tnOper == TN_CNS_INT) ? clabx->tnIntCon.tnIconVal
  1002.                                                           : clabx->tnLngCon.tnLconVal;
  1003.  
  1004.                     /* Make sure any gaps are filled with 'break' */
  1005.  
  1006.                     if  (clnum == 0)
  1007.                     {
  1008.                         lastv = clabv;
  1009.                         first = false;
  1010.                     }
  1011.  
  1012.                     assert(clabv >= lastv);
  1013.  
  1014.                     while (clabv > lastv++)
  1015.                     {
  1016. #ifdef  DEBUG
  1017.                         tgcnt++;
  1018. #endif
  1019.                         dst = genJmp32(dst, brklb, base);
  1020.                     }
  1021.  
  1022.                     clnum++;
  1023.  
  1024. #ifdef  DEBUG
  1025.                     tgcnt++;
  1026. #endif
  1027.  
  1028.                     /* Generate the case label's address */
  1029.  
  1030.                     dst = genJmp32(dst, label, base);
  1031.                 }
  1032.                 while (--count);
  1033.  
  1034.                 assert(tgcnt == tlcnt);
  1035.             }
  1036.             break;
  1037.  
  1038.         default:
  1039.             {
  1040.                 size_t          size;
  1041.                 unsigned        jump;
  1042.                 unsigned        code;
  1043.                 int             dist;
  1044.  
  1045.                 /* This is a "simple" jump to a label */
  1046.  
  1047.                 size = block->ILblkJumpSize;
  1048.                 jump = block->ILblkJumpCode;
  1049.                 code = genOpcodeEnc(jump);
  1050.  
  1051.                 /* Compute the jump distance */
  1052.  
  1053.                 dist = block->ILblkJumpDest->ILblkOffs - (dst + size - base);
  1054.  
  1055. //              printf("Block at %08X [2]: src = %u, dst = %u, dist = %d\n", block, dst + size - base, block->ILblkJumpDest->ILblkOffs, dist);
  1056.  
  1057.                 /* Append the opcode  of the jump */
  1058.  
  1059.                 assert((code & ~0xFF) == 0); *dst++ = code;
  1060.  
  1061.                 /* Append the operand of the jump */
  1062.  
  1063.                 if  (size < 4)
  1064.                 {
  1065.                     /* This must be a short jump */
  1066.  
  1067.                     assert(jump == CEE_BR_S      ||
  1068.                            jump == CEE_BRTRUE_S  ||
  1069.                            jump == CEE_BRFALSE_S ||
  1070.                            jump == CEE_BEQ_S     ||
  1071.                            jump == CEE_BNE_UN_S  ||
  1072.                            jump == CEE_BLE_S     ||
  1073.                            jump == CEE_BLE_UN_S  ||
  1074.                            jump == CEE_BLT_S     ||
  1075.                            jump == CEE_BLT_UN_S  ||
  1076.                            jump == CEE_BGE_S     ||
  1077.                            jump == CEE_BGE_UN_S  ||
  1078.                            jump == CEE_BGT_S     ||
  1079.                            jump == CEE_BGT_UN_S  ||
  1080.                            jump == CEE_LEAVE_S);
  1081.  
  1082.                     assert(size == 2);
  1083.                     assert(dist == (signed char)dist);
  1084.                 }
  1085.                 else
  1086.                 {
  1087.                     /* This must be a long  jump */
  1088.  
  1089.                     assert(jump == CEE_BR        ||
  1090.                            jump == CEE_BRTRUE    ||
  1091.                            jump == CEE_BRFALSE   ||
  1092.                            jump == CEE_BEQ       ||
  1093.                            jump == CEE_BNE_UN    ||
  1094.                            jump == CEE_BLE       ||
  1095.                            jump == CEE_BLE_UN    ||
  1096.                            jump == CEE_BLT       ||
  1097.                            jump == CEE_BLT_UN    ||
  1098.                            jump == CEE_BGE       ||
  1099.                            jump == CEE_BGE_UN    ||
  1100.                            jump == CEE_BGT       ||
  1101.                            jump == CEE_BGT_UN    ||
  1102.                            jump == CEE_LEAVE);
  1103.  
  1104.                     assert(size == 5);
  1105.                 }
  1106.  
  1107.                 size--; memcpy(dst, &dist, size); dst += size;
  1108.             }
  1109.             break;
  1110.         }
  1111.     }
  1112.  
  1113.     return  dst;
  1114. }
  1115.  
  1116. /*****************************************************************************
  1117.  *
  1118.  *  Create a unique temporary label name.
  1119.  */
  1120.  
  1121. #if DISP_IL_CODE
  1122.  
  1123. const   char    *   genIL::genTempLabName()
  1124. {
  1125.     static
  1126.     char            temp[16];
  1127.  
  1128.     sprintf(temp, "$t%04u", ++genTempLabCnt);
  1129.  
  1130.     return  temp;
  1131. }
  1132.  
  1133. #endif
  1134.  
  1135. /*****************************************************************************
  1136.  *
  1137.  *  Check that all temps have been freed.
  1138.  */
  1139.  
  1140. #ifdef  DEBUG
  1141.  
  1142. void                genIL::genTempVarChk()
  1143. {
  1144.     unsigned        i;
  1145.  
  1146.     for (i = 0; i < TYP_COUNT; i++) assert(genTempVarCnt [i] ==    0);
  1147.     for (i = 0; i < TYP_COUNT; i++) assert(genTempVarUsed[i] == NULL);
  1148.     for (i = 0; i < TYP_COUNT; i++) assert(genTempVarFree[i] == NULL);
  1149. }
  1150.  
  1151. #endif
  1152.  
  1153. /*****************************************************************************
  1154.  *
  1155.  *  Initialize the temp tracking logic.
  1156.  */
  1157.  
  1158. void                genIL::genTempVarInit()
  1159. {
  1160.     memset(genTempVarCnt , 0, sizeof(genTempVarCnt ));
  1161.     memset(genTempVarUsed, 0, sizeof(genTempVarUsed));
  1162.     memset(genTempVarFree, 0, sizeof(genTempVarFree));
  1163. }
  1164.  
  1165. /*****************************************************************************
  1166.  *
  1167.  *  Shutdown the temp tracking logic.
  1168.  */
  1169.  
  1170. void                genIL::genTempVarDone()
  1171. {
  1172.     genTempVarChk();
  1173. }
  1174.  
  1175. /*****************************************************************************
  1176.  *
  1177.  *  Start using temps - called at the beginning of codegen for a function.
  1178.  */
  1179.  
  1180. void                genIL::genTempVarBeg(unsigned lclCnt)
  1181. {
  1182.     genTmpBase  = lclCnt;
  1183.     genTmpCount = 0;
  1184.  
  1185.     genTempList =
  1186.     genTempLast = NULL;
  1187.  
  1188.     genTempVarChk();
  1189. }
  1190.  
  1191. /*****************************************************************************
  1192.  *
  1193.  *  Finish using temps - called at the end of codegen for a function.
  1194.  */
  1195.  
  1196. void                genIL::genTempVarEnd()
  1197. {
  1198.     assert(genTmpBase == genLclCount || genComp->cmpErrorCount);
  1199.  
  1200.     memset(genTempVarFree, 0, sizeof(genTempVarFree));
  1201.  
  1202.     genTempVarChk();
  1203. }
  1204.  
  1205. /*****************************************************************************
  1206.  *
  1207.  *  Allocate a temp of the given type.
  1208.  */
  1209.  
  1210. unsigned            genIL::genTempVarGet(TypDef type)
  1211. {
  1212.     unsigned        vtp = type->tdTypeKind;
  1213.  
  1214.     unsigned        num;
  1215.     ILtemp          tmp;
  1216.  
  1217. //  printf("Creating temp of type '%s'\n", genStab->stTypeName(type, NULL));
  1218.  
  1219.     /* Map pointer temps to integers and all refs to Object */
  1220.  
  1221.     switch (vtp)
  1222.     {
  1223.     case TYP_ARRAY:
  1224.         if  (!type->tdIsManaged)
  1225.             goto UMG_PTR;
  1226.  
  1227.         // Fall through ...
  1228.  
  1229.     case TYP_REF:
  1230.         type = genComp->cmpObjectRef();
  1231.         break;
  1232.  
  1233.     case TYP_ENUM:
  1234.         type = type->tdEnum.tdeIntType;
  1235.         vtp  = type->tdTypeKind;
  1236.         break;
  1237.  
  1238.     case TYP_PTR:
  1239.     UMG_PTR:
  1240.         type = genComp->cmpTypeInt;
  1241.         vtp  = TYP_INT;
  1242.         break;
  1243.     }
  1244.  
  1245.     /* Is there a free temp available? */
  1246.  
  1247.     tmp = genTempVarFree[vtp];
  1248.  
  1249.     if  (tmp)
  1250.     {
  1251.         /* Is this a struct type? */
  1252.  
  1253.         if  (vtp == TYP_CLASS)
  1254.         {
  1255.             ILtemp          lst = NULL;
  1256.  
  1257.             /* We better get a precise match on the type */
  1258.  
  1259.             for (;;)
  1260.             {
  1261.                 ILtemp          nxt = tmp->tmpNext;
  1262.  
  1263.                 if  (symTab::stMatchTypes(tmp->tmpType, type))
  1264.                 {
  1265.                     /* Match - reuse this temp */
  1266.  
  1267.                     if  (lst)
  1268.                     {
  1269.                         lst->tmpNext = nxt;
  1270.                     }
  1271.                     else
  1272.                     {
  1273.                         genTempVarFree[vtp] = lst;
  1274.                     }
  1275.  
  1276.                     break;
  1277.                 }
  1278.  
  1279.                 /* Are there more temps to consider? */
  1280.  
  1281.                 lst = tmp;
  1282.                 tmp = nxt;
  1283.  
  1284.                 if  (!tmp)
  1285.                     goto GET_TMP;
  1286.             }
  1287.         }
  1288.         else
  1289.         {
  1290.             /* Remove the temp from the free list */
  1291.  
  1292.             genTempVarFree[vtp] = tmp->tmpNext;
  1293.         }
  1294.     }
  1295.     else
  1296.     {
  1297.         /* Here we need to allocate a new temp */
  1298.  
  1299.     GET_TMP:
  1300.  
  1301.         /* Grab a local slot# for the temp */
  1302.  
  1303.         num = genTmpBase + genTmpCount++;
  1304.  
  1305.         /* Allocate a temp descriptor */
  1306.  
  1307. #if MGDDATA
  1308.         tmp = new ILtemp;
  1309. #else
  1310.         tmp =    (ILtemp)genAlloc->nraAlloc(sizeof(*tmp));
  1311. #endif
  1312.  
  1313. #ifdef  DEBUG
  1314.         tmp->tmpSelf = tmp;
  1315. #endif
  1316.  
  1317.         /* Record the temporary number, type, etc. */
  1318.  
  1319.         tmp->tmpNum  = num;
  1320.         tmp->tmpType = type;
  1321.  
  1322.         /* Append the temp to the global temp list */
  1323.  
  1324.         tmp->tmpNxtN = NULL;
  1325.  
  1326.         if  (genTempList)
  1327.             genTempLast->tmpNxtN = tmp;
  1328.         else
  1329.             genTempList          = tmp;
  1330.  
  1331.         genTempLast = tmp;
  1332.     }
  1333.  
  1334.     /* Append the temp  to  the used list */
  1335.  
  1336.     tmp->tmpNext = genTempVarUsed[vtp];
  1337.                    genTempVarUsed[vtp] = tmp;
  1338.  
  1339.     /* Return the temp number to the caller */
  1340.  
  1341.     return  tmp->tmpNum;
  1342. }
  1343.  
  1344. /*****************************************************************************
  1345.  *
  1346.  *  Release the given temp.
  1347.  */
  1348.  
  1349. void                genIL::genTempVarRls(TypDef type, unsigned tnum)
  1350. {
  1351.     unsigned        vtp = type->tdTypeKind;
  1352.  
  1353.     ILtemp       *  ptr;
  1354.     ILtemp          tmp;
  1355.  
  1356.     switch (vtp)
  1357.     {
  1358.     case TYP_PTR:
  1359.  
  1360.         /* Map pointer temps to integers [ISSUE: is this correct?] */
  1361.  
  1362.         type = genComp->cmpTypeInt;
  1363.         vtp  = TYP_INT;
  1364.         break;
  1365.  
  1366.     case TYP_ENUM:
  1367.  
  1368.         /* Map enums to their underlying type */
  1369.  
  1370.         type = type->tdEnum.tdeIntType;
  1371.         vtp  = type->tdTypeKind;
  1372.         break;
  1373.     }
  1374.  
  1375.     /* Remove the entry from the used list */
  1376.  
  1377.     for (ptr = &genTempVarUsed[vtp];;)
  1378.     {
  1379.         tmp = *ptr; assert(tmp);
  1380.  
  1381.         if  (tmp->tmpNum == tnum)
  1382.         {
  1383.             /* Remove the temp from the used list */
  1384.  
  1385.             *ptr = tmp->tmpNext;
  1386.  
  1387.             /* Append the temp  to  the free list */
  1388.  
  1389.             tmp->tmpNext = genTempVarFree[vtp];
  1390.                            genTempVarFree[vtp] = tmp;
  1391.  
  1392.             return;
  1393.         }
  1394.  
  1395.         ptr = &tmp->tmpNext;
  1396.     }
  1397. }
  1398.  
  1399. /*****************************************************************************
  1400.  *
  1401.  *  Temp iterator: return the type of the given temp and return a cookie for
  1402.  *  the next one.
  1403.  */
  1404.  
  1405. genericRef          genIL::genTempIterNxt(genericRef iter, OUT TypDef REF typRef)
  1406. {
  1407.     ILtemp          tmp = (ILtemp)iter;
  1408.  
  1409.     assert(tmp->tmpSelf == tmp);
  1410.  
  1411.     typRef = tmp->tmpType;
  1412.  
  1413.     return  tmp->tmpNxtN;
  1414. }
  1415.  
  1416. /*****************************************************************************/
  1417. #if     DISP_IL_CODE
  1418. /*****************************************************************************/
  1419.  
  1420. const   char *  DISP_BCODE_PREFIX   = "       ";
  1421. const   int     DISP_STKLVL         =  1;       // enable for debugging of MSIL generation
  1422.  
  1423. /*****************************************************************************/
  1424.  
  1425. #ifndef __SMC__
  1426. const char *        opcodeName(unsigned op);    // moved into macros.cpp
  1427. #endif
  1428.  
  1429. /*****************************************************************************/
  1430.  
  1431. void                genIL::genDispILopc(const char *name, const char *suff)
  1432. {
  1433.     static  char    temp[128];
  1434.  
  1435.     strcpy(temp, name);
  1436.     if  (suff)
  1437.         strcat(temp, suff);
  1438.  
  1439.     printf(" %-11s   ", temp);
  1440. }
  1441.  
  1442. void                genIL::genDispILinsBeg(unsigned op)
  1443. {
  1444.     assert(op != CEE_ILLEGAL);
  1445.     assert(op != CEE_count);
  1446.  
  1447.     if  (genDispCode)
  1448.     {
  1449.         if  (DISP_STKLVL)
  1450.         {
  1451.             printf("[%04X", genCurOffset());
  1452.             if  ((int)genCurStkLvl >= 0 && genComp->cmpErrorCount == 0)
  1453.                 printf(":%2d] ", genCurStkLvl);
  1454.             else
  1455.                 printf( "   ] ");
  1456.         }
  1457.         else
  1458.             printf(DISP_BCODE_PREFIX);
  1459.  
  1460.         genDispILinsLst  = op;
  1461.  
  1462.         genDispILnext    = genDispILbuff;
  1463.         genDispILnext[0] = 0;
  1464.     }
  1465. }
  1466.  
  1467. void                genIL::genDispILins_I1(int v)
  1468. {
  1469.     if  (genComp->cmpConfig.ccDispILcd)
  1470.     {
  1471.         char            buff[8];
  1472.         sprintf(buff, "%02X ", v & 0xFF);
  1473.         strcat(genDispILnext, buff);
  1474.     }
  1475. }
  1476.  
  1477. void                genIL::genDispILins_I2(int v)
  1478. {
  1479.     if  (genComp->cmpConfig.ccDispILcd)
  1480.     {
  1481.         char            buff[8];
  1482.         sprintf(buff, "%04X ", v & 0xFFFF);
  1483.         strcat(genDispILnext, buff);
  1484.     }
  1485. }
  1486.  
  1487. void                genIL::genDispILins_I4(int v)
  1488. {
  1489.     if  (genComp->cmpConfig.ccDispILcd)
  1490.     {
  1491.         char            buff[12];
  1492.         sprintf(buff, "%08X ", v);
  1493.         strcat(genDispILnext, buff);
  1494.     }
  1495. }
  1496.  
  1497. void                genIL::genDispILins_I8(__int64 v)
  1498. {
  1499.     if  (genComp->cmpConfig.ccDispILcd)
  1500.     {
  1501.         char            buff[20];
  1502.         sprintf(buff, "%016I64X ", v);
  1503.         strcat(genDispILnext, buff);
  1504.     }
  1505. }
  1506.  
  1507. void                genIL::genDispILins_R4(float v)
  1508. {
  1509.     if  (genComp->cmpConfig.ccDispILcd)
  1510.     {
  1511.         char            buff[16];
  1512.         sprintf(buff, "%f ", v);
  1513.         strcat(genDispILnext, buff);
  1514.     }
  1515. }
  1516.  
  1517. void                genIL::genDispILins_R8(double v)
  1518. {
  1519.     if  (genComp->cmpConfig.ccDispILcd)
  1520.     {
  1521.         char            buff[20];
  1522.         sprintf(buff, "%lf ", v);
  1523.         strcat(genDispILnext, buff);
  1524.     }
  1525. }
  1526.  
  1527. void    __cdecl     genIL::genDispILinsEnd(const char *fmt, ...)
  1528. {
  1529.     if  (genDispCode)
  1530.     {
  1531.         va_list     args; va_start(args, fmt);
  1532.  
  1533.         assert(genDispILinsLst != CEE_ILLEGAL);
  1534.  
  1535.         if  (genComp->cmpConfig.ccDispILcd)
  1536.         {
  1537.             genDispILbuff[IL_OPCDSP_LEN] = 0;
  1538.  
  1539.             printf("%*s ", -(int)IL_OPCDSP_LEN, genDispILbuff);
  1540.         }
  1541.  
  1542.         genDispILopc(opcodeName(genDispILinsLst));
  1543.  
  1544.         vprintf(fmt, args);
  1545.         printf("\n");
  1546.  
  1547.         genDispILinsLst = CEE_ILLEGAL;
  1548.     }
  1549. }
  1550.  
  1551. /*****************************************************************************/
  1552. #endif//DISP_IL_CODE
  1553. /*****************************************************************************
  1554.  *
  1555.  *  The following helpers output data of various sizes / formats to the IL
  1556.  *  stream.
  1557.  */
  1558.  
  1559. inline
  1560. void                genIL::genILdata_I1(int v)
  1561. {
  1562.     if  (genBuffNext   >= genBuffLast) genBuffFlush();
  1563.  
  1564. #if DISP_IL_CODE
  1565.     genDispILins_I1(v);
  1566. #endif
  1567.  
  1568.     *genBuffNext++ = v;
  1569. }
  1570.  
  1571. inline
  1572. void                genIL::genILdata_I2(int v)
  1573. {
  1574.     if  (genBuffNext+1 >= genBuffLast) genBuffFlush();
  1575.  
  1576.     *(__int16 *)genBuffNext = v;    // WARNING: This is not endian-safe!
  1577.  
  1578. #if DISP_IL_CODE
  1579.     genDispILins_I2(v);
  1580. #endif
  1581.  
  1582.     genBuffNext += sizeof(__int16);
  1583. }
  1584.  
  1585. inline
  1586. void                genIL::genILdata_I4(int v)
  1587. {
  1588.     if  (genBuffNext+3 >= genBuffLast) genBuffFlush();
  1589.  
  1590.     *(__int32 *)genBuffNext = v;    // WARNING: This is not endian-safe!
  1591.  
  1592. #if DISP_IL_CODE
  1593.     genDispILins_I4(v);
  1594. #endif
  1595.  
  1596.     genBuffNext += sizeof(__int32);
  1597. }
  1598.  
  1599. inline
  1600. void                genIL::genILdata_R4(float v)
  1601. {
  1602.     if  (genBuffNext+3 >= genBuffLast) genBuffFlush();
  1603.  
  1604.     *(float *)genBuffNext = v;
  1605.  
  1606. #if DISP_IL_CODE
  1607.     genDispILins_R4(v);
  1608. #endif
  1609.  
  1610.     genBuffNext += sizeof(float);
  1611. }
  1612.  
  1613. inline
  1614. void                genIL::genILdata_R8(double v)
  1615. {
  1616.     if  (genBuffNext+7 >= genBuffLast) genBuffFlush();
  1617.  
  1618.     *(double *)genBuffNext = v;
  1619.  
  1620. #if DISP_IL_CODE
  1621.     genDispILins_R8(v);
  1622. #endif
  1623.  
  1624.     genBuffNext += sizeof(double);
  1625. }
  1626.  
  1627. void                genIL::genILdataStr(unsigned o)
  1628. {
  1629.     genILdataFix(PE_SECT_string);
  1630.  
  1631.     *(__int32 *)genBuffNext = o;    // WARNING: This is not endian-safe!
  1632.  
  1633. #if DISP_IL_CODE
  1634.     genDispILins_I4(o);
  1635. #endif
  1636.  
  1637.     genBuffNext += sizeof(__int32);
  1638. }
  1639.  
  1640. void                genIL::genILdataRVA(unsigned o, WPEstdSects s)
  1641. {
  1642.     if  (genBuffNext+3 >= genBuffLast) genBuffFlush();
  1643.  
  1644.     genILdataFix(s);
  1645.  
  1646.     *(__int32 *)genBuffNext = o;    // WARNING: This is not endian-safe!
  1647.  
  1648. #if DISP_IL_CODE
  1649.     genDispILins_I4(o);
  1650. #endif
  1651.  
  1652.     genBuffNext += sizeof(__int32);
  1653. }
  1654.  
  1655. void                genIL::genILdata_I8(__int64 v)
  1656. {
  1657.     if  (genBuffNext+7 >= genBuffLast) genBuffFlush();
  1658.  
  1659.     *(__int64 *)genBuffNext = v;    // WARNING: This is not endian-safe!
  1660.  
  1661. #if DISP_IL_CODE
  1662.     genDispILins_I8(v);
  1663. #endif
  1664.  
  1665.     genBuffNext += sizeof(__int64);
  1666. }
  1667.  
  1668. /*****************************************************************************
  1669.  *
  1670.  *  Generate the encoding for the given MSIL opcode.
  1671.  */
  1672.  
  1673. void                genIL::genOpcodeOper(unsigned op)
  1674. {
  1675.     const
  1676.     ILencoding  *   opc;
  1677.  
  1678.     assert(op <  CEE_count);
  1679.     assert(op != CEE_ILLEGAL);
  1680.     assert(op != CEE_UNREACHED);
  1681.  
  1682.     genCurStkLvl += ILopcodeStack[op]; genMarkStkMax();
  1683.  
  1684. #ifndef NDEBUG
  1685.     if  ((int)genCurStkLvl < 0 && !genComp->cmpErrorCount)
  1686.     {
  1687.         genDispILinsEnd("");
  1688.         NO_WAY(!"bad news, stack depth is going negative");
  1689.     }
  1690. #endif
  1691.  
  1692.     opc = ILopcodeCodes + op;
  1693.  
  1694.     switch (opc->ILopcL)
  1695.     {
  1696.     case 1:
  1697.         assert(opc->ILopc1 == 0xFF);
  1698.         genILdata_I1(opc->ILopc2);
  1699.         break;
  1700.  
  1701.     case 2:
  1702.         genILdata_I1(opc->ILopc1);
  1703.         genILdata_I1(opc->ILopc2);
  1704.         break;
  1705.  
  1706.     case 0:
  1707.         UNIMPL(!"output large opcode");
  1708.  
  1709.     default:
  1710.         NO_WAY(!"unexpected encoding length");
  1711.     }
  1712. }
  1713.  
  1714. /*****************************************************************************
  1715.  *
  1716.  *  Update the current stack level to reflect the effects of the given IL
  1717.  *  opcode.
  1718.  */
  1719.  
  1720. inline
  1721. void                genIL::genUpdateStkLvl(unsigned op)
  1722. {
  1723.     assert(op <  CEE_count);
  1724.     assert(op != CEE_ILLEGAL);
  1725.     assert(op != CEE_UNREACHED);
  1726.  
  1727.     genCurStkLvl += ILopcodeStack[op];
  1728. }
  1729.  
  1730. /*****************************************************************************
  1731.  *
  1732.  *  Generate an MSIL instruction with no operands.
  1733.  */
  1734.  
  1735. void                genIL::genOpcode(unsigned op)
  1736. {
  1737.     assert(op != CEE_NOP);
  1738.  
  1739. #if DISP_IL_CODE
  1740.     genDispILinsBeg(op);
  1741. #endif
  1742.  
  1743.     genOpcodeOper(op);
  1744.  
  1745. #if DISP_IL_CODE
  1746.     genDispILinsEnd("");
  1747. #endif
  1748. }
  1749.  
  1750. /*****************************************************************************
  1751.  *
  1752.  *  Generate an MSIL instruction with a single 8-bit signed int operand.
  1753.  */
  1754.  
  1755. void                genIL::genOpcode_I1(unsigned op, int v1)
  1756. {
  1757. #if DISP_IL_CODE
  1758.     genDispILinsBeg(op);
  1759. #endif
  1760.  
  1761.     genOpcodeOper(op);
  1762.     genILdata_I1(v1);
  1763.  
  1764. #if DISP_IL_CODE
  1765.     genDispILinsEnd("%d", v1);
  1766. #endif
  1767. }
  1768.  
  1769. /*****************************************************************************
  1770.  *
  1771.  *  Generate an MSIL instruction with a single 8-bit unsigned int operand.
  1772.  */
  1773.  
  1774. void                genIL::genOpcode_U1(unsigned op, unsigned v1)
  1775. {
  1776. #if DISP_IL_CODE
  1777.     genDispILinsBeg(op);
  1778. #endif
  1779.  
  1780.     genOpcodeOper(op);
  1781.     genILdata_I1(v1);
  1782.  
  1783. #if DISP_IL_CODE
  1784.     genDispILinsEnd("%u", v1);
  1785. #endif
  1786. }
  1787.  
  1788. /*****************************************************************************
  1789.  *
  1790.  *  Generate an MSIL instruction with a single 16-bit unsigned int operand.
  1791.  */
  1792.  
  1793. void                genIL::genOpcode_U2(unsigned op, unsigned v1)
  1794. {
  1795. #if DISP_IL_CODE
  1796.     genDispILinsBeg(op);
  1797. #endif
  1798.  
  1799.     genOpcodeOper(op);
  1800.     genILdata_I2(v1);
  1801.  
  1802. #if DISP_IL_CODE
  1803.     genDispILinsEnd("%u", v1);
  1804. #endif
  1805. }
  1806.  
  1807. /*****************************************************************************
  1808.  *
  1809.  *  Generate an MSIL instruction with a single 32-bit signed int operand.
  1810.  */
  1811.  
  1812. void                genIL::genOpcode_I4(unsigned op, int v1)
  1813. {
  1814. #if DISP_IL_CODE
  1815.     genDispILinsBeg(op);
  1816. #endif
  1817.  
  1818.     genOpcodeOper(op);
  1819.     genILdata_I4(v1);
  1820.  
  1821. #if DISP_IL_CODE
  1822.     if  (v1 < 0 || v1 >= 10)
  1823.         genDispILinsEnd("%d ; 0x%X", v1, v1);
  1824.     else
  1825.         genDispILinsEnd("%d", v1);
  1826. #endif
  1827. }
  1828.  
  1829. /*****************************************************************************
  1830.  *
  1831.  *  Generate an MSIL instruction with a single 64-bit signed int operand.
  1832.  */
  1833.  
  1834. void                genIL::genOpcode_I8(unsigned op, __int64 v1)
  1835. {
  1836. #if DISP_IL_CODE
  1837.     genDispILinsBeg(op);
  1838. #endif
  1839.  
  1840.     genOpcodeOper(op);
  1841.     genILdata_I8(v1);
  1842.  
  1843. #if DISP_IL_CODE
  1844.     genDispILinsEnd("%Ld", v1);
  1845. #endif
  1846. }
  1847.  
  1848. /*****************************************************************************
  1849.  *
  1850.  *  Generate an MSIL instruction with a 'float' operand.
  1851.  */
  1852.  
  1853. void                genIL::genOpcode_R4(unsigned op, float v1)
  1854. {
  1855. #if DISP_IL_CODE
  1856.     genDispILinsBeg(op);
  1857. #endif
  1858.  
  1859.     genOpcodeOper(op);
  1860.     genILdata_R4(v1);
  1861.  
  1862. #if DISP_IL_CODE
  1863.     genDispILinsEnd("%f", v1);
  1864. #endif
  1865. }
  1866.  
  1867. /*****************************************************************************
  1868.  *
  1869.  *  Generate an MSIL instruction with a 'double' operand.
  1870.  */
  1871.  
  1872. void                genIL::genOpcode_R8(unsigned op, double v1)
  1873. {
  1874. #if DISP_IL_CODE
  1875.     genDispILinsBeg(op);
  1876. #endif
  1877.  
  1878.     genOpcodeOper(op);
  1879.     genILdata_R8(v1);
  1880.  
  1881. #if DISP_IL_CODE
  1882.     genDispILinsEnd("%lf", v1);
  1883. #endif
  1884. }
  1885.  
  1886. /*****************************************************************************
  1887.  *
  1888.  *  Generate an MSIL instruction with a token operand.
  1889.  */
  1890.  
  1891. void                genIL::genOpcode_tok(unsigned op, mdToken tok)
  1892. {
  1893. #if DISP_IL_CODE
  1894.     genDispILinsBeg(op);
  1895. #endif
  1896.  
  1897.     genOpcodeOper(op);
  1898.     genILdata_I4(tok);
  1899.  
  1900. #if DISP_IL_CODE
  1901.     genDispILinsEnd("tok[%04X]", tok);
  1902. #endif
  1903. }
  1904.  
  1905. /*****************************************************************************
  1906.  *
  1907.  *  Generate an MSIL instruction with a RVA operand.
  1908.  */
  1909.  
  1910. void                genIL::genOpcode_RVA(unsigned op, WPEstdSects sect,
  1911.                                                       unsigned    offs)
  1912. {
  1913. #if DISP_IL_CODE
  1914.     genDispILinsBeg(op);
  1915. #endif
  1916.  
  1917.     genOpcodeOper(op);
  1918.     genILdataRVA(offs, sect);
  1919.  
  1920. #if DISP_IL_CODE
  1921.     genDispILinsEnd("[%s + 0x%04X]", genPEwriter->WPEsecName(sect), offs);
  1922. #endif
  1923. }
  1924.  
  1925. /*****************************************************************************
  1926.  *
  1927.  *  Generate an MSIL instruction with a string operand.
  1928.  */
  1929.  
  1930. void                genIL::genOpcode_str(unsigned op, unsigned offs)
  1931. {
  1932. #if DISP_IL_CODE
  1933.     genDispILinsBeg(op);
  1934. #endif
  1935.  
  1936.     genOpcodeOper(op);
  1937.     genILdataStr(offs);
  1938.  
  1939.     // The caller is required to call genDispILinsEnd(), since only
  1940.     // he knows whether the string is ANSI or Unicode.
  1941. }
  1942.  
  1943. /*****************************************************************************
  1944.  *
  1945.  *  Generate an opcode if it's not a NOP.
  1946.  */
  1947.  
  1948. void                genIL::genOpcodeNN(unsigned op)
  1949. {
  1950.     if  (op != CEE_NOP)
  1951.         genOpcode(op);
  1952. }
  1953.  
  1954. /*****************************************************************************/
  1955. #if DISP_IL_CODE
  1956.  
  1957. const   char *      genIL::genDspLabel(ILblock lab)
  1958. {
  1959.     if  (genDispCode)
  1960.     {
  1961.         assert(lab->ILblkNum);
  1962.  
  1963.         static  char    temp[16];
  1964.         sprintf(temp, "L_%02u", lab->ILblkNum);        // watch out: static buffer!
  1965.         return  temp;
  1966.     }
  1967.     else
  1968.         return NULL;
  1969. }
  1970.  
  1971. void                genIL::genDspLabDf(ILblock lab)
  1972. {
  1973.     if  (genDispCode)
  1974.     {
  1975.         if  (!(lab->ILblkFlags & ILBF_LABDEF))
  1976.         {
  1977.             if  (genComp->cmpConfig.ccDispILcd)
  1978.                 printf("%*s ", IL_OPCDSP_LEN, "");
  1979.  
  1980.             printf("%s:\n", genDspLabel(lab));
  1981.  
  1982.             lab->ILblkFlags |= ILBF_LABDEF;
  1983.         }
  1984.     }
  1985. }
  1986.  
  1987. #endif//DISP_IL_CODE
  1988. /*****************************************************************************
  1989.  *
  1990.  *  Return a block that can be used to make jump references to the current
  1991.  *  position.
  1992.  */
  1993.  
  1994. ILblock             genIL::genBwdLab()
  1995. {
  1996.     /* Is the current block non-empty? */
  1997.  
  1998.     if  (genCurBlkNonEmpty())
  1999.     {
  2000.         /* End the current block and start a new one */
  2001.  
  2002.         genEndBlock(CEE_NOP);
  2003.         genBegBlock();
  2004.     }
  2005.  
  2006. #if DISP_IL_CODE
  2007.     genDspLabDf(genILblockCur);
  2008. #endif
  2009.  
  2010.     return  genILblockCur;
  2011. }
  2012.  
  2013. /*****************************************************************************
  2014.  *
  2015.  *  Define the given forward reference block as being the current position.
  2016.  */
  2017.  
  2018. void                genIL::genFwdLabDef(ILblock block)
  2019. {
  2020.     assert(block);
  2021.  
  2022.     genEndBlock(CEE_NOP);
  2023.  
  2024. #if DISP_IL_CODE
  2025.     genDspLabDf(block);
  2026. #endif
  2027.  
  2028.     genBegBlock(block);
  2029. }
  2030.  
  2031. /*****************************************************************************
  2032.  *
  2033.  *  Generate an MSIL instruction with a jump target (label) operand.
  2034.  */
  2035.  
  2036. void                genIL::genOpcode_lab(unsigned op, ILblock lab)
  2037. {
  2038.     assert(lab);
  2039.  
  2040. #if DISP_IL_CODE
  2041.     genDispILinsBeg(op);
  2042.     genDispILinsEnd("%s", genDspLabel(lab));
  2043. #endif
  2044.  
  2045.     genUpdateStkLvl(op);
  2046.  
  2047.     genEndBlock(op, lab);
  2048.     genBegBlock();
  2049. }
  2050.  
  2051. /*****************************************************************************
  2052.  *
  2053.  *  Generate an integer constant value.
  2054.  */
  2055.  
  2056. void                genIL::genIntConst(__int32 val)
  2057. {
  2058.     if  (val >= -128 && val < 128)
  2059.     {
  2060.         if  (val >= -1 && val <= 8)
  2061.         {
  2062.             static
  2063.             unsigned        constOpc[] =
  2064.             {
  2065.                 CEE_LDC_I4_M1,
  2066.                 CEE_LDC_I4_0,
  2067.                 CEE_LDC_I4_1,
  2068.                 CEE_LDC_I4_2,
  2069.                 CEE_LDC_I4_3,
  2070.                 CEE_LDC_I4_4,
  2071.                 CEE_LDC_I4_5,
  2072.                 CEE_LDC_I4_6,
  2073.                 CEE_LDC_I4_7,
  2074.                 CEE_LDC_I4_8,
  2075.             };
  2076.  
  2077.             genOpcode(constOpc[val+1]);
  2078.         }
  2079.         else
  2080.         {
  2081.             genOpcode_I1(CEE_LDC_I4_S, val);
  2082.         }
  2083.     }
  2084.     else
  2085.         genOpcode_I4(CEE_LDC_I4, val);
  2086. }
  2087.  
  2088. /*****************************************************************************
  2089.  *
  2090.  *  Generate a 64-bit integer constant value.
  2091.  */
  2092.  
  2093. inline
  2094. void                genIL::genLngConst(__int64 val)
  2095. {
  2096.     genOpcode_I8(CEE_LDC_I8, val);
  2097. }
  2098.  
  2099. /*****************************************************************************
  2100.  *
  2101.  *  Generate a small integral constant value with the given type.
  2102.  */
  2103.  
  2104. void                genIL::genAnyConst(__int64 val, var_types vtp)
  2105. {
  2106.     switch (vtp)
  2107.     {
  2108.     default:
  2109.         genIntConst((__int32)val);
  2110.         return;
  2111.  
  2112.     case TYP_LONG:
  2113.     case TYP_ULONG:
  2114.         genLngConst(         val);
  2115.         return;
  2116.  
  2117.     case TYP_FLOAT:
  2118.         genOpcode_R4(CEE_LDC_R4, (  float)val);
  2119.         return;
  2120.  
  2121.     case TYP_DOUBLE:
  2122.     case TYP_LONGDBL:
  2123.         genOpcode_R8(CEE_LDC_R8, ( double)val);
  2124.         return;
  2125.     }
  2126. }
  2127.  
  2128. /*****************************************************************************
  2129.  *
  2130.  *  Returns the local variable / argument index of the given variable.
  2131.  */
  2132.  
  2133. inline
  2134. unsigned            genIL::genGetLclIndex(SymDef varSym)
  2135. {
  2136.     assert(varSym->sdSymKind == SYM_VAR);
  2137.     assert(varSym->sdVar.sdvLocal);
  2138.     assert(varSym->sdParent->sdSymKind == SYM_FNC ||
  2139.            varSym->sdParent->sdSymKind == SYM_SCOPE);
  2140.  
  2141. #ifdef  DEBUG
  2142.  
  2143.     if      (varSym->sdVar.sdvArgument)
  2144.     {
  2145.         assert(varSym->sdVar.sdvILindex <  genArgCount);
  2146.     }
  2147.     else if (varSym->sdIsImplicit)
  2148.     {
  2149.         assert(varSym->sdVar.sdvILindex >= genTmpBase);
  2150.         assert(varSym->sdVar.sdvILindex <  genTmpBase + genTmpCount);
  2151.     }
  2152.     else
  2153.     {
  2154.         assert(varSym->sdVar.sdvILindex <  genLclCount);
  2155.     }
  2156.  
  2157. #endif
  2158.  
  2159.     return varSym->sdVar.sdvILindex;
  2160. }
  2161.  
  2162. /*****************************************************************************
  2163.  *
  2164.  *  Generate load/store of a local variable/argument.
  2165.  */
  2166.  
  2167. inline
  2168. void                genIL::genLclVarRef(SymDef varSym, bool store)
  2169. {
  2170.     unsigned        index;
  2171.  
  2172.     assert(varSym);
  2173.     assert(varSym->sdSymKind == SYM_VAR);
  2174.  
  2175.     index = genGetLclIndex(varSym);
  2176.  
  2177.     if  (varSym->sdVar.sdvArgument)
  2178.         genArgVarRef(index, store);
  2179.     else
  2180.         genLclVarRef(index, store);
  2181. }
  2182.  
  2183. /*****************************************************************************
  2184.  *
  2185.  *  Generate the address of a local variable/argument.
  2186.  */
  2187.  
  2188. void                genIL::genLclVarAdr(SymDef varSym)
  2189. {
  2190.     unsigned        index;
  2191.  
  2192.     assert(varSym);
  2193.     assert(varSym->sdSymKind == SYM_VAR);
  2194.  
  2195.     index = genGetLclIndex(varSym);
  2196.  
  2197.     if  (varSym->sdVar.sdvArgument)
  2198.     {
  2199.         //  Check for reference arguments
  2200.  
  2201.         if  (index < 256)
  2202.             genOpcode_U1(CEE_LDARGA_S, index);
  2203.         else
  2204.             genOpcode_I4(CEE_LDARGA  , index);
  2205.     }
  2206.     else
  2207.     {
  2208.         if  (index < 256)
  2209.             genOpcode_U1(CEE_LDLOCA_S, index);
  2210.         else
  2211.             genOpcode_I4(CEE_LDLOCA  , index);
  2212.     }
  2213. }
  2214.  
  2215. /*****************************************************************************
  2216.  *
  2217.  *  Generate the address of a local variable.
  2218.  */
  2219.  
  2220. inline
  2221. void                genIL::genLclVarAdr(unsigned slot)
  2222. {
  2223.     if  (slot < 256)
  2224.         genOpcode_U1(CEE_LDLOCA_S, slot);
  2225.     else
  2226.         genOpcode_I4(CEE_LDLOCA  , slot);
  2227. }
  2228.  
  2229. /*****************************************************************************
  2230.  *
  2231.  *  Unfortunately, the compiler is too lazy to convert all tree nodes that
  2232.  *  have enum type to have the actual underlying integer types, so we do
  2233.  *  this here.
  2234.  */
  2235.  
  2236. inline
  2237. var_types           genIL::genExprVtyp(Tree expr)
  2238. {
  2239.     var_types       vtp = expr->tnVtypGet();
  2240.  
  2241.     if  (vtp == TYP_ENUM)
  2242.         vtp = genComp->cmpActualVtyp(expr->tnType);
  2243.  
  2244.     return  vtp;
  2245. }
  2246.  
  2247. /*****************************************************************************
  2248.  *
  2249.  *  Returns the reverse of a comparison operator.
  2250.  */
  2251.  
  2252. static  treeOps     revRel[] =
  2253. {
  2254.     TN_NE,          // TN_EQ
  2255.     TN_EQ,          // TN_NE
  2256.     TN_GE,          // TN_LT
  2257.     TN_GT,          // TN_LE
  2258.     TN_LT,          // TN_GE
  2259.     TN_LE,          // TN_GT
  2260. };
  2261.  
  2262. /*****************************************************************************
  2263.  *
  2264.  *  Map a relational tree node operator to the corresponding MSIL opcode that
  2265.  *  will branch when the condition is satisfied.
  2266.  */
  2267.  
  2268. static  unsigned    relToOpcSgn[] =
  2269. {
  2270.     CEE_BEQ,        // TN_EQ
  2271.     CEE_BNE_UN,     // TN_NE
  2272.     CEE_BLT,        // TN_LT
  2273.     CEE_BLE,        // TN_LE
  2274.     CEE_BGE,        // TN_GE
  2275.     CEE_BGT,        // TN_GT
  2276. };
  2277.  
  2278. static  unsigned    relToOpcUns[] =
  2279. {
  2280.     CEE_BEQ,        // TN_EQ
  2281.     CEE_BNE_UN,     // TN_NE
  2282.     CEE_BLT_UN,     // TN_LT
  2283.     CEE_BLE_UN,     // TN_LE
  2284.     CEE_BGE_UN,     // TN_GE
  2285.     CEE_BGT_UN,     // TN_GT
  2286. };
  2287.  
  2288. /*****************************************************************************
  2289.  *
  2290.  *  Map a relational tree node operator to the corresponding MSIL opcode that
  2291.  *  will compute (materialize) the value of the condition.
  2292.  */
  2293.  
  2294. struct  cmpRelDsc
  2295. {
  2296.     unsigned short      crdOpcode;
  2297.     unsigned char       crdNegate;
  2298. };
  2299.  
  2300. static  cmpRelDsc   relToMopSgn[] =
  2301. {
  2302.   { CEE_CEQ   , 0 },// TN_EQ
  2303.   { CEE_CEQ   , 1 },// TN_NE
  2304.   { CEE_CLT   , 0 },// TN_LT
  2305.   { CEE_CGT   , 1 },// TN_LE
  2306.   { CEE_CLT   , 1 },// TN_GE
  2307.   { CEE_CGT   , 0 },// TN_GT
  2308. };
  2309.  
  2310. static  cmpRelDsc   relToMopUns[] =
  2311. {
  2312.   { CEE_CEQ   , 0 },// TN_EQ
  2313.   { CEE_CEQ   , 1 },// TN_NE
  2314.   { CEE_CLT_UN, 0 },// TN_LT
  2315.   { CEE_CGT_UN, 1 },// TN_LE
  2316.   { CEE_CLT_UN, 1 },// TN_GE
  2317.   { CEE_CGT_UN, 0 },// TN_GT
  2318. };
  2319.  
  2320. /*****************************************************************************
  2321.  *
  2322.  *  Generate code that will jump to 'labTrue' if 'op1 <relOper> op2' is 'sense'.
  2323.  */
  2324.  
  2325. void                genIL::genRelTest(Tree cond, Tree op1,
  2326.                                                  Tree op2, int      sense,
  2327.                                                            ILblock  labTrue)
  2328. {
  2329.     unsigned    *   relTab;
  2330.  
  2331.     treeOps         relOper = cond->tnOperGet();
  2332.     treeOps         orgOper = relOper;
  2333.  
  2334.     var_types       vtp = genExprVtyp(op1);
  2335.  
  2336.     /* Reverse the comparison, if appropriate */
  2337.  
  2338.     if  (!sense)
  2339.     {
  2340.         relOper = revRel[relOper - TN_EQ];
  2341.         cond->tnFlags ^= TNF_REL_NANREV;
  2342.     }
  2343.  
  2344.     /* Both operands should have the same type */
  2345.  
  2346. #ifdef DEBUG
  2347.     if  (op1->tnVtypGet() != op2->tnVtypGet())
  2348.     {
  2349.         printf("\n"); genComp->cmpParser->parseDispTree(op1);
  2350.         printf("\n"); genComp->cmpParser->parseDispTree(op2);
  2351.     }
  2352. #endif
  2353.  
  2354.     assert(op1->tnVtypGet() == op2->tnVtypGet());
  2355.  
  2356.     genExpr(op1, true);
  2357.     genExpr(op2, true);
  2358.  
  2359.     assert(relToOpcSgn[TN_EQ - TN_EQ] == CEE_BEQ);
  2360.     assert(relToOpcSgn[TN_NE - TN_EQ] == CEE_BNE_UN);
  2361.     assert(relToOpcSgn[TN_LT - TN_EQ] == CEE_BLT);
  2362.     assert(relToOpcSgn[TN_LE - TN_EQ] == CEE_BLE);
  2363.     assert(relToOpcSgn[TN_GE - TN_EQ] == CEE_BGE);
  2364.     assert(relToOpcSgn[TN_GT - TN_EQ] == CEE_BGT);
  2365.  
  2366.     assert(relToOpcUns[TN_EQ - TN_EQ] == CEE_BEQ);
  2367.     assert(relToOpcUns[TN_NE - TN_EQ] == CEE_BNE_UN);
  2368.     assert(relToOpcUns[TN_LT - TN_EQ] == CEE_BLT_UN);
  2369.     assert(relToOpcUns[TN_LE - TN_EQ] == CEE_BLE_UN);
  2370.     assert(relToOpcUns[TN_GE - TN_EQ] == CEE_BGE_UN);
  2371.     assert(relToOpcUns[TN_GT - TN_EQ] == CEE_BGT_UN);
  2372.  
  2373.     if  (varTypeIsUnsigned(vtp))
  2374.     {
  2375.         relTab = relToOpcUns;
  2376.     }
  2377.     else if (varTypeIsFloating(vtp) && (cond->tnFlags & TNF_REL_NANREV))
  2378.     {
  2379.         relTab = relToOpcUns;
  2380.     }
  2381.     else
  2382.         relTab = relToOpcSgn;
  2383.  
  2384.     assert(relOper - TN_EQ < arraylen(relToOpcUns));
  2385.     assert(relOper - TN_EQ < arraylen(relToOpcSgn));
  2386.  
  2387.     genOpcode_lab(relTab[relOper - TN_EQ], labTrue);
  2388. }
  2389.  
  2390. /*****************************************************************************
  2391.  *
  2392.  *  Generate code that will test the given expression for non-zero and jump
  2393.  *  to the appropriate label.
  2394.  */
  2395.  
  2396. void                genIL::genExprTest(Tree            expr,
  2397.                                        int             sense,
  2398.                                        int             genJump, ILblock labTrue,
  2399.                                                                 ILblock labFalse)
  2400. {
  2401.     /* Just in case we'll want to generate line# info for the condition */
  2402.  
  2403. //  genRecordExprAddr(expr);
  2404.  
  2405. AGAIN:
  2406.  
  2407.     /* Is the condition a short-circuit or relational operator? */
  2408.  
  2409.     switch (expr->tnOper)
  2410.     {
  2411.         Tree            oper;
  2412.         ILblock         labTmp;
  2413.  
  2414.     case TN_LOG_OR:
  2415.  
  2416.         /*
  2417.             For a test of an "||" condition, we generate the following:
  2418.  
  2419.                     <op1>
  2420.                     JccTrue  labTrue
  2421.             tmpFalse:
  2422.                     <op2>
  2423.          */
  2424.  
  2425.         labTmp = genFwdLabGet();
  2426.  
  2427.         if  (sense)
  2428.             genExprTest(expr->tnOp.tnOp1, true, true, labTrue , labTmp);
  2429.         else
  2430.             genExprTest(expr->tnOp.tnOp1, true, true, labFalse, labTmp);
  2431.  
  2432.     SC_FIN:
  2433.  
  2434.         genFwdLabDef(labTmp);
  2435.  
  2436.         if  (genJump)
  2437.         {
  2438.             expr = expr->tnOp.tnOp2;
  2439.             goto AGAIN;
  2440.         }
  2441.  
  2442.         genExpr(expr->tnOp.tnOp2, true);
  2443.         break;
  2444.  
  2445.     case TN_LOG_AND:
  2446.  
  2447.         /*
  2448.             For a test of an "&&" condition, we generate the following:
  2449.  
  2450.                     <op1>
  2451.                     JccFalse labFalse
  2452.             tmpTrue:
  2453.                     <op2>
  2454.          */
  2455.  
  2456.         labTmp = genFwdLabGet();
  2457.  
  2458.         if  (sense)
  2459.             genExprTest(expr->tnOp.tnOp1, false, true, labFalse, labTmp);
  2460.         else
  2461.             genExprTest(expr->tnOp.tnOp1, false, true, labTrue , labTmp);
  2462.  
  2463.         goto SC_FIN;
  2464.  
  2465.     case TN_LOG_NOT:
  2466.  
  2467.         /* Logical negation: "flip" the sense of the comparison and repeat */
  2468.  
  2469.         oper = expr->tnOp.tnOp1;
  2470.  
  2471.         expr->tnFlags &= ~TNF_REL_NANREV;
  2472.         expr->tnFlags |= (oper->tnFlags & TNF_REL_NANREV) ^ TNF_REL_NANREV;
  2473.  
  2474.         expr   = oper;
  2475.         sense  = !sense;
  2476.         goto AGAIN;
  2477.  
  2478.     case TN_EQ:
  2479.     case TN_NE:
  2480.  
  2481.         if  (!genJump)
  2482.             break;
  2483.  
  2484.         if  ((expr->tnOp.tnOp2->tnOper == TN_CNS_INT &&
  2485.               expr->tnOp.tnOp2->tnIntCon.tnIconVal == 0) ||
  2486.               expr->tnOp.tnOp2->tnOper == TN_NULL)
  2487.         {
  2488.             if  (expr->tnOper == TN_EQ)
  2489.                 sense ^= 1;
  2490.  
  2491.             genExpr(expr->tnOp.tnOp1, true);
  2492.             genOpcode_lab(sense ? CEE_BRTRUE : CEE_BRFALSE, labTrue);
  2493.             return;
  2494.         }
  2495.  
  2496.         // Fall through ....
  2497.  
  2498.     case TN_LE:
  2499.     case TN_GE:
  2500.     case TN_LT:
  2501.     case TN_GT:
  2502.  
  2503.         if  (!genJump)
  2504.             break;
  2505.  
  2506.         genRelTest(expr, expr->tnOp.tnOp1,
  2507.                          expr->tnOp.tnOp2, sense, labTrue);
  2508.         return;
  2509.  
  2510.     case TN_ISTYPE:
  2511.  
  2512.         assert(expr->tnOp.tnOp2->tnOper == TN_NONE);
  2513.  
  2514.         genExpr(expr->tnOp.tnOp1, true);
  2515.         genOpcode_tok(CEE_ISINST, genTypeRef(expr->tnOp.tnOp2->tnType));
  2516.         genOpcode_lab(sense ? CEE_BRTRUE : CEE_BRFALSE, labTrue);
  2517.         return;
  2518.  
  2519.     case TN_COMMA:
  2520.         genExpr(expr->tnOp.tnOp1, false);
  2521.         expr = expr->tnOp.tnOp2;
  2522.         goto AGAIN;
  2523.  
  2524.     default:
  2525.         genExpr(expr, true);
  2526.         break;
  2527.     }
  2528.  
  2529.     /* Generate the final jump, if the caller requested it */
  2530.  
  2531.     if  (genJump)
  2532.     {
  2533.         genOpcode_lab(sense ? CEE_BRTRUE
  2534.                             : CEE_BRFALSE, labTrue);
  2535.     }
  2536. }
  2537.  
  2538. /*****************************************************************************
  2539.  *
  2540.  *  Create a temporary label; test the expression 'pt' for zero/non-zero,
  2541.  *  and jump to that temporary label if the expression is logically equal
  2542.  *  to 'sense'. Return the temporary label to the caller for further use.
  2543.  */
  2544.  
  2545. ILblock             genIL::genTestCond(Tree cond, bool sense)
  2546. {
  2547.     ILblock         labYo;
  2548.     ILblock         labNo;
  2549.  
  2550.     /* We'll need 2 labels, one of them will be returned to the caller */
  2551.  
  2552.     labYo = genFwdLabGet();
  2553.     labNo = genFwdLabGet();
  2554.  
  2555.     genExprTest(cond, sense, true, labYo, labNo);
  2556.  
  2557.     genFwdLabDef(labNo);
  2558.  
  2559.     return labYo;
  2560. }
  2561.  
  2562. /*****************************************************************************
  2563.  *
  2564.  *  Generate the address of the given global variable (static data members
  2565.  *  of unmanaged classes are also acceptable).
  2566.  */
  2567.  
  2568. void                genIL::genGlobalAddr(Tree expr)
  2569. {
  2570.     SymDef          sym;
  2571.  
  2572.     /* Get hold of the variable symbol */
  2573.  
  2574.     assert(expr->tnOper == TN_VAR_SYM);
  2575.  
  2576.     sym = expr->tnVarSym.tnVarSym; assert(sym->sdSymKind == SYM_VAR);
  2577.  
  2578.     /* Generate the side effects in the object expression */
  2579.  
  2580.     if  (expr->tnVarSym.tnVarObj)
  2581.         genSideEff(expr->tnVarSym.tnVarObj);
  2582.  
  2583.     /* Make sure the variable has been assigned an address */
  2584.  
  2585.     if  (!sym->sdVar.sdvAllocated)
  2586.         genComp->cmpAllocGlobVar(sym);
  2587.  
  2588.     /* Push the address of the global variable */
  2589.  
  2590.     genOpcode_tok(CEE_LDSFLDA, genMemberRef(sym));
  2591. }
  2592.  
  2593. /*****************************************************************************
  2594.  *
  2595.  *  Generate the address given by an address expression and a constant offset.
  2596.  */
  2597.  
  2598. void                genIL::genAddr(Tree addr, unsigned offs)
  2599. {
  2600.     genExpr(addr, true);
  2601.  
  2602.     if  (offs)
  2603.     {
  2604.         genIntConst(offs);
  2605.         genOpcode(CEE_ADD);
  2606.     }
  2607. }
  2608.  
  2609. /*****************************************************************************
  2610.  *
  2611.  *  Opcodes to load/store various types of values from various locations.
  2612.  */
  2613.  
  2614. static
  2615. unsigned            opcodesIndLoad[] =
  2616. {
  2617.     /* UNDEF   */  CEE_ILLEGAL,
  2618.     /* VOID    */  CEE_ILLEGAL,
  2619.     /* BOOL    */  CEE_LDIND_I1,
  2620.     /* WCHAR   */  CEE_LDIND_U2,
  2621.     /* CHAR    */  CEE_LDIND_I1,
  2622.     /* UCHAR   */  CEE_LDIND_U1,
  2623.     /* SHORT   */  CEE_LDIND_I2,
  2624.     /* USHORT  */  CEE_LDIND_U2,
  2625.     /* INT     */  CEE_LDIND_I4,
  2626.     /* UINT    */  CEE_LDIND_U4,
  2627.     /* NATINT  */  CEE_LDIND_I,
  2628.     /* NATUINT */  CEE_LDIND_I,
  2629.     /* LONG    */  CEE_LDIND_I8,
  2630.     /* ULONG   */  CEE_LDIND_I8,
  2631.     /* FLOAT   */  CEE_LDIND_R4,
  2632.     /* DOUBLE  */  CEE_LDIND_R8,
  2633.     /* LONGDBL */  CEE_LDIND_R8,
  2634.     /* REFANY  */  CEE_ILLEGAL,
  2635.     /* ARRAY   */  CEE_LDIND_REF,   // is this correct?
  2636.     /* CLASS   */  CEE_ILLEGAL,
  2637.     /* FNC     */  CEE_ILLEGAL,
  2638.     /* REF     */  CEE_LDIND_REF,
  2639.     /* PTR     */  CEE_LDIND_I4,
  2640. };
  2641.  
  2642. static
  2643. unsigned            opcodesIndStore[] =
  2644. {
  2645.     /* UNDEF   */  CEE_ILLEGAL,
  2646.     /* VOID    */  CEE_ILLEGAL,
  2647.     /* BOOL    */  CEE_STIND_I1,
  2648.     /* WCHAR   */  CEE_STIND_I2,
  2649.     /* CHAR    */  CEE_STIND_I1,
  2650.     /* UCHAR   */  CEE_STIND_I1,
  2651.     /* SHORT   */  CEE_STIND_I2,
  2652.     /* USHORT  */  CEE_STIND_I2,
  2653.     /* INT     */  CEE_STIND_I4,
  2654.     /* UINT    */  CEE_STIND_I4,
  2655.     /* NATINT  */  CEE_STIND_I,
  2656.     /* NATUINT */  CEE_STIND_I,
  2657.     /* LONG    */  CEE_STIND_I8,
  2658.     /* ULONG   */  CEE_STIND_I8,
  2659.     /* FLOAT   */  CEE_STIND_R4,
  2660.     /* DOUBLE  */  CEE_STIND_R8,
  2661.     /* LONGDBL */  CEE_STIND_R8,
  2662.     /* REFANY  */  CEE_ILLEGAL,
  2663.     /* ARRAY   */  CEE_STIND_REF,
  2664.     /* CLASS   */  CEE_ILLEGAL,
  2665.     /* FNC     */  CEE_ILLEGAL,
  2666.     /* REF     */  CEE_STIND_REF,
  2667.     /* PTR     */  CEE_STIND_I4,
  2668. };
  2669.  
  2670. static
  2671. unsigned            opcodesArrLoad[] =
  2672. {
  2673.     /* UNDEF   */  CEE_ILLEGAL,
  2674.     /* VOID    */  CEE_ILLEGAL,
  2675.     /* BOOL    */  CEE_LDELEM_I1,
  2676.     /* WCHAR   */  CEE_LDELEM_U2,
  2677.     /* CHAR    */  CEE_LDELEM_I1,
  2678.     /* UCHAR   */  CEE_LDELEM_U1,
  2679.     /* SHORT   */  CEE_LDELEM_I2,
  2680.     /* USHORT  */  CEE_LDELEM_U2,
  2681.     /* INT     */  CEE_LDELEM_I4,
  2682.     /* UINT    */  CEE_LDELEM_U4,
  2683.     /* NATINT  */  CEE_LDELEM_I,
  2684.     /* NATUINT */  CEE_LDELEM_I,
  2685.     /* LONG    */  CEE_LDELEM_I8,
  2686.     /* ULONG   */  CEE_LDELEM_I8,
  2687.     /* FLOAT   */  CEE_LDELEM_R4,
  2688.     /* DOUBLE  */  CEE_LDELEM_R8,
  2689.     /* LONGDBL */  CEE_LDELEM_R8,
  2690.     /* REFANY  */  CEE_ILLEGAL,
  2691.     /* ARRAY   */  CEE_LDELEM_REF,
  2692.     /* CLASS   */  CEE_ILLEGAL,
  2693.     /* FNC     */  CEE_ILLEGAL,
  2694.     /* REF     */  CEE_LDELEM_REF,
  2695.     /* PTR     */  CEE_LDELEM_I4,
  2696. };
  2697.  
  2698. static
  2699. unsigned            opcodesArrStore[] =
  2700. {
  2701.     /* UNDEF   */  CEE_ILLEGAL,
  2702.     /* VOID    */  CEE_ILLEGAL,
  2703.     /* BOOL    */  CEE_STELEM_I1,
  2704.     /* WCHAR   */  CEE_STELEM_I2,
  2705.     /* CHAR    */  CEE_STELEM_I1,
  2706.     /* UCHAR   */  CEE_STELEM_I1,
  2707.     /* SHORT   */  CEE_STELEM_I2,
  2708.     /* USHORT  */  CEE_STELEM_I2,
  2709.     /* INT     */  CEE_STELEM_I4,
  2710.     /* UINT    */  CEE_STELEM_I4,
  2711.     /* NATINT  */  CEE_STELEM_I,
  2712.     /* NATUINT */  CEE_STELEM_I,
  2713.     /* LONG    */  CEE_STELEM_I8,
  2714.     /* ULONG   */  CEE_STELEM_I8,
  2715.     /* FLOAT   */  CEE_STELEM_R4,
  2716.     /* DOUBLE  */  CEE_STELEM_R8,
  2717.     /* LONGDBL */  CEE_STELEM_R8,
  2718.     /* REFANY  */  CEE_ILLEGAL,
  2719.     /* ARRAY   */  CEE_STELEM_REF,
  2720.     /* CLASS   */  CEE_ILLEGAL,
  2721.     /* FNC     */  CEE_ILLEGAL,
  2722.     /* REF     */  CEE_STELEM_REF,
  2723.     /* PTR     */  CEE_STELEM_I4,
  2724. };
  2725.  
  2726. /*****************************************************************************
  2727.  *
  2728.  *  Generate the address part of an lvalue (for example, if the lvalue is a
  2729.  *  member, generate the address of the object). Returns the number of items
  2730.  *  that comprise the address (0 for non-members, 1 for members, 2 for array
  2731.  *  members).
  2732.  *
  2733.  *  Note that sometimes we need to take the address of something that doesn't
  2734.  *  have one, in which case we introduce a temp and use its address (hard to
  2735.  *  believe, but it does happen with method calls on intrinsic values). It is
  2736.  *  extremely important to keep the function genCanTakeAddr() below in synch
  2737.  *  with the kinds of expressions genAdr(expr, true) will accept.
  2738.  */
  2739.  
  2740. unsigned            genIL::genAdr(Tree expr, bool compute)
  2741. {
  2742.     switch (expr->tnOper)
  2743.     {
  2744.         SymDef          sym;
  2745.         TypDef          typ;
  2746.  
  2747.         unsigned        xcnt;
  2748.  
  2749.     case TN_LCL_SYM:
  2750.  
  2751.         if  (compute)
  2752.         {
  2753.             genLclVarAdr(expr->tnLclSym.tnLclSym);
  2754.             return  1;
  2755.         }
  2756.         break;
  2757.  
  2758.     case TN_VAR_SYM:
  2759.  
  2760.         sym = expr->tnVarSym.tnVarSym;
  2761.  
  2762.         assert(sym->sdSymKind      == SYM_VAR);
  2763.         assert(sym->sdVar.sdvLocal == false);
  2764.         assert(sym->sdVar.sdvConst == false);
  2765.  
  2766.         /* Is this a non-static class member? */
  2767.  
  2768.         if  (sym->sdIsMember && !sym->sdIsStatic)
  2769.         {
  2770.             Tree            addr;
  2771.             unsigned        offs;
  2772.  
  2773.             /* Get hold of the instance address value */
  2774.  
  2775.             addr = expr->tnVarSym.tnVarObj; assert(addr);
  2776.  
  2777.             /* Do we have an offset we need to add? */
  2778.  
  2779.             offs = 0;
  2780.  
  2781.             if  (!sym->sdIsManaged)
  2782.             {
  2783.                 offs = sym->sdVar.sdvOffset;
  2784.  
  2785.                 /* Special case: fold offset for "foo.bar.baz...." */
  2786.  
  2787.                 while (addr->tnOper == TN_VAR_SYM &&
  2788.                        addr->tnVtyp == TYP_CLASS)
  2789.                 {
  2790.                     sym = addr->tnVarSym.tnVarSym;
  2791.  
  2792.                     assert(sym->sdSymKind      == SYM_VAR);
  2793.                     assert(sym->sdVar.sdvLocal == false);
  2794.                     assert(sym->sdVar.sdvConst == false);
  2795.  
  2796.                     if  (sym->sdIsMember == false)
  2797.                         break;
  2798.                     if  (sym->sdIsStatic)
  2799.                         break;
  2800.                     if  (sym->sdIsManaged)
  2801.                         break;
  2802.  
  2803.                     offs += sym->sdVar.sdvOffset;
  2804.  
  2805.                     addr = addr->tnVarSym.tnVarObj; assert(addr);
  2806.                 }
  2807.             }
  2808.  
  2809.             if  (addr->tnVtyp == TYP_CLASS)
  2810.             {
  2811.                 assert(sym->sdIsManaged);
  2812.                 assert(offs == 0);
  2813.  
  2814.                 genExpr(addr, true);
  2815.             }
  2816.             else
  2817.             {
  2818.                 /* Don't take the address of a function by mistake */
  2819.  
  2820.                 if  (addr->tnOper == TN_ADDROF)
  2821.                 {
  2822.                     Tree            oper = addr->tnOp.tnOp1;
  2823.  
  2824.                     if  (oper->tnOper == TN_FNC_SYM ||
  2825.                          oper->tnOper == TN_FNC_PTR)
  2826.                     {
  2827.                         UNIMPL(!"should never get here");
  2828.                     }
  2829.                 }
  2830.  
  2831.                 /* Fold the offset if we have a global variable address */
  2832.  
  2833.                 genAddr(addr, offs);
  2834.             }
  2835.  
  2836.             /* Is this member of a managed class? */
  2837.  
  2838.             if  (sym->sdIsManaged && compute)
  2839.                 genOpcode_tok(CEE_LDFLDA, genMemberRef(sym));
  2840.  
  2841.             return 1;
  2842.         }
  2843.  
  2844.         if  (sym->sdIsManaged)
  2845.         {
  2846.             assert(sym->sdIsMember);        // assume managed global vars don't exist
  2847.  
  2848.             /* Is this a static data member of a managed class? */
  2849.  
  2850.             if  (expr->tnVarSym.tnVarObj)
  2851.                 genSideEff(expr->tnVarSym.tnVarObj);
  2852.  
  2853.             if  (compute)
  2854.             {
  2855.                 genOpcode_tok(CEE_LDSFLDA, genMemberRef(sym));
  2856.                 return  1;
  2857.             }
  2858.             else
  2859.                 return  0;
  2860.         }
  2861.  
  2862.         /* Here we have an unmanaged global variable */
  2863.  
  2864.         if  (compute)
  2865.         {
  2866.             genGlobalAddr(expr);
  2867.             return  1;
  2868.         }
  2869.  
  2870.         return  0;
  2871.  
  2872.     case TN_IND:
  2873.         genExpr(expr->tnOp.tnOp1, true);
  2874.         return  1;
  2875.  
  2876.     case TN_INDEX:
  2877.  
  2878.         /* Get hold of the array type */
  2879.  
  2880.         typ = genComp->cmpDirectType(expr->tnOp.tnOp1->tnType);
  2881.  
  2882.         /* Generate the address of the array */
  2883.  
  2884.         genExpr(expr->tnOp.tnOp1, true);
  2885.  
  2886.         /* Generate the dimension list */
  2887.  
  2888.         if  (expr->tnOp.tnOp2->tnOper == TN_LIST)
  2889.         {
  2890.             Tree            xlst;
  2891.  
  2892.             assert(typ->tdTypeKind == TYP_ARRAY);
  2893.             assert(typ->tdIsManaged);
  2894.  
  2895.             xlst = expr->tnOp.tnOp2;
  2896.             xcnt = 0;
  2897.  
  2898.             do
  2899.             {
  2900.                 assert(xlst && xlst->tnOper == TN_LIST);
  2901.  
  2902.                 genExpr(xlst->tnOp.tnOp1, true);
  2903.  
  2904.                 xlst = xlst->tnOp.tnOp2;
  2905.  
  2906.                 xcnt++;
  2907.             }
  2908.             while (xlst);
  2909.  
  2910.             assert(xcnt > 1);
  2911.             assert(xcnt == typ->tdArr.tdaDcnt || !typ->tdArr.tdaDcnt);
  2912.         }
  2913.         else
  2914.         {
  2915.             genExpr(expr->tnOp.tnOp2, true); xcnt = 1;
  2916.         }
  2917.  
  2918.         /* Is this a managed or unmanaged array? */
  2919.  
  2920.         switch (typ->tdTypeKind)
  2921.         {
  2922.         case TYP_ARRAY:
  2923.  
  2924.             assert(typ->tdIsValArray == (typ->tdIsManaged && isMgdValueType(genComp->cmpActualType(typ->tdArr.tdaElem))));
  2925.  
  2926.             if  (typ->tdIsManaged)
  2927.             {
  2928.                 if  (compute)
  2929.                 {
  2930.                     if  (xcnt == 1 && !typ->tdIsGenArray)
  2931.                     {
  2932.                         genOpcode_tok(CEE_LDELEMA, genValTypeRef(typ->tdArr.tdaElem));
  2933.                     }
  2934.                     else
  2935.                     {
  2936.                         genOpcode_tok(CEE_CALL, genComp->cmpArrayEAtoken(typ, xcnt, false, true));
  2937.                         genCurStkLvl -= xcnt;
  2938.                     }
  2939.  
  2940.                     return  1;
  2941.                 }
  2942.                 else
  2943.                 {
  2944.                     return  xcnt + 1;
  2945.                 }
  2946.             }
  2947.  
  2948.             assert(xcnt == 1);
  2949.             break;
  2950.  
  2951.         case TYP_PTR:
  2952.             break;
  2953.  
  2954.         case TYP_REF:
  2955.             assert(typ->tdIsManaged == false);
  2956.             break;
  2957.  
  2958.         default:
  2959.             NO_WAY(!"index applied to weird address");
  2960.             break;
  2961.         }
  2962.  
  2963.         // ISSUE: Are we supposed to do scaling here?
  2964.  
  2965.         genOpcode(CEE_ADD);
  2966.         return 1;
  2967.  
  2968.     case TN_ERROR:
  2969.         return 1;
  2970.  
  2971.     default:
  2972. #ifdef DEBUG
  2973.         genComp->cmpParser->parseDispTree(expr);
  2974. #endif
  2975.         assert(!"invalid/unhandled expression in genAdr()");
  2976.     }
  2977.  
  2978.     return 0;
  2979. }
  2980.  
  2981. /*****************************************************************************
  2982.  *
  2983.  *  Return true if it's possible to directly compute the address of the given
  2984.  *  expression.
  2985.  */
  2986.  
  2987. inline
  2988. bool                genIL::genCanTakeAddr(Tree expr)
  2989. {
  2990.     switch (expr->tnOper)
  2991.     {
  2992.         TypDef          type;
  2993.  
  2994.     case TN_LCL_SYM:
  2995.     case TN_VAR_SYM:
  2996.     case TN_IND:
  2997.         return  true;
  2998.  
  2999.     case TN_INDEX:
  3000.  
  3001.         /* For now, we disallow taking the address of a Common Type System array element */
  3002.  
  3003.         type = expr->tnOp.tnOp1->tnType;
  3004.         if  (type->tdTypeKind && type->tdIsManaged && !type->tdIsValArray)
  3005.             return  false;
  3006.         else
  3007.             return  true;
  3008.     }
  3009.  
  3010.     return  false;
  3011. }
  3012.  
  3013. /*****************************************************************************
  3014.  *
  3015.  *  Generate the load/store part of an lvalue (the object address (if we're
  3016.  *  loading/storing a member) has already been generated).
  3017.  */
  3018.  
  3019. void                genIL::genRef(Tree expr, bool store)
  3020. {
  3021.     switch (expr->tnOper)
  3022.     {
  3023.         SymDef          sym;
  3024.         TypDef          type;
  3025.         var_types       vtyp;
  3026.  
  3027.     case TN_LCL_SYM:
  3028.  
  3029.         sym = expr->tnLclSym.tnLclSym;
  3030.  
  3031.         assert(sym->sdSymKind == SYM_VAR);
  3032.         assert(sym->sdVar.sdvLocal);
  3033.  
  3034.         genLclVarRef(sym, store);
  3035.         return;
  3036.  
  3037.     case TN_VAR_SYM:
  3038.  
  3039.         /* Get hold of the member symbol */
  3040.  
  3041.         sym  = expr->tnVarSym.tnVarSym; assert(sym->sdSymKind == SYM_VAR);
  3042.  
  3043.         /* Generate the Common Type System load/store opcode */
  3044.  
  3045.         if  (sym->sdIsMember == false ||
  3046.              sym->sdIsStatic != false)
  3047.         {
  3048.             genOpcode_tok(store ? CEE_STSFLD
  3049.                                 : CEE_LDSFLD, genMemberRef(sym));
  3050.         }
  3051.         else
  3052.         {
  3053.             if  (sym->sdIsManaged)
  3054.             {
  3055.                 genOpcode_tok(store ? CEE_STFLD
  3056.                                     : CEE_LDFLD, genMemberRef(sym));
  3057.             }
  3058.             else
  3059.             {
  3060.                 /* Member of an unmanaged class, use an indirect load/store */
  3061.  
  3062.                 vtyp = expr->tnVtypGet();
  3063.  
  3064.                 switch (vtyp)
  3065.                 {
  3066.                 case TYP_CLASS:
  3067.  
  3068.                     /* Push the value type on the stack */
  3069.  
  3070.                     genOpcode_tok(CEE_LDOBJ, genValTypeRef(expr->tnType));
  3071.                     return;
  3072.  
  3073.                 case TYP_ENUM:
  3074.                     vtyp = compiler::cmpEnumBaseVtp(expr->tnType);
  3075.                     break;
  3076.                 }
  3077.  
  3078.                 assert(vtyp < arraylen(opcodesIndLoad ));
  3079.                 assert(vtyp < arraylen(opcodesIndStore));
  3080.  
  3081.                 genOpcode((store ? opcodesIndStore
  3082.                                  : opcodesIndLoad)[vtyp]);
  3083.             }
  3084.         }
  3085.  
  3086.         return;
  3087.  
  3088.     case TN_INDEX:
  3089.  
  3090.         /* Is this a managed or unmanaged array? */
  3091.  
  3092.         type = genComp->cmpDirectType(expr->tnOp.tnOp1->tnType);
  3093.  
  3094.         if  (type->tdTypeKind == TYP_ARRAY && type->tdIsManaged)
  3095.         {
  3096.             TypDef              etyp;
  3097.             unsigned            dcnt = type->tdArr.tdaDcnt;
  3098.  
  3099.             /* Is this a multi-dimensional/generic managed array? */
  3100.  
  3101.             if  (dcnt > 1 || dcnt == 0)
  3102.             {
  3103.                 /* Figure out the number of dimensions */
  3104.  
  3105.                 if  (!dcnt)
  3106.                 {
  3107.                     Tree            xlst = expr->tnOp.tnOp2;
  3108.  
  3109.                     do
  3110.                     {
  3111.                         assert(xlst && xlst->tnOper == TN_LIST);
  3112.  
  3113.                         dcnt++;
  3114.  
  3115.                         xlst = xlst->tnOp.tnOp2;
  3116.                     }
  3117.                     while (xlst);
  3118.                 }
  3119.  
  3120.         ELEM_HELPER:
  3121.  
  3122.                 genOpcode_tok(CEE_CALL, genComp->cmpArrayEAtoken(type, dcnt, store));
  3123.                 genCurStkLvl -= dcnt;
  3124.                 if  (store)
  3125.                     genCurStkLvl -= 2;
  3126.                 return;
  3127.             }
  3128.  
  3129.             etyp = expr->tnType;
  3130.             vtyp = genExprVtyp(expr);
  3131.  
  3132.             /* Is this an array of intrinsic values? */
  3133.  
  3134.             if  (etyp->tdTypeKind == TYP_CLASS)
  3135.             {
  3136.                 if  (etyp->tdClass.tdcIntrType == TYP_UNDEF)
  3137.                 {
  3138.                     /* Call the "get element" helper to fetch the value */
  3139.  
  3140.                     goto ELEM_HELPER;
  3141.                 }
  3142.  
  3143.                 vtyp = (var_types)etyp->tdClass.tdcIntrType;
  3144.             }
  3145.  
  3146.             assert(vtyp < arraylen(opcodesArrLoad ));
  3147.             assert(vtyp < arraylen(opcodesArrStore));
  3148.  
  3149.             genOpcode((store ? opcodesArrStore
  3150.                              : opcodesArrLoad)[vtyp]);
  3151.  
  3152.             return;
  3153.         }
  3154.  
  3155.         /* If we have an array here it better have exactly one dimension */
  3156.  
  3157.         assert(type->tdTypeKind != TYP_ARRAY || type->tdArr.tdaDcnt == 1);
  3158.  
  3159.         // Fall through, unmanaged array same as indirection ....
  3160.  
  3161.     case TN_IND:
  3162.  
  3163.         vtyp = expr->tnVtypGet();
  3164.  
  3165.         if  (vtyp == TYP_ENUM)
  3166.             vtyp = compiler::cmpEnumBaseVtp(expr->tnType);
  3167.  
  3168.         assert(vtyp < arraylen(opcodesIndLoad ));
  3169.         assert(vtyp < arraylen(opcodesIndStore));
  3170.  
  3171.         if  (vtyp == TYP_CLASS)
  3172.         {
  3173.             assert(store == false);
  3174.  
  3175.             /* Push the astruct value on the stack */
  3176.  
  3177.             genOpcode_tok(CEE_LDOBJ, genValTypeRef(expr->tnType));
  3178.             return;
  3179.         }
  3180.  
  3181.         genOpcode((store ? opcodesIndStore
  3182.                          : opcodesIndLoad)[vtyp]);
  3183.  
  3184.         return;
  3185.  
  3186.     default:
  3187. #ifdef DEBUG
  3188.         genComp->cmpParser->parseDispTree(expr);
  3189. #endif
  3190.         assert(!"invalid/unhandled expression in genRef()");
  3191.     }
  3192. }
  3193.  
  3194. /*****************************************************************************
  3195.  *
  3196.  *  Generate the address of the given expression (works for any expression by
  3197.  *  introducing a temp for the value and using its address when necessary).
  3198.  */
  3199.  
  3200. bool                genIL::genGenAddressOf(Tree addr,
  3201.                                            bool oneUse, unsigned *tnumPtr,
  3202.                                                         TypDef   *ttypPtr)
  3203. {
  3204.     if  (genCanTakeAddr(addr))
  3205.     {
  3206.         genAdr(addr, true);
  3207.  
  3208.         return  false;
  3209.     }
  3210.     else
  3211.     {
  3212.         unsigned        tempNum;
  3213.         TypDef          tempType;
  3214.  
  3215.         /* Store the value in a temp */
  3216.  
  3217.         tempType = addr->tnType;
  3218.         tempNum  = genTempVarGet(tempType);
  3219.  
  3220.         /* Special case: "new" of a value type */
  3221.  
  3222.         if  (addr->tnOper == TN_NEW    &&
  3223.              addr->tnVtyp == TYP_CLASS) // && addr->tnType->tdIsIntrinsic == false) ??????????????????
  3224.         {
  3225.             /* Direct "new" into the temp we've just created */
  3226.  
  3227.             genLclVarAdr(tempNum);
  3228.             genCall(addr, false);
  3229.         }
  3230.         else
  3231.         {
  3232.             genExpr(addr, true);
  3233.             genLclVarRef(tempNum,  true);
  3234.         }
  3235.  
  3236.         /* Compute the address of the temp */
  3237.  
  3238.         genLclVarAdr(tempNum);
  3239.  
  3240.         /* Are we supposed to free up the temp right away? */
  3241.  
  3242.         if  (oneUse)
  3243.         {
  3244.             genTempVarRls(tempType, tempNum);
  3245.             return  false;
  3246.         }
  3247.         else
  3248.         {
  3249.             *tnumPtr = tempNum;
  3250.             *ttypPtr = tempType;
  3251.  
  3252.             return  true;
  3253.         }
  3254.     }
  3255. }
  3256.  
  3257. /*****************************************************************************
  3258.  *
  3259.  *  Generate the address of a function.
  3260.  */
  3261.  
  3262. void                genIL::genFncAddr(Tree expr)
  3263. {
  3264.     SymDef          fncSym;
  3265.     mdToken         fncTok;
  3266.  
  3267.     assert(expr->tnOper == TN_FNC_SYM || expr->tnOper == TN_FNC_PTR);
  3268.     assert(expr->tnFncSym.tnFncSym->sdSymKind == SYM_FNC);
  3269.  
  3270.     fncSym = expr->tnFncSym.tnFncSym;
  3271.     fncTok = genMethodRef(fncSym, false);
  3272.  
  3273.     if  (fncSym->sdFnc.sdfVirtual != false &&
  3274.          fncSym->sdIsStatic       == false &&
  3275.          fncSym->sdIsSealed       == false &&
  3276.          fncSym->sdAccessLevel    != ACL_PRIVATE)
  3277.     {
  3278.         genOpcode    (CEE_DUP);
  3279.         genOpcode_tok(CEE_LDVIRTFTN, fncTok);
  3280.     }
  3281.     else
  3282.         genOpcode_tok(CEE_LDFTN    , fncTok);
  3283. }
  3284.  
  3285. /*****************************************************************************
  3286.  *
  3287.  *  Given a binary operator, return the opcode to compute it.
  3288.  */
  3289.  
  3290. ILopcodes           genIL::genBinopOpcode(treeOps oper, var_types type)
  3291. {
  3292.     static
  3293.     unsigned        binopOpcodesSgn[] =
  3294.     {
  3295.         CEE_ADD,    // TN_ADD
  3296.         CEE_SUB,    // TN_SUB
  3297.         CEE_MUL,    // TN_MUL
  3298.         CEE_DIV,    // TN_DIV
  3299.         CEE_REM,    // TN_MOD
  3300.  
  3301.         CEE_AND,    // TN_AND
  3302.         CEE_XOR,    // TN_XOR
  3303.         CEE_OR ,    // TN_OR
  3304.  
  3305.         CEE_SHL,    // TN_SHL
  3306.         CEE_SHR,    // TN_SHR
  3307.         CEE_SHR_UN, // TN_SHZ
  3308.  
  3309.         CEE_BEQ,    // TN_EQ
  3310.         CEE_BNE_UN, // TN_NE
  3311.         CEE_BLT,    // TN_LT
  3312.         CEE_BLE,    // TN_LE
  3313.         CEE_BGE,    // TN_GE
  3314.         CEE_BGT,    // TN_GT
  3315.     };
  3316.  
  3317.     static
  3318.     unsigned        binopOpcodesUns[] =
  3319.     {
  3320.         CEE_ADD,    // TN_ADD
  3321.         CEE_SUB,    // TN_SUB
  3322.         CEE_MUL,    // TN_MUL
  3323.         CEE_DIV_UN, // TN_DIV
  3324.         CEE_REM_UN, // TN_MOD
  3325.  
  3326.         CEE_AND,    // TN_AND
  3327.         CEE_XOR,    // TN_XOR
  3328.         CEE_OR ,    // TN_OR
  3329.  
  3330.         CEE_SHL,    // TN_SHL
  3331.         CEE_SHR_UN, // TN_SHR
  3332.         CEE_SHR_UN, // TN_SHZ
  3333.  
  3334.         CEE_BEQ,    // TN_EQ
  3335.         CEE_BNE_UN, // TN_NE
  3336.         CEE_BLT_UN, // TN_LT
  3337.         CEE_BLE_UN, // TN_LE
  3338.         CEE_BGE_UN, // TN_GE
  3339.         CEE_BGT_UN, // TN_GT
  3340.     };
  3341.  
  3342.     if  (oper < TN_ADD || oper > TN_GT)
  3343.     {
  3344.         if  (oper > TN_ASG)
  3345.         {
  3346.             if  (oper > TN_ASG_RSZ)
  3347.                 return  CEE_NOP;
  3348.  
  3349.             assert(TN_ASG_ADD - TN_ASG_ADD == TN_ADD - TN_ADD);
  3350.             assert(TN_ASG_SUB - TN_ASG_ADD == TN_SUB - TN_ADD);
  3351.             assert(TN_ASG_MUL - TN_ASG_ADD == TN_MUL - TN_ADD);
  3352.             assert(TN_ASG_DIV - TN_ASG_ADD == TN_DIV - TN_ADD);
  3353.             assert(TN_ASG_MOD - TN_ASG_ADD == TN_MOD - TN_ADD);
  3354.             assert(TN_ASG_AND - TN_ASG_ADD == TN_AND - TN_ADD);
  3355.             assert(TN_ASG_XOR - TN_ASG_ADD == TN_XOR - TN_ADD);
  3356.             assert(TN_ASG_OR  - TN_ASG_ADD == TN_OR  - TN_ADD);
  3357.             assert(TN_ASG_LSH - TN_ASG_ADD == TN_LSH - TN_ADD);
  3358.             assert(TN_ASG_RSH - TN_ASG_ADD == TN_RSH - TN_ADD);
  3359.             assert(TN_ASG_RSZ - TN_ASG_ADD == TN_RSZ - TN_ADD);
  3360.  
  3361.             assert(oper >= TN_ASG_ADD);
  3362.             assert(oper <= TN_ASG_RSZ);
  3363.  
  3364.             oper = (treeOps)(oper - (TN_ASG_ADD - TN_ADD));
  3365.         }
  3366.         else
  3367.             return  CEE_NOP;
  3368.     }
  3369.  
  3370.     assert(oper >= TN_ADD);
  3371.     assert(oper <= TN_GT);
  3372.  
  3373.     return  (ILopcodes)(varTypeIsUnsigned(type) ? binopOpcodesUns[oper - TN_ADD]
  3374.                                                 : binopOpcodesSgn[oper - TN_ADD]);
  3375. }
  3376.  
  3377. /*****************************************************************************
  3378.  *
  3379.  *  The following can be used when one needs to make a copy of some address.
  3380.  */
  3381.  
  3382. struct   genCloneDsc
  3383. {
  3384.     Tree            gcdAddr;        // address or NULL if temp is being used
  3385.     unsigned        gcdOffs;        // to be added to address
  3386.     unsigned        gcdTemp;        // temp number (when gcdAddr==NULL)
  3387.     TypDef          gcdType;        // type of temp
  3388.     bool            gcdGlob;        // address of a global variable?
  3389. };
  3390.  
  3391. void                genIL::genCloneAddrBeg(genCloneDsc *clone, Tree addr, unsigned offs)
  3392. {
  3393.     unsigned        temp;
  3394.  
  3395.     /* Save the offset */
  3396.  
  3397.     clone->gcdOffs = offs;
  3398.  
  3399.     /* Do we have an address of a global variable or a simple pointer value? */
  3400.  
  3401.     if  (!offs)
  3402.     {
  3403.         if  (addr->tnOper == TN_LCL_SYM)
  3404.         {
  3405.             /* Simple pointer value */
  3406.  
  3407.             clone->gcdAddr = addr;
  3408.             clone->gcdGlob = false;
  3409.  
  3410.             genExpr(addr, true);
  3411.             return;
  3412.         }
  3413.  
  3414.         if  (addr->tnOper == TN_ADDROF)
  3415.         {
  3416.             Tree            base = addr->tnOp.tnOp1;
  3417.  
  3418.             if  (base->tnOper == TN_VAR_SYM)
  3419.             {
  3420.                 SymDef          sym;
  3421.  
  3422.                 /* Only static members / globals are acceptable */
  3423.  
  3424.                 sym = base->tnVarSym.tnVarSym; assert(sym->sdSymKind == SYM_VAR);
  3425.  
  3426.                 if  (sym->sdIsMember == false ||
  3427.                      sym->sdIsStatic != false)
  3428.                 {
  3429.                     /* Address of a global variable */
  3430.  
  3431.                     clone->gcdAddr = base;
  3432.                     clone->gcdGlob = true;
  3433.  
  3434.                     assert(offs == 0);
  3435.  
  3436.                     genGlobalAddr(base);
  3437.                     return;
  3438.                 }
  3439.             }
  3440.         }
  3441.     }
  3442.  
  3443.     /* Oh well, let's use a temp */
  3444.  
  3445.     clone->gcdAddr = NULL;
  3446.     clone->gcdTemp = temp = genTempVarGet(addr->tnType);
  3447.     clone->gcdType = addr->tnType;
  3448.  
  3449.     /* Store the address in the temp and reload it */
  3450.  
  3451.     genExpr     (addr,  true);
  3452.  
  3453.     if  (offs)
  3454.     {
  3455.         genIntConst(offs);
  3456.         genOpcode(CEE_ADD);
  3457.     }
  3458.  
  3459.     genLclVarRef(temp,  true);
  3460.     genLclVarRef(temp, false);
  3461. }
  3462.  
  3463. void                genIL::genCloneAddrUse(genCloneDsc *clone)
  3464. {
  3465.     if  (clone->gcdAddr)
  3466.     {
  3467.         assert(clone->gcdOffs == 0);
  3468.  
  3469.         if  (clone->gcdGlob)
  3470.         {
  3471.             /* Address of a global variable */
  3472.  
  3473.             genGlobalAddr(clone->gcdAddr);
  3474.         }
  3475.         else
  3476.         {
  3477.             /* Simple pointer value */
  3478.  
  3479.             genExpr(clone->gcdAddr, true);
  3480.         }
  3481.     }
  3482.     else
  3483.     {
  3484.         /* Temp variable */
  3485.  
  3486.         genLclVarRef(clone->gcdTemp, false);
  3487.     }
  3488. }
  3489.  
  3490. void                genIL::genCloneAddrEnd(genCloneDsc *clone)
  3491. {
  3492.     if  (!clone->gcdAddr)
  3493.         genTempVarRls(clone->gcdType, clone->gcdTemp);
  3494. }
  3495.  
  3496. /*****************************************************************************
  3497.  *
  3498.  *  Load the value of a bitfield.
  3499.  */
  3500.  
  3501. void                genIL::genBitFieldLd(Tree expr, bool didAddr, bool valUsed)
  3502. {
  3503.     Tree            addr;
  3504.     unsigned        offs;
  3505.     var_types       btyp;
  3506.     unsigned        bpos;
  3507.     unsigned        blen;
  3508.  
  3509.     /* Get hold of the address and offset */
  3510.  
  3511.     assert(expr->tnOper == TN_BFM_SYM);
  3512.  
  3513.     addr = expr->tnBitFld.tnBFinst;
  3514.     offs = expr->tnBitFld.tnBFoffs;
  3515.  
  3516.     if  (!valUsed)
  3517.     {
  3518.         assert(didAddr == false);
  3519.  
  3520.         /* Go figure ... */
  3521.  
  3522.         genSideEff(addr);
  3523.         return;
  3524.     }
  3525.  
  3526.     /* How big is the bitfield and what is its type? */
  3527.  
  3528.     btyp = genComp->cmpActualVtyp(expr->tnBitFld.tnBFmsym->sdType);
  3529.     bpos = expr->tnBitFld.tnBFpos;
  3530.     blen = expr->tnBitFld.tnBFlen;
  3531.  
  3532.     /* Compute the address of the bitfield, unless caller already did that */
  3533.  
  3534.     if  (!didAddr)
  3535.         genAddr(addr, offs);
  3536.  
  3537.     /* Load the bitfield cell and shift/mask it as appropriate */
  3538.  
  3539.     assert(btyp < arraylen(opcodesIndLoad)); genOpcode(opcodesIndLoad[btyp]);
  3540.  
  3541.     /* Is the bitfield unsigned? */
  3542.  
  3543.     if  (varTypeIsUnsigned(btyp))
  3544.     {
  3545.         assert(btyp != TYP_LONG);
  3546.  
  3547.         /* Unsigned bitfield - shift if necessary and then mask */
  3548.  
  3549.         if  (bpos)
  3550.         {
  3551.             genIntConst(bpos);
  3552.             genOpcode(CEE_SHR_UN);
  3553.         }
  3554.  
  3555.         if  (btyp == TYP_ULONG)
  3556.             genLngConst(((__uint64)1 << blen) - 1);
  3557.         else
  3558.             genIntConst(((unsigned)1 << blen) - 1);
  3559.  
  3560.         genOpcode(CEE_AND);
  3561.     }
  3562.     else
  3563.     {
  3564.         unsigned    size;
  3565.         unsigned    diff;
  3566.  
  3567.         /* Signed bitfield - shift left and then right */
  3568.  
  3569.         assert(btyp != TYP_ULONG);
  3570.  
  3571.         /* Compute how far left we need to shift */
  3572.  
  3573.         size = (btyp == TYP_LONG) ? 64 : 32;
  3574.         diff = size - (bpos + blen); assert((int)diff >= 0);
  3575.  
  3576.         if  (diff)
  3577.         {
  3578.             genIntConst(diff);
  3579.             genOpcode(CEE_SHL);
  3580.         }
  3581.  
  3582.         genIntConst(bpos + diff);
  3583.         genOpcode(CEE_SHR);
  3584.     }
  3585. }
  3586.  
  3587. /*****************************************************************************
  3588.  *
  3589.  *  Compute a new bitfield value and store it. In the simplest case, 'newx' is
  3590.  *  the new value to be assigned. If 'newx' is NULL, we either have an inc/dec
  3591.  *  operator (in which case 'delta' and 'post' yield the value and ordering of
  3592.  *  the increment/decrement) or 'asgx' specifies an assignment operator (which
  3593.  *  must be TN_ASG_OR or TN_ASG_AND).
  3594.  */
  3595.  
  3596. void                genIL::genBitFieldSt(Tree   dstx,
  3597.                                          Tree   newx,
  3598.                                          Tree   asgx,
  3599.                                          int    delta,
  3600.                                          bool   post, bool valUsed)
  3601. {
  3602.     Tree            addr;
  3603.     unsigned        offs;
  3604.     var_types       btyp;
  3605.     unsigned        bpos;
  3606.     unsigned        blen;
  3607.  
  3608.     bool            ncns;
  3609.  
  3610.     __uint64        mask;
  3611.     __uint64        lval;
  3612.     __uint32        ival;
  3613.  
  3614.     genCloneDsc     clone;
  3615.  
  3616.     bool            nilCns  = false;
  3617.     bool            logCns  = false;
  3618.  
  3619.     bool            tempUse = false;
  3620.     unsigned        tempNum;
  3621.  
  3622.     /* Get hold of the address and offset */
  3623.  
  3624.     assert(dstx->tnOper == TN_BFM_SYM);
  3625.  
  3626.     addr = dstx->tnBitFld.tnBFinst;
  3627.     offs = dstx->tnBitFld.tnBFoffs;
  3628.  
  3629.     /* How big is the bitfield and what is its type? */
  3630.  
  3631.     btyp = genComp->cmpActualVtyp(dstx->tnBitFld.tnBFmsym->sdType);
  3632.     bpos = dstx->tnBitFld.tnBFpos;
  3633.     blen = dstx->tnBitFld.tnBFlen;
  3634.     mask = ((__uint64)1 << blen) - 1;
  3635.  
  3636.     /* We'll need to duplicate the address */
  3637.  
  3638.     genCloneAddrBeg(&clone, addr, offs);
  3639.  
  3640.     /* Is this an assignment or increment/decrement operator? */
  3641.  
  3642.     if  (newx == NULL)
  3643.     {
  3644.         treeOps         oper;
  3645.  
  3646.         /* Check for a special case: "|= icon" or "&= icon" */
  3647.  
  3648.         if  (asgx)
  3649.         {
  3650.             /* This is an assignment operator */
  3651.  
  3652.             assert(post);
  3653.  
  3654.             /* Get hold of the operator and the RHS */
  3655.  
  3656.             oper = asgx->tnOperGet();
  3657.             newx = asgx->tnOp.tnOp2;
  3658.  
  3659.             if  (oper == TN_ASG_OR || oper == TN_ASG_AND)
  3660.             {
  3661.                 if  (newx->tnOper == TN_CNS_INT ||
  3662.                      newx->tnOper == TN_CNS_LNG)
  3663.                 {
  3664.                     logCns = true;
  3665.                     goto ASGOP;
  3666.                 }
  3667.             }
  3668.         }
  3669.  
  3670.         /* Load the old value of the bitfield */
  3671.  
  3672.         genCloneAddrUse(&clone);
  3673.         genBitFieldLd(dstx, true, true);
  3674.  
  3675.     ASGOP:
  3676.  
  3677.         /* For post-operators whose result value is used, save the old value */
  3678.  
  3679.         if  (post && valUsed)
  3680.         {
  3681.             tempNum = genTempVarGet(dstx->tnType);
  3682.             tempUse = true;
  3683.  
  3684.             genLclVarRef(tempNum,  true);
  3685.             genLclVarRef(tempNum, false);
  3686.         }
  3687.  
  3688.         /* Compute the new value */
  3689.  
  3690.         if  (asgx)
  3691.         {
  3692.             /* This is an assignment operator */
  3693.  
  3694.             assert((asgx->tnOperKind() & TNK_ASGOP) && oper != TN_ASG);
  3695.             assert(asgx->tnOp.tnOp1 == dstx);
  3696.  
  3697.             /* Special case: "|= icon" or "&= icon" */
  3698.  
  3699.             if  (logCns)
  3700.             {
  3701.                 switch (newx->tnOper)
  3702.                 {
  3703.                 case TN_CNS_INT:
  3704.  
  3705.                     ival = (newx->tnIntCon.tnIconVal & (__uint32)mask) << bpos;
  3706.  
  3707.                     if  (oper == TN_ASG_OR)
  3708.                     {
  3709.                         genIntConst(ival);
  3710.                         goto COMBINE;
  3711.                     }
  3712.                     else
  3713.                     {
  3714.                         genCloneAddrUse(&clone);
  3715.                         assert(btyp < arraylen(opcodesIndLoad));
  3716.                         genOpcode(opcodesIndLoad[btyp]);
  3717.  
  3718.                         genIntConst(ival | ~((__uint32)mask << bpos));
  3719.                         genOpcode(CEE_AND);
  3720.                         goto STORE;
  3721.                     }
  3722.  
  3723.                 case TN_CNS_LNG:
  3724.  
  3725.                     lval = (newx->tnLngCon.tnLconVal & (__uint64)mask) << bpos;
  3726.  
  3727.                     if  (oper == TN_ASG_OR)
  3728.                     {
  3729.                         genLngConst(lval);
  3730.                         goto COMBINE;
  3731.                     }
  3732.                     else
  3733.                     {
  3734.                         genCloneAddrUse(&clone);
  3735.                         assert(btyp < arraylen(opcodesIndLoad));
  3736.                         genOpcode(opcodesIndLoad[btyp]);
  3737.  
  3738.                         genLngConst(lval | ~((__uint64)mask << bpos));
  3739.                         genOpcode(CEE_AND);
  3740.                         goto STORE;
  3741.                     }
  3742.  
  3743.                 default:
  3744.                     NO_WAY(!"no way");
  3745.                 }
  3746.             }
  3747.  
  3748.             /* Compute the new value */
  3749.  
  3750.             genExpr(newx, true);
  3751.             genOpcode(genBinopOpcode(oper, btyp));
  3752.         }
  3753.         else
  3754.         {
  3755.             /* This is an increment/decrement operator */
  3756.  
  3757.             if  (delta > 0)
  3758.             {
  3759.                 genAnyConst( delta, btyp);
  3760.                 genOpcode(CEE_ADD);
  3761.             }
  3762.             else
  3763.             {
  3764.                 genAnyConst(-delta, btyp);
  3765.                 genOpcode(CEE_SUB);
  3766.             }
  3767.         }
  3768.  
  3769.         /* Mask off any extra bits from the result */
  3770.  
  3771.         if  (btyp == TYP_LONG || btyp == TYP_ULONG)
  3772.             genLngConst((__uint64)mask);
  3773.         else
  3774.             genIntConst((__uint32)mask);
  3775.  
  3776.         genOpcode(CEE_AND);
  3777.  
  3778.         /* Go store the new value in the bitfield */
  3779.  
  3780.         ncns = false;
  3781.         goto SHIFT;
  3782.     }
  3783.  
  3784.     /* Evaluate the new value and mask it off */
  3785.  
  3786.     if  (btyp == TYP_LONG || btyp == TYP_ULONG)
  3787.     {
  3788.         if  (newx->tnOper == TN_CNS_LNG)
  3789.         {
  3790.             ncns = true;
  3791.  
  3792.             /* Don't bother OR'ing zeros */
  3793.  
  3794.             lval = (__uint64)mask & newx->tnLngCon.tnLconVal;
  3795.  
  3796.             if  (lval)
  3797.                 genLngConst(lval << bpos);
  3798.             else
  3799.                 nilCns = true;
  3800.  
  3801.             goto COMBINE;
  3802.         }
  3803.         else
  3804.         {
  3805.             ncns = false;
  3806.  
  3807.             genExpr(newx, true);
  3808.             genLngConst((__uint64)mask);
  3809.             genOpcode(CEE_AND);
  3810.         }
  3811.     }
  3812.     else
  3813.     {
  3814.         if  (newx->tnOper == TN_CNS_INT)
  3815.         {
  3816.             ncns = true;
  3817.  
  3818.             /* Don't bother OR'ing zeros */
  3819.  
  3820.             ival = (__uint32)mask & newx->tnIntCon.tnIconVal;
  3821.  
  3822.             if  (ival)
  3823.                 genIntConst(ival << bpos);
  3824.             else
  3825.                 nilCns = true;
  3826.  
  3827.             goto COMBINE;
  3828.         }
  3829.         else
  3830.         {
  3831.             ncns = false;
  3832.  
  3833.             genExpr(newx, true);
  3834.             genIntConst((__uint32)mask);
  3835.             genOpcode(CEE_AND);
  3836.         }
  3837.     }
  3838.  
  3839.     /* Is the new value used and is it an unsigned non-constant? */
  3840.  
  3841.     if  (valUsed && !ncns && varTypeIsUnsigned(btyp))
  3842.     {
  3843.         /* Store the new (masked) value in a temp */
  3844.  
  3845.         tempUse = true;
  3846.         tempNum = genTempVarGet(dstx->tnType);
  3847.  
  3848.         genLclVarRef(tempNum,  true);
  3849.         genLclVarRef(tempNum, false);
  3850.     }
  3851.  
  3852. SHIFT:
  3853.  
  3854.     /* Shift the new value if the bit position is non-zero */
  3855.  
  3856.     if  (bpos)
  3857.     {
  3858.         genIntConst(bpos);
  3859.         genOpcode(CEE_SHL);
  3860.     }
  3861.  
  3862. COMBINE:
  3863.  
  3864.     /* Load and mask off the old value of the bitfield */
  3865.  
  3866.     genCloneAddrUse(&clone);
  3867.  
  3868.     assert(btyp < arraylen(opcodesIndLoad)); genOpcode(opcodesIndLoad[btyp]);
  3869.  
  3870.     if  (!logCns)
  3871.     {
  3872.         if  (btyp == TYP_LONG || btyp == TYP_ULONG)
  3873.             genLngConst(~((((__uint64)1 << blen) - 1) << bpos));
  3874.         else
  3875.             genIntConst(~((((unsigned)1 << blen) - 1) << bpos));
  3876.  
  3877.         genOpcode(CEE_AND);
  3878.     }
  3879.  
  3880.     /* Place the new bits in the cell value */
  3881.  
  3882.     if  (!nilCns)
  3883.         genOpcode(CEE_OR);
  3884.  
  3885. STORE:
  3886.  
  3887.     /* Store the new cell value in the class */
  3888.  
  3889.     assert(btyp < arraylen(opcodesIndStore)); genOpcode(opcodesIndStore[btyp]);
  3890.  
  3891.     /* Load the new value if necessary */
  3892.  
  3893.     if  (valUsed)
  3894.     {
  3895.         if  (ncns)
  3896.         {
  3897.             /* The new value is a constant */
  3898.  
  3899.             //  for signed bitfields we have to bash the upper bits!
  3900.  
  3901.             if  (newx->tnOper == TN_CNS_LNG)
  3902.                 genLngConst(lval);
  3903.             else
  3904.                 genIntConst(ival);
  3905.         }
  3906.         else
  3907.         {
  3908.             /* Either load the saved value or reload the bitfield */
  3909.  
  3910.             if  (tempUse)
  3911.             {
  3912.                 genLclVarRef(tempNum, false);
  3913.                 genTempVarRls(dstx->tnType, tempNum);
  3914.             }
  3915.             else
  3916.             {
  3917.                 genCloneAddrUse(&clone);
  3918.  
  3919.                 genBitFieldLd(dstx, true, true);
  3920.             }
  3921.         }
  3922.     }
  3923.  
  3924.     genCloneAddrEnd(&clone);
  3925. }
  3926.  
  3927. /*****************************************************************************
  3928.  *
  3929.  *  Use the following to figure out the opcode needed to convert from one
  3930.  *  arithmetic type to another.
  3931.  */
  3932.  
  3933. unsigned            genIL::genConvOpcode(var_types src, var_types dst)
  3934. {
  3935.     unsigned        opcode;
  3936.  
  3937.     const
  3938.     unsigned        opcodesConvMin = TYP_BOOL;
  3939.     const
  3940.     unsigned        opcodesConvMax = TYP_LONGDBL;
  3941.  
  3942.     static
  3943.     unsigned        opcodesConv[][opcodesConvMax - opcodesConvMin + 1] =
  3944.     {
  3945.     // from       to BOOL           WCHAR          CHAR           UCHAR          SHORT          USHORT         INT            UINT           NATINT         NATUINT        LONG           ULONG           FLOAT          DOUBLE         LONGDBL
  3946.     /* BOOL    */  { CEE_NOP      , CEE_CONV_U2  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3947.     /* WCHAR   */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_U8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3948.     /* CHAR    */  { CEE_ILLEGAL  , CEE_NOP      , CEE_NOP      , CEE_CONV_U1  , CEE_CONV_I2  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3949.     /* UCHAR   */  { CEE_ILLEGAL  , CEE_NOP      , CEE_CONV_I1  , CEE_NOP      , CEE_CONV_I2  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_U8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3950.     /* SHORT   */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3951.     /* USHORT  */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_NOP      , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_U8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3952.     /* INT     */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3953.     /* UINT    */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_NOP      , CEE_NOP      , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_U8  , CEE_CONV_U8  , CEE_CONV_R_UN, CEE_CONV_R_UN, CEE_CONV_R_UN},
  3954.     /* NATINT  */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_NOP      , CEE_NOP      , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3955.     /* NATUINT */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_NOP      , CEE_NOP      , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R_UN, CEE_CONV_R_UN, CEE_CONV_R_UN},
  3956.     /* LONG    */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_CONV_I   , CEE_CONV_U   , CEE_NOP      , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_CONV_R8  },
  3957.     /* ULONG   */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_NOP      , CEE_CONV_R_UN, CEE_CONV_R_UN, CEE_CONV_R_UN},
  3958.     /* FLOAT   */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_NOP      , CEE_CONV_R8  , CEE_CONV_R8  },
  3959.     /* DOUBLE  */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_NOP      , CEE_NOP      },
  3960.     /* LONGDBL */  { CEE_ILLEGAL  , CEE_CONV_U2  , CEE_CONV_I1  , CEE_CONV_U1  , CEE_CONV_I2  , CEE_CONV_U2  , CEE_CONV_I4  , CEE_CONV_U4  , CEE_CONV_I   , CEE_CONV_U   , CEE_CONV_I8  , CEE_CONV_U8  , CEE_CONV_R4  , CEE_CONV_R8  , CEE_NOP      },
  3961.     };
  3962.  
  3963.     assert(src != TYP_ENUM && "enums should never make it here");
  3964.     assert(dst != TYP_ENUM && "enums should never make it here");
  3965.  
  3966.     assert(src >= opcodesConvMin);
  3967.     assert(src <= opcodesConvMax);
  3968.  
  3969.     assert(dst >= opcodesConvMin);
  3970.     assert(dst <= opcodesConvMax);
  3971.  
  3972.     opcode = opcodesConv[src - opcodesConvMin][dst - opcodesConvMin];
  3973.  
  3974. #ifdef DEBUG
  3975.     if  (opcode == CEE_ILLEGAL)
  3976.     {
  3977.         printf("Don't have an opcode for conversion of '%s' to '%s'.\n", genStab->stIntrinsicTypeName(src),
  3978.                                                                          genStab->stIntrinsicTypeName(dst));
  3979.     }
  3980. #endif
  3981.  
  3982.     assert(opcode != CEE_ILLEGAL);
  3983.  
  3984.     return opcode;
  3985. }
  3986.  
  3987. /*****************************************************************************
  3988.  *
  3989.  *  Generate code to cast the given expression to the specified type.
  3990.  */
  3991.  
  3992. void                genIL::genCast(Tree expr, TypDef type, unsigned flags)
  3993. {
  3994.     unsigned        opcode;
  3995.  
  3996.     TypDef          srcTyp = expr->tnType;
  3997.     var_types       srcVtp = expr->tnVtypGet();
  3998.     var_types       dstVtp = type->tdTypeKindGet();
  3999.  
  4000. AGAIN:
  4001.  
  4002.     /* Is this an arithmetic conversion? */
  4003.  
  4004.     if  (varTypeIsArithmetic(srcVtp) &&
  4005.          varTypeIsArithmetic(dstVtp))
  4006.     {
  4007.  
  4008.     ARITH:
  4009.  
  4010.         genExpr(expr, true);
  4011.  
  4012.         opcode = genConvOpcode(srcVtp, dstVtp);
  4013.  
  4014.         if  (opcode == CEE_count)
  4015.         {
  4016.             /* This is a special case: we have to convert to 'int' first */
  4017.  
  4018.             genOpcode(genConvOpcode(srcVtp, TYP_INT));
  4019.  
  4020.             opcode =  genConvOpcode(TYP_INT, dstVtp);
  4021.  
  4022.             assert(opcode != CEE_NOP);
  4023.             assert(opcode != CEE_count);
  4024.             assert(opcode != CEE_ILLEGAL);
  4025.         }
  4026.         else if ((srcVtp == TYP_LONG || srcVtp == TYP_ULONG) && dstVtp < TYP_INT)
  4027.         {
  4028.             genOpcode(CEE_CONV_I4);
  4029.         }
  4030.         else if (opcode == CEE_CONV_R_UN)
  4031.         {
  4032.             genOpcode(opcode);
  4033.  
  4034.             opcode = (dstVtp == TYP_FLOAT) ? CEE_CONV_R4
  4035.                                            : CEE_CONV_R8;
  4036.         }
  4037.  
  4038.         if  (opcode != CEE_NOP)
  4039.             genOpcode(opcode);
  4040.  
  4041.         return;
  4042.     }
  4043.  
  4044.     switch (dstVtp)
  4045.     {
  4046.     case TYP_WCHAR:
  4047.         assert(varTypeIsArithmetic(srcVtp) || srcVtp == TYP_WCHAR || srcVtp == TYP_BOOL);
  4048.         goto ARITH;
  4049.  
  4050.     case TYP_CHAR:
  4051.     case TYP_UCHAR:
  4052.     case TYP_SHORT:
  4053.     case TYP_USHORT:
  4054.     case TYP_INT:
  4055.     case TYP_UINT:
  4056.     case TYP_NATINT:
  4057.     case TYP_NATUINT:
  4058.     case TYP_LONG:
  4059.     case TYP_ULONG:
  4060.     case TYP_FLOAT:
  4061.     case TYP_DOUBLE:
  4062.  
  4063.         if  (srcVtp == TYP_REF)
  4064.         {
  4065.             assert(expr->tnOper == TN_CNS_STR);
  4066.             genExpr(expr, true);
  4067.             return;
  4068.         }
  4069.  
  4070.         if  (srcVtp == TYP_PTR && genComp->cmpConfig.ccTgt64bit)
  4071.         {
  4072. //          printf("Possible bad cast at %s(%u)\n", genComp->cmpErrorComp->sdComp.sdcSrcFile,
  4073. //                                                  genComp->cmpErrorTree->tnLineNo);
  4074.             srcVtp =  TYP_NATUINT;
  4075.         }
  4076.  
  4077.         assert(varTypeIsArithmetic(srcVtp) || srcVtp == TYP_WCHAR || srcVtp == TYP_BOOL);
  4078.         goto ARITH;
  4079.  
  4080.     case TYP_REF:
  4081.  
  4082.         type = type->tdRef.tdrBase;
  4083.  
  4084.     case TYP_ARRAY:
  4085.  
  4086.         assert(dstVtp == TYP_REF ||
  4087.                dstVtp == TYP_ARRAY);
  4088.  
  4089.         assert(srcVtp == TYP_REF ||
  4090.                srcVtp == TYP_ARRAY);
  4091.  
  4092.         genExpr(expr, true);
  4093.  
  4094.         if  (flags & TNF_CHK_CAST)
  4095.         {
  4096.             if  (type->tdIsGenArg)
  4097.             {
  4098.                 printf("WARNING: cast to generic type argument '%s' will not be checked\n", genStab->stTypeName(type, NULL));
  4099.             }
  4100.             else
  4101.                 genOpcode_tok(CEE_CASTCLASS, genTypeRef(type));
  4102.         }
  4103.  
  4104. #if 0
  4105.  
  4106.         if  (flags & TNF_CTX_CAST)
  4107.         {
  4108.             unsigned        srcCtx = 0;
  4109.             unsigned        dstCtx = 0;
  4110.  
  4111.             if  (srcVtp == TYP_REF)
  4112.             {
  4113.                 srcTyp = srcTyp->tdRef.tdrBase;
  4114.                 if  (srcTyp->tdTypeKind == TYP_CLASS)
  4115.                     srcCtx = srcTyp->tdClass.tdcContext;
  4116.             }
  4117.  
  4118.             if  (type->tdTypeKindGet() == TYP_CLASS)
  4119.                 dstCtx = type->tdClass.tdcContext;
  4120.  
  4121. //          printf("Src type [%u] '%s'\n", srcCtx, genStab->stTypeName(expr->tnType, NULL));
  4122. //          printf("Dst type [%u] '%s'\n", dstCtx, genStab->stTypeName(type        , NULL));
  4123.  
  4124.             assert((srcCtx == 2) != (dstCtx == 2));
  4125.  
  4126.             genOpcode(srcCtx ? CEE_TOPROXY : CEE_FROMPROXY);
  4127.         }
  4128.  
  4129. #endif
  4130.  
  4131.         return;
  4132.  
  4133.     case TYP_PTR:
  4134.  
  4135.         /* Presumably a cast that doesn't really change anything [ISSUE: is this correct?] */
  4136.  
  4137.         genExpr(expr, true);
  4138.         return;
  4139.  
  4140.     case TYP_ENUM:
  4141.  
  4142.         dstVtp = compiler::cmpEnumBaseVtp(type);
  4143.         goto AGAIN;
  4144.  
  4145.     case TYP_REFANY:
  4146.  
  4147.         assert(expr->tnOper == TN_ADDROF);
  4148.  
  4149.         genExpr(expr, true);
  4150.  
  4151.         genOpcode_tok(CEE_MKREFANY, genTypeRef(expr->tnOp.tnOp1->tnType));
  4152.  
  4153.         return;
  4154.  
  4155.     case TYP_BOOL:
  4156.  
  4157.         /* Casts to bool should never be encountered here */
  4158.  
  4159.         NO_WAY(!"unexpected cast to bool found in codegen");
  4160.  
  4161.     default:
  4162. #ifdef DEBUG
  4163.         genComp->cmpParser->parseDispTree(expr);
  4164.         printf("The above expression is, alas, being cast to '%s'\n", genStab->stTypeName(type, NULL));
  4165. #endif
  4166.         assert(!"invalid cast type");
  4167.     }
  4168. }
  4169.  
  4170. /*****************************************************************************
  4171.  *
  4172.  *  Add the given delta to an operand of the specified type.
  4173.  */
  4174.  
  4175. void                genIL::genIncDecByExpr(int delta, TypDef type)
  4176. {
  4177.     bool            convVal = false;
  4178.     var_types       valType = type->tdTypeKindGet();
  4179.  
  4180.     /* See what type we're dealing with */
  4181.  
  4182.     switch (valType)
  4183.     {
  4184.     case TYP_PTR:
  4185.     case TYP_REF:
  4186.  
  4187.         /* Scale the delta value by the size of the pointed-to type */
  4188.  
  4189.         delta  *= genComp->cmpGetTypeSize(type->tdRef.tdrBase);
  4190.  
  4191. #pragma message("forcing 64-bit increment value")
  4192.         valType = genComp->cmpConfig.ccTgt64bit ? TYP_LONG : TYP_INT;
  4193.         break;
  4194.  
  4195.     case TYP_CHAR:
  4196.     case TYP_UCHAR:
  4197.     case TYP_WCHAR:
  4198.     case TYP_SHORT:
  4199.     case TYP_USHORT:
  4200.  
  4201.         /* We'll have to shrink the new value to maintain precision */
  4202.  
  4203.         convVal = true;
  4204.         break;
  4205.     }
  4206.  
  4207.     /* Compute the new value by adding/subtracting the delta */
  4208.  
  4209.     if  (delta > 0)
  4210.     {
  4211.         genAnyConst( delta, valType);
  4212.         genOpcode(CEE_ADD);
  4213.     }
  4214.     else
  4215.     {
  4216.         genAnyConst(-delta, valType);
  4217.         genOpcode(CEE_SUB);
  4218.     }
  4219.  
  4220.     /* Convert the value if necessary */
  4221.  
  4222.     if  (convVal)
  4223.         genOpcodeNN(genConvOpcode(TYP_INT, valType));
  4224. }
  4225.  
  4226. /*****************************************************************************
  4227.  *
  4228.  *  Generate an assignment operator (such as "+=") or a pre/post increment or
  4229.  *  decrement where the target is a Common Type System array element. The arguments should be
  4230.  *  passed in as follows:
  4231.  *
  4232.  *      op=
  4233.  *
  4234.  *              expr     ....   the op= node itself
  4235.  *              delta    ....   ignored
  4236.  *              post     ....   false
  4237.  *              asgop    ....   true
  4238.  *
  4239.  *      ++/--
  4240.  *
  4241.  *              expr     ....   the target
  4242.  *              delta    ....   the amount to be added
  4243.  *              post     ....   true if the operator is post-inc/dec
  4244.  *              asgop    ....   false
  4245.  */
  4246.  
  4247. void                genIL::genCTSindexAsgOp(Tree    expr,
  4248.                                             int     delta,
  4249.                                             bool    post,
  4250.                                             bool    asgop, bool valUsed)
  4251. {
  4252.     TypDef          dstType;
  4253.     var_types       dstVtyp;
  4254.  
  4255.     Tree            dstExpr;
  4256.     Tree            srcExpr;
  4257.  
  4258.     Tree            addrExp;
  4259.     Tree            indxExp;
  4260.  
  4261.     unsigned        tempNum;
  4262.     unsigned        indxTmp;
  4263.     unsigned        addrTmp;
  4264.  
  4265.     if  (asgop)
  4266.     {
  4267.         dstExpr = expr->tnOp.tnOp1;
  4268.         srcExpr = expr->tnOp.tnOp2;
  4269.     }
  4270.     else
  4271.     {
  4272.         dstExpr = expr;
  4273.         srcExpr = NULL;
  4274.     }
  4275.  
  4276.     dstType = dstExpr->tnType;
  4277.     dstVtyp = dstExpr->tnVtypGet();
  4278.  
  4279.     assert(dstExpr->tnOper == TN_INDEX);
  4280.     assert(dstExpr->tnOp.tnOp1->tnVtyp == TYP_ARRAY);
  4281.     assert(dstExpr->tnOp.tnOp1->tnType->tdIsManaged);
  4282.  
  4283.     /* Get hold of the address/index expressions and generate them */
  4284.  
  4285.     addrExp = dstExpr->tnOp.tnOp1; genExpr(addrExp, true);
  4286.     indxExp = dstExpr->tnOp.tnOp2; genExpr(indxExp, true);
  4287.  
  4288.     /* Grab temps for the address and index and save both */
  4289.  
  4290.     addrTmp = genTempVarGet(addrExp->tnType);
  4291.     indxTmp = genTempVarGet(indxExp->tnType);
  4292.  
  4293.     genLclVarRef(indxTmp, true);
  4294.     genOpcode(CEE_DUP);
  4295.     genLclVarRef(addrTmp, true);
  4296.  
  4297.     /* Reload the index, leaving [addr,index] on the stack */
  4298.  
  4299.     genLclVarRef(indxTmp, false);
  4300.  
  4301.     /* Reload the addr and index and fetch the old value */
  4302.  
  4303.     genLclVarRef(addrTmp, false);
  4304.     genLclVarRef(indxTmp, false);
  4305.     genRef(dstExpr, false);
  4306.  
  4307.     /* Both of the temps can be freed up now */
  4308.  
  4309.     genTempVarRls(indxExp->tnType, indxTmp);
  4310.     genTempVarRls(addrExp->tnType, addrTmp);
  4311.  
  4312.     /* Do we need the result of the expression? */
  4313.  
  4314.     if  (valUsed)
  4315.     {
  4316.         /* Yes, grab a temp for it then */
  4317.  
  4318.         tempNum = genTempVarGet(dstType);
  4319.  
  4320.         /* Save the old value if necessary */
  4321.  
  4322.         if  (post)
  4323.         {
  4324.             genOpcode(CEE_DUP);
  4325.             genLclVarRef(tempNum, true);
  4326.         }
  4327.     }
  4328.  
  4329.     /* Compute the new value */
  4330.  
  4331.     if  (asgop)
  4332.     {
  4333.         assert(post == false);
  4334.  
  4335.         /* Compute the RHS value */
  4336.  
  4337.         genExpr(srcExpr, true);
  4338.  
  4339.         /* Generate the opcode to perform the operation */
  4340.  
  4341.         genOpcode(genBinopOpcode(expr->tnOperGet(), expr->tnVtypGet()));
  4342.  
  4343.         /* If the value is smaller than int, convert it before assigning */
  4344.  
  4345.         if  (dstVtyp < TYP_INT && dstVtyp != TYP_BOOL)  // is this right?????
  4346.             genOpcode(genConvOpcode(TYP_INT, dstVtyp));
  4347.     }
  4348.     else
  4349.     {
  4350.         genIncDecByExpr(delta, dstType);
  4351.     }
  4352.  
  4353.     if  (valUsed)
  4354.     {
  4355.         /* Save the new value if necessary */
  4356.  
  4357.         if  (!post)
  4358.         {
  4359.             genOpcode(CEE_DUP);
  4360.             genLclVarRef(tempNum, true);
  4361.         }
  4362.  
  4363.         /* Store the new value in the target */
  4364.  
  4365.         genRef(dstExpr, true);
  4366.  
  4367.         /* Reload the saved value and free up the temp */
  4368.  
  4369.         genLclVarRef(tempNum, false);
  4370.         genTempVarRls(dstType, tempNum);
  4371.     }
  4372.     else
  4373.     {
  4374.         /* Store the new value in the target */
  4375.  
  4376.         genRef(dstExpr, true);
  4377.     }
  4378. }
  4379.  
  4380. /*****************************************************************************
  4381.  *
  4382.  *  Generate code for an ++ / -- operator.
  4383.  */
  4384.  
  4385. void                genIL::genIncDec(Tree expr, int delta, bool post, bool valUsed)
  4386. {
  4387.     unsigned        addrCnt;
  4388.     unsigned        tempNum;
  4389.  
  4390. #ifdef  DEBUG
  4391.     unsigned        stkLvl = genCurStkLvl;
  4392. #endif
  4393.  
  4394.     /* Bitfield operations are handled elsewhere */
  4395.  
  4396.     if  (expr->tnOper == TN_BFM_SYM)
  4397.     {
  4398.         genBitFieldSt(expr, NULL, NULL, delta, post, valUsed);
  4399.         return;
  4400.     }
  4401.  
  4402.     /* Generate the object pointer value, if one is needed */
  4403.  
  4404.     addrCnt = genAdr(expr);
  4405.  
  4406.     if  (addrCnt)
  4407.     {
  4408.         if  (addrCnt == 1)
  4409.         {
  4410.             /* There is an object address: duplicate it */
  4411.  
  4412.             genOpcode(CEE_DUP);
  4413.         }
  4414.         else
  4415.         {
  4416.             Tree            addrExp;
  4417.             Tree            indxExp;
  4418.  
  4419.             unsigned        indxTmp;
  4420.             unsigned        addrTmp;
  4421.  
  4422.             assert(addrCnt == 2);
  4423.             assert(expr->tnOper == TN_INDEX);
  4424.  
  4425.             /* We have a Common Type System array element, save address and index */
  4426.  
  4427.             addrExp = expr->tnOp.tnOp1;
  4428.             indxExp = expr->tnOp.tnOp2;
  4429.  
  4430.             /* Grab temps for the address and index and save both */
  4431.  
  4432.             addrTmp = genTempVarGet(addrExp->tnType);
  4433.             indxTmp = genTempVarGet(indxExp->tnType);
  4434.  
  4435.             genLclVarRef(indxTmp, true);
  4436.             genOpcode(CEE_DUP);
  4437.             genLclVarRef(addrTmp, true);
  4438.  
  4439.             /* Reload the index, leaving [addr,index] on the stack */
  4440.  
  4441.             genLclVarRef(indxTmp, false);
  4442.  
  4443.             /* Reload the addr and index and fetch the old value */
  4444.  
  4445.             genLclVarRef(addrTmp, false);
  4446.             genLclVarRef(indxTmp, false);
  4447.             genRef(expr, false);
  4448.  
  4449.             /* Both of the temps can be freed up now */
  4450.  
  4451.             genTempVarRls(indxExp->tnType, indxTmp);
  4452.             genTempVarRls(addrExp->tnType, addrTmp);
  4453.  
  4454.             /* Do we need the result of the expression? */
  4455.  
  4456.             if  (valUsed)
  4457.             {
  4458.                 tempNum = genTempVarGet(expr->tnType);
  4459.  
  4460.                 /* Save the old value if necessary */
  4461.  
  4462.                 if  (post != false)
  4463.                 {
  4464.                     genOpcode(CEE_DUP);
  4465.                     genLclVarRef(tempNum, true);
  4466.                 }
  4467.  
  4468.                 /* Compute the new value */
  4469.  
  4470.                 genIncDecByExpr(delta, expr->tnType);
  4471.  
  4472.                 /* Save the new value if necessary */
  4473.  
  4474.                 if  (post == false)
  4475.                 {
  4476.                     genOpcode(CEE_DUP);
  4477.                     genLclVarRef(tempNum, true);
  4478.                 }
  4479.  
  4480.                 /* Store the new value in the target */
  4481.  
  4482.                 genRef(expr, true);
  4483.  
  4484.                 /* Reload the saved value and free up the temp */
  4485.  
  4486.                 genLclVarRef(tempNum, false);
  4487.                 genTempVarRls(expr->tnType, tempNum);
  4488.             }
  4489.             else
  4490.             {
  4491.                 /* Compute the new value */
  4492.  
  4493.                 genIncDecByExpr(delta, expr->tnType);
  4494.  
  4495.                 /* Store the new value in the target */
  4496.  
  4497.                 genRef(expr, true);
  4498.             }
  4499.  
  4500.             return;
  4501.         }
  4502.     }
  4503.  
  4504.     /* Load the old value */
  4505.  
  4506.     genRef(expr, false);
  4507.  
  4508.     /* If the result of is used, we'll need a temp */
  4509.  
  4510.     if  (valUsed)
  4511.     {
  4512.         /* Grab a temp of the right type */
  4513.  
  4514.         tempNum = genTempVarGet(expr->tnType);
  4515.  
  4516.         if  (post)
  4517.         {
  4518.             /* Save the old value in the temp */
  4519.  
  4520.             genLclVarRef(tempNum, true);
  4521.  
  4522.             /* Reload the old value so we can inc/dec it */
  4523.  
  4524.             genLclVarRef(tempNum, false);
  4525.         }
  4526.     }
  4527.  
  4528.     genIncDecByExpr(delta, expr->tnType);
  4529.  
  4530.     /* Is this a pre-inc/dec or post-inc/dec operator? */
  4531.  
  4532.     if  (post)
  4533.     {
  4534.         /* Store the new value in the lvalue */
  4535.  
  4536.         genRef(expr, true);
  4537.     }
  4538.     else
  4539.     {
  4540.         if  (valUsed)
  4541.         {
  4542.             /* Save a copy of the new value in the temp */
  4543.  
  4544.             genOpcode(CEE_DUP);
  4545.             genLclVarRef(tempNum, true);
  4546.         }
  4547.  
  4548.         /* Store the new value in the lvalue */
  4549.  
  4550.         genRef(expr, true);
  4551.     }
  4552.  
  4553.     /* Load the old/new value from the temp where we saved it */
  4554.  
  4555.     if  (valUsed)
  4556.     {
  4557.         genLclVarRef(tempNum, false);
  4558.  
  4559.         /* If we grabbed a temp, free it now */
  4560.  
  4561.         genTempVarRls(expr->tnType, tempNum);
  4562.     }
  4563.  
  4564.     assert(genCurStkLvl == stkLvl + (int)valUsed);
  4565. }
  4566.  
  4567. /*****************************************************************************
  4568.  *
  4569.  *  Generate code for an assignment operator (e.g. "+=").
  4570.  */
  4571.  
  4572. void                genIL::genAsgOper(Tree expr, bool valUsed)
  4573. {
  4574.     Tree            op1     = expr->tnOp.tnOp1;
  4575.     Tree            op2     = expr->tnOp.tnOp2;
  4576.  
  4577.     var_types       dstType =  op1->tnVtypGet();
  4578.  
  4579.     bool            haveAddr;
  4580.     unsigned        tempNum;
  4581.  
  4582.     /* Check for a bitfield target */
  4583.  
  4584.     if  (op1->tnOper == TN_BFM_SYM)
  4585.     {
  4586.         genBitFieldSt(op1, NULL, expr, 0, true, valUsed);
  4587.         return;
  4588.     }
  4589.  
  4590.     /* We'll need to refer to the target address twice or thrice */
  4591.  
  4592.     switch (op1->tnOper)
  4593.     {
  4594.         unsigned        checkCnt;
  4595.  
  4596.         SymDef          sym;
  4597.  
  4598.     case TN_LCL_SYM:
  4599.  
  4600.     SREF:
  4601.  
  4602.         /* Load the old value of the destination */
  4603.  
  4604.         genExpr(op1, true);
  4605.  
  4606.         haveAddr = false;
  4607.         break;
  4608.  
  4609.     case TN_VAR_SYM:
  4610.  
  4611.         sym = op1->tnVarSym.tnVarSym; assert(sym->sdSymKind == SYM_VAR);
  4612.  
  4613.         /* Is this a non-static class member? */
  4614.  
  4615.         if  (!sym->sdIsMember)
  4616.             goto SREF;
  4617.         if  (sym->sdIsStatic)
  4618.             goto SREF;
  4619.  
  4620.         /* For managed members we use ldfld/stfld */
  4621.  
  4622.         if  (sym->sdIsManaged)
  4623.         {
  4624.             genExpr(op1->tnVarSym.tnVarObj, true);
  4625.             goto SAVE;
  4626.         }
  4627.  
  4628.         // Fall through ...
  4629.  
  4630.     case TN_IND:
  4631.  
  4632.     ADDR:
  4633.  
  4634.         checkCnt = genAdr(op1, true); assert(checkCnt == 1);
  4635.  
  4636.     SAVE:
  4637.  
  4638.         haveAddr = true;
  4639.  
  4640.         /* Make a copy of the address */
  4641.  
  4642.         genOpcode(CEE_DUP);
  4643.  
  4644.         /* Load the old value of the destination */
  4645.  
  4646.         genRef(op1, false);
  4647.         break;
  4648.  
  4649.     case TN_INDEX:
  4650.  
  4651.         /* Is this a managed or unmanaged array? */
  4652.  
  4653.         if  (op1->tnOp.tnOp1->tnVtyp == TYP_ARRAY &&
  4654.              op1->tnOp.tnOp1->tnType->tdIsManaged)
  4655.         {
  4656.             genCTSindexAsgOp(expr, 0, false, true, valUsed);
  4657.             return;
  4658.         }
  4659.  
  4660.         goto ADDR;
  4661.  
  4662.     default:
  4663.         NO_WAY(!"unexpected asgop dest");
  4664.     }
  4665.  
  4666.     /* Compute the RHS value */
  4667.  
  4668.     genExpr(op2, true);
  4669.  
  4670.     /* Generate the opcode to perform the operation */
  4671.  
  4672.     genOpcode(genBinopOpcode(expr->tnOperGet(), genExprVtyp(expr)));
  4673.  
  4674.     /* If the value is smaller than int, convert it before assigning */
  4675.  
  4676.     if  (dstType < TYP_INT && dstType != TYP_BOOL)  // is this right?????
  4677.         genOpcode(genConvOpcode(TYP_INT, dstType));
  4678.  
  4679.     /* Did we have an indirection or a simple local variable destination? */
  4680.  
  4681.     if  (haveAddr)
  4682.     {
  4683.         if  (valUsed)
  4684.         {
  4685.             /* Save a copy of the new value in a temp */
  4686.  
  4687.             tempNum = genTempVarGet(expr->tnType);
  4688.  
  4689.             genOpcode(CEE_DUP);
  4690.             genLclVarRef(tempNum, true);
  4691.         }
  4692.  
  4693.         /* Store the new value in the target */
  4694.  
  4695.         genRef(op1, true);
  4696.  
  4697.         /* Is the result of the assignment used? */
  4698.  
  4699.         if  (valUsed)
  4700.         {
  4701.             /* Load the saved value and free up the temp */
  4702.  
  4703.             genLclVarRef(tempNum, false);
  4704.             genTempVarRls(expr->tnType, tempNum);
  4705.         }
  4706.     }
  4707.     else
  4708.     {
  4709.         genRef(op1, true);
  4710.  
  4711.         if  (valUsed)
  4712.             genRef(op1, false);
  4713.     }
  4714. }
  4715.  
  4716. /*****************************************************************************
  4717.  *
  4718.  *  Generate any side effects in the given expression.
  4719.  */
  4720.  
  4721. void                genIL::genSideEff(Tree expr)
  4722. {
  4723.     treeOps         oper;
  4724.     unsigned        kind;
  4725.  
  4726. AGAIN:
  4727.  
  4728.     assert(expr);
  4729. #if!MGDDATA
  4730.     assert((int)expr != 0xCCCCCCCC && (int)expr != 0xDDDDDDDD);
  4731. #endif
  4732.     assert(expr->tnType && expr->tnType->tdTypeKind == expr->tnVtyp);
  4733.  
  4734.     /* Classify the root node */
  4735.  
  4736.     oper = expr->tnOperGet ();
  4737.     kind = expr->tnOperKind();
  4738.  
  4739.     /* Is this a constant or leaf node? */
  4740.  
  4741.     if  (kind & (TNK_CONST|TNK_LEAF))
  4742.         return;
  4743.  
  4744.     /* Is it a 'simple' unary/binary operator? */
  4745.  
  4746.     if  (kind & TNK_SMPOP)
  4747.     {
  4748.         /* Is this an assignment or a potential exception? */
  4749.  
  4750.         if  ((kind & TNK_ASGOP) || expr->tnOperMayThrow())
  4751.         {
  4752.             genExpr(expr, false);
  4753.             return;
  4754.         }
  4755.  
  4756.         /* Is there a second operand? */
  4757.  
  4758.         if  (expr->tnOp.tnOp2)
  4759.         {
  4760.             if  (expr->tnOp.tnOp1)
  4761.                 genSideEff(expr->tnOp.tnOp1);
  4762.  
  4763.             expr = expr->tnOp.tnOp2;
  4764.             goto AGAIN;
  4765.         }
  4766.  
  4767.         expr = expr->tnOp.tnOp1;
  4768.         if  (expr)
  4769.             goto AGAIN;
  4770.  
  4771.         return;
  4772.     }
  4773.  
  4774.     /* See what kind of a special operator we have here */
  4775.  
  4776.     switch  (oper)
  4777.     {
  4778.     case TN_VAR_SYM:
  4779.         expr = expr->tnVarSym.tnVarObj;
  4780.         if  (expr)
  4781.             goto AGAIN;
  4782.         return;
  4783.  
  4784.     case TN_FNC_SYM:
  4785.         genCall(expr, false);
  4786.         return;
  4787.     }
  4788. }
  4789.  
  4790. /*****************************************************************************
  4791.  *
  4792.  *  Generate MSIL for the bounds of an array being allocated.
  4793.  */
  4794.  
  4795. unsigned            genIL::genArrBounds(TypDef type, OUT TypDef REF elemRef)
  4796. {
  4797.     TypDef          elem;
  4798.     unsigned        dcnt;
  4799.     DimDef          dims;
  4800.  
  4801.     assert(type->tdTypeKind == TYP_ARRAY && type->tdIsManaged);
  4802.  
  4803.     elem = genComp->cmpDirectType(type->tdArr.tdaElem);
  4804.  
  4805.     /* Recursively process the element if it's also an array type */
  4806.  
  4807.     if  (elem->tdTypeKind == TYP_ARRAY && elem->tdIsManaged)
  4808.     {
  4809.         dcnt    = genArrBounds(elem, elemRef);
  4810.     }
  4811.     else
  4812.     {
  4813.         dcnt    = 0;
  4814.         elemRef = elem;
  4815.     }
  4816.  
  4817.     dims = type->tdArr.tdaDims; assert(dims);
  4818.  
  4819.     do
  4820.     {
  4821.         if  (dims->ddNoDim)
  4822.         {
  4823.             genIntConst(0);
  4824.         }
  4825.         else
  4826.         {
  4827.             assert(dims->ddDimBound);
  4828.  
  4829.             if  (dims->ddIsConst)
  4830.                 genIntConst(dims->ddSize);
  4831.             else
  4832.                 genExpr(dims->ddLoTree, true);
  4833.  
  4834.             if  (dims->ddHiTree)
  4835.                 genExpr(dims->ddHiTree, true);
  4836.         }
  4837.  
  4838.         dcnt++;
  4839.  
  4840.         dims = dims->ddNext;
  4841.     }
  4842.     while (dims);
  4843.  
  4844.     return  dcnt;
  4845. }
  4846.  
  4847. /*****************************************************************************
  4848.  *
  4849.  *  Generate MSIL for a "new" expression. If "dstx" is non-NULL the result of
  4850.  *  the expression is to be assigned to the given destination.
  4851.  */
  4852.  
  4853. void                genIL::genNewExpr(Tree expr, bool valUsed, Tree dstx)
  4854. {
  4855.     TypDef          type;
  4856.     var_types       otyp;
  4857.     var_types       vtyp;
  4858.  
  4859.     assert(expr->tnOper == TN_NEW);
  4860.  
  4861.     /* Make sure the caller didn't mess up */
  4862.  
  4863.     assert(dstx == NULL || expr->tnVtyp == TYP_CLASS && !expr->tnType->tdIsIntrinsic);
  4864.  
  4865.     /* What kind of a value is the "new" trying to allocate? */
  4866.  
  4867.     type = expr->tnType;
  4868.     if  (expr->tnOp.tnOp2 && expr->tnOp.tnOp2->tnOper == TN_NONE)
  4869.         type = expr->tnOp.tnOp2->tnType;
  4870.  
  4871.     vtyp = otyp = type->tdTypeKindGet();
  4872.  
  4873.     if  (vtyp <= TYP_lastIntrins)
  4874.     {
  4875.         /* Locate the appropriate built-in value type */
  4876.  
  4877.         type = genComp->cmpFindStdValType(vtyp); assert(type);
  4878.         vtyp = TYP_CLASS; assert(vtyp == type->tdTypeKind);
  4879.     }
  4880.  
  4881.     switch (vtyp)
  4882.     {
  4883.         ILblock         labTemp;
  4884.  
  4885.     case TYP_CLASS:
  4886.         if  (dstx)
  4887.         {
  4888.             unsigned        cnt;
  4889.  
  4890.             cnt = genAdr(dstx, true); assert(cnt == 1);
  4891.  
  4892.             genCall(expr, false);
  4893.  
  4894.             assert(valUsed == false);
  4895.         }
  4896.         else
  4897.         {
  4898.             unsigned        tmp = genTempVarGet(type);
  4899.  
  4900.             genLclVarAdr(tmp);
  4901.             genCall(expr, false);
  4902.  
  4903.             if  (valUsed)
  4904.                 genLclVarRef(tmp, false);
  4905.  
  4906.             genTempVarRls(type, tmp);
  4907.         }
  4908.         return;
  4909.  
  4910.     case TYP_REF:
  4911.         if  (expr->tnOp.tnOp1->tnFlags & TNF_CALL_STRCAT)
  4912.         {
  4913.             genCall(expr, valUsed);
  4914.         }
  4915.         else
  4916.         {
  4917.             genCall(expr, true);
  4918.             if  (!valUsed)
  4919.                 genOpcode(CEE_POP);
  4920.         }
  4921.         return;
  4922.  
  4923.     case TYP_PTR:
  4924.  
  4925.         assert(dstx == NULL);
  4926.  
  4927.         /* Generate the size of the class and call 'operator new' */
  4928.  
  4929.         genIntConst(genComp->cmpGetTypeSize(type->tdRef.tdrBase));
  4930.         genOpcode_tok(CEE_CALL, genMethodRef(genComp->cmpFNumgOperNewGet(), false));
  4931.  
  4932.         /* Duplicate the result so that we can test it */
  4933.  
  4934.         labTemp = genFwdLabGet();
  4935.  
  4936.         genOpcode(CEE_DUP);
  4937.         genOpcode_lab(CEE_BRFALSE, labTemp);
  4938.         genCurStkLvl--;
  4939.  
  4940.         /* Now call the ctor for the class */
  4941.  
  4942.         genOpcode(CEE_DUP);
  4943.         genCall(expr->tnOp.tnOp1, false);
  4944.  
  4945.         /* The result will remain on the stack */
  4946.  
  4947.         genFwdLabDef(labTemp);
  4948.         return;
  4949.  
  4950.     case TYP_ARRAY:
  4951.  
  4952.         /* Are we allocating a managed or unmanaged array? */
  4953.  
  4954.         if  (type->tdIsManaged)
  4955.         {
  4956.             TypDef          elem;
  4957.             unsigned        slvl = genCurStkLvl;
  4958.             unsigned        dcnt = 0;
  4959.  
  4960.             /* Is there an array initializer? */
  4961.  
  4962.             if  (expr->tnOp.tnOp1)
  4963.             {
  4964.                 assert(expr->tnOp.tnOp1->tnOper == TN_ARR_INIT ||
  4965.                        expr->tnOp.tnOp1->tnOper == TN_ERROR);
  4966.                 genExpr(expr->tnOp.tnOp1, valUsed);
  4967.                 return;
  4968.             }
  4969.  
  4970.             /* We need to generate the list of dimensions */
  4971.  
  4972.             dcnt = genArrBounds(type, elem);
  4973.  
  4974.             /* Generate the opcode with the appropriate type token */
  4975.  
  4976.             if  (dcnt > 1)
  4977.             {
  4978.                 /* We need to generate "newobj array::ctor" */
  4979.  
  4980.                 genOpcode_tok(CEE_NEWOBJ, genComp->cmpArrayCTtoken(type, elem, dcnt));
  4981.             }
  4982.             else
  4983.             {
  4984.                 /* Single-dim array, we can use a simple opcode */
  4985.  
  4986.                 genOpcode_tok(CEE_NEWARR, genTypeRef(elem));
  4987.             }
  4988.  
  4989.             /* The dimensions will all be popped, array addr pushed */
  4990.  
  4991.             genCurStkLvl = slvl + 1;
  4992.         }
  4993.         else
  4994.         {
  4995. #ifdef  DEBUG
  4996.             genComp->cmpParser->parseDispTree(expr);
  4997. #endif
  4998.             UNIMPL(!"gen MSIL for 'new' of an unmanaged array");
  4999.         }
  5000.         break;
  5001.  
  5002.     default:
  5003. #ifdef  DEBUG
  5004.         genComp->cmpParser->parseDispTree(expr);
  5005. #endif
  5006.         UNIMPL(!"gen new of some weird type");
  5007.     }
  5008.  
  5009.     if  (!valUsed)
  5010.         genOpcode(CEE_POP);
  5011. }
  5012.  
  5013. /*****************************************************************************
  5014.  *
  5015.  *  Generate MSIL for a call expression.
  5016.  */
  5017.  
  5018. void                genIL::genCall(Tree expr, bool valUsed)
  5019. {
  5020.     SymDef          fncSym;
  5021.     TypDef          fncTyp;
  5022.  
  5023.     TypDef          retType;
  5024.  
  5025.     Tree            objPtr;
  5026.  
  5027.     Tree            argLst;
  5028.     unsigned        argCnt;
  5029.  
  5030.     bool            strArr;
  5031.  
  5032.     bool            isNew;
  5033.     bool            indir;
  5034.     bool            CTcall;
  5035.  
  5036.     Tree            adrDst = NULL;
  5037.     unsigned        adrCnt;
  5038.  
  5039.     mdToken         methRef;
  5040.  
  5041.     unsigned        tempNum;
  5042.     bool            tempUsed = false;
  5043.     TypDef          tempType;
  5044.  
  5045.     TypDef          asgType = NULL;
  5046.  
  5047. //  bool            isIntf  = false;
  5048.     bool            isVirt  = false;
  5049.     bool            umVirt  = false;
  5050.  
  5051.     assert(expr->tnOper == TN_FNC_SYM ||
  5052.            expr->tnOper == TN_CALL    ||
  5053.            expr->tnOper == TN_NEW);
  5054.  
  5055.     /* Keep track of how many arguments we've pushed */
  5056.  
  5057.     argCnt = genCurStkLvl;
  5058.  
  5059.     /* Is this a direct or indirect call? */
  5060.  
  5061.     switch (expr->tnOper)
  5062.     {
  5063.     case TN_FNC_SYM:
  5064.  
  5065.         /* Get hold of the function symbol */
  5066.  
  5067.         fncSym = expr->tnFncSym.tnFncSym; assert(fncSym->sdFnc.sdfDisabled == false);
  5068.  
  5069.         /* Process the object address if it's present */
  5070.  
  5071.         objPtr = expr->tnFncSym.tnFncObj;
  5072.  
  5073.         if  (fncSym->sdIsStatic || !fncSym->sdIsMember)
  5074.         {
  5075.             /* Generate side effects in the object expression, if any */
  5076.  
  5077.             if  (objPtr)
  5078.                 genSideEff(objPtr);
  5079.         }
  5080.         else
  5081.         {
  5082.             TypDef          clsTyp = fncSym->sdParent->sdType;
  5083.  
  5084.             /* This must be a member function */
  5085.  
  5086.             assert(clsTyp->tdTypeKind == TYP_CLASS);
  5087.  
  5088.             /* Is the method (and the call to it) virtual? */
  5089.  
  5090.             if  (fncSym->sdFnc.sdfVirtual && !fncSym->sdIsSealed)
  5091.             {
  5092.                 if  (expr->tnFlags & TNF_CALL_NVIRT)
  5093.                 {
  5094.                     // We're being asked not to call it virtually, so oblige
  5095.                 }
  5096.                 else if (clsTyp->tdClass.tdcValueType && clsTyp->tdIsManaged)
  5097.                 {
  5098.                     // Managed structs never inherit so virtual is worthless
  5099.                 }
  5100.                 else
  5101.                     isVirt = true;
  5102.             }
  5103.  
  5104.             /* Evaluate the instance pointer if an explicit one is present */
  5105.  
  5106.             if  (objPtr)
  5107.             {
  5108.                 /* We might have to introduce a temp for the operand */
  5109.  
  5110.                 if  (objPtr->tnOper == TN_ADDROF)
  5111.                 {
  5112.                     tempUsed = genGenAddressOf(objPtr->tnOp.tnOp1,
  5113.                                                false,
  5114.                                                &tempNum,
  5115.                                                &tempType);
  5116.  
  5117.                     /* Special case: "lclvar.func()" is not virtual */
  5118.  
  5119.                     if  (objPtr->tnOp.tnOp1->tnOper == TN_LCL_SYM)
  5120.                     {
  5121.                         // ISSUE: Is this correct and sufficient?
  5122.  
  5123.                         isVirt = false;
  5124.                     }
  5125.                 }
  5126.                 else
  5127.                     genExpr(objPtr, true);
  5128.             }
  5129.  
  5130.             /* Is it an interface method? */
  5131.  
  5132. //          isIntf = (fncSym->sdParent->sdType->tdClass.tdcFlavor == STF_INTF);
  5133.  
  5134.             /* Is the class managed or unmanaged? */
  5135.  
  5136.             assert(fncSym->sdParent->sdSymKind == SYM_CLASS);
  5137.  
  5138.             if  (!fncSym->sdParent->sdIsManaged && isVirt)
  5139.             {
  5140.                 /* We have an unmanaged virtual call */
  5141.  
  5142.                 umVirt = true;
  5143.  
  5144.                 /*
  5145.                     We'll need to push the "this" value twice, see whether
  5146.                     we need to store it in a temp or whether we can simply
  5147.                     evaluate it twice.
  5148.                  */
  5149.  
  5150.                 assert(objPtr);
  5151.  
  5152.                 if  (tempUsed)
  5153.                 {
  5154.                     UNIMPL("can this really happen?");
  5155.                 }
  5156.                 else
  5157.                 {
  5158.                     if  (objPtr->tnOper == TN_LCL_SYM && !(expr->tnFlags & TNF_CALL_MODOBJ))
  5159.                     {
  5160.                         /* We can simply reuse the instance pointer */
  5161.  
  5162.                         tempUsed = false;
  5163.                     }
  5164.                     else
  5165.                     {
  5166.                         /* We'll have to save the instance ptr in a temp */
  5167.  
  5168.                         tempUsed = true;
  5169.                         tempType = objPtr->tnType;
  5170.                         tempNum  = genTempVarGet(tempType);
  5171.  
  5172.                         /* Store the instance pointer in the temp and reload it */
  5173.  
  5174.                         genLclVarRef(tempNum,  true);
  5175.                         genLclVarRef(tempNum, false);
  5176.                     }
  5177.                 }
  5178.             }
  5179.         }
  5180.  
  5181.         argLst = expr->tnFncSym.tnFncArgs;
  5182.  
  5183.         fncTyp = fncSym->sdType;
  5184.         isNew  =
  5185.         indir  = false;
  5186.  
  5187.         /* Is this an assignment operator? */
  5188.  
  5189.         if  (expr->tnFlags & TNF_CALL_ASGOP)
  5190.         {
  5191.             /* Get hold of the argument */
  5192.  
  5193.             assert(argLst);
  5194.             assert(argLst->tnOper == TN_LIST);
  5195.             assert(argLst->tnOp.tnOp2 == NULL);
  5196.  
  5197.             argLst  = argLst->tnOp.tnOp1;
  5198.             asgType = argLst->tnType;
  5199.  
  5200.             /* Compute the address of the target and make a copy of it */
  5201.  
  5202.             genAdr(argLst, true);
  5203.             genOpcode(CEE_DUP);
  5204.  
  5205.             /* Is the value of the operator used ? */
  5206.  
  5207.             if  (valUsed)
  5208.             {
  5209.                 if  (expr->tnFlags & TNF_CALL_ASGPRE)
  5210.                 {
  5211.                     genOpcode(CEE_DUP);
  5212.                     genOpcode_tok(CEE_LDOBJ, genValTypeRef(asgType));
  5213.                 }
  5214.                 else
  5215.                 {
  5216.                     unsigned        adrTemp;
  5217.                     TypDef          tmpType = genComp->cmpTypeVoid;
  5218.  
  5219.                     /* Allocate a temp to hold the address and save it */
  5220.  
  5221.                     adrTemp = genTempVarGet(tmpType);
  5222.                     genLclVarRef(adrTemp,  true);
  5223.  
  5224.                     /* Load the old value and leave it at the bottom */
  5225.  
  5226.                     genOpcode_tok(CEE_LDOBJ, genValTypeRef(asgType));
  5227.  
  5228.                     /* Reload the address of the target */
  5229.  
  5230.                     genLclVarRef(adrTemp, false);
  5231.  
  5232.                     /* Push a copy of the value as the argument value */
  5233.  
  5234.                     genOpcode(CEE_DUP);
  5235.                     genOpcode_tok(CEE_LDOBJ, genValTypeRef(asgType));
  5236.  
  5237.                     /* We're done with the temp */
  5238.  
  5239.                     genTempVarRls(tmpType, adrTemp);
  5240.                 }
  5241.             }
  5242.             else
  5243.             {
  5244.                 genOpcode_tok(CEE_LDOBJ, genValTypeRef(asgType));
  5245.             }
  5246.  
  5247.             /* We've taken care of the arguments */
  5248.  
  5249.             argLst = NULL;
  5250.             argCnt = genCurStkLvl;
  5251.         }
  5252.  
  5253.         if  (expr->tnFlags & TNF_CALL_STRCAT)
  5254.         {
  5255.             strArr = false;
  5256.  
  5257.             /* Get hold of the target - it's the first argument */
  5258.  
  5259.             assert(argLst && argLst->tnOper == TN_LIST);
  5260.  
  5261.             adrDst = argLst->tnOp.tnOp1;
  5262.  
  5263.             if  (adrDst->tnOper == TN_NEW)
  5264.             {
  5265.                 Tree            arrLst;
  5266.  
  5267.                 /* This is the version that uses a "String[]" constructor */
  5268.  
  5269.                 arrLst = adrDst->tnOp.tnOp1; assert(arrLst->tnOper == TN_ARR_INIT);
  5270.                 adrDst = arrLst->tnOp.tnOp1; assert(adrDst->tnOper == TN_LIST);
  5271.  
  5272.                 /* The first argument is also the destination and result */
  5273.  
  5274.                 adrDst = adrDst->tnOp.tnOp1;
  5275.  
  5276.                 /* Remember which flavor we have */
  5277.  
  5278.                 strArr = true;
  5279.             }
  5280.  
  5281.             assert(genComp->cmpIsStringExpr(adrDst));
  5282.  
  5283.             /* Generate the address of the destination */
  5284.  
  5285.             adrCnt = genAdr(adrDst, false);
  5286.  
  5287.             if  (adrCnt && !strArr)
  5288.             {
  5289.                 /* Do we need to duplicate one or two address values? */
  5290.  
  5291.                 if  (adrCnt == 1)
  5292.                 {
  5293.                     genOpcode(CEE_DUP);
  5294.                 }
  5295.                 else
  5296.                 {
  5297.                     unsigned        adrTmp1;
  5298.                     unsigned        adrTmp2;
  5299.  
  5300.                     assert(adrDst->tnOper == TN_INDEX);
  5301.  
  5302.                     /* Grab temps for the array address and index and save copies */
  5303.  
  5304.                     adrTmp1 = genTempVarGet(adrDst->tnOp.tnOp1->tnType);
  5305.                     adrTmp2 = genTempVarGet(adrDst->tnOp.tnOp2->tnType);
  5306.                     genLclVarRef(adrTmp2, true);
  5307.                     genOpcode(CEE_DUP);
  5308.                     genLclVarRef(adrTmp1, true);
  5309.                     genLclVarRef(adrTmp2, false);
  5310.  
  5311.                     genLclVarRef(adrTmp1, false);
  5312.                     genLclVarRef(adrTmp2, false);
  5313.  
  5314.                     genTempVarRls(adrDst->tnOp.tnOp1->tnType, adrTmp1);
  5315.                     genTempVarRls(adrDst->tnOp.tnOp2->tnType, adrTmp2);
  5316.                 }
  5317.  
  5318.                 argCnt += adrCnt;
  5319.             }
  5320.  
  5321.             if  (!strArr)
  5322.             {
  5323.                 /* Load the old target value and skip over it in the argument list */
  5324.  
  5325.                 genRef(adrDst, false);
  5326.  
  5327.                 if  (argLst->tnOp.tnOp2)
  5328.                     argLst = argLst->tnOp.tnOp2;
  5329.             }
  5330.         }
  5331.  
  5332.         break;
  5333.  
  5334.     case TN_CALL:
  5335.  
  5336.         indir  = true;
  5337.         isNew  = false;
  5338.  
  5339.         assert(expr->tnOper             == TN_CALL);
  5340.         assert(expr->tnOp.tnOp1->tnVtyp == TYP_FNC);
  5341.         assert(expr->tnOp.tnOp1->tnOper == TN_IND);
  5342.  
  5343.         argLst = expr->tnOp.tnOp2;
  5344.         fncTyp = expr->tnOp.tnOp1->tnType;
  5345.  
  5346.         break;
  5347.  
  5348.     default:
  5349.  
  5350.         expr = expr->tnOp.tnOp1;
  5351.  
  5352.         assert(expr && expr->tnOper == TN_FNC_SYM);
  5353.  
  5354.         fncSym = expr->tnFncSym.tnFncSym; assert(fncSym);
  5355.         argLst = expr->tnFncSym.tnFncArgs;
  5356.         fncTyp = fncSym->sdType;
  5357.  
  5358.         indir  = false;
  5359.         isNew  = true;
  5360.         CTcall = false;
  5361.  
  5362.         /* Value types get created via a direct ctor call */
  5363.  
  5364.         assert(fncSym->sdParent->sdSymKind == SYM_CLASS);
  5365.         if  (fncSym->sdParent->sdType->tdClass.tdcValueType)
  5366.             CTcall = true;
  5367.  
  5368.         /* We no longer do string concat via ctor calls */
  5369.  
  5370.         assert((expr->tnFlags & TNF_CALL_STRCAT) == 0);
  5371.         break;
  5372.     }
  5373.  
  5374.     /* Get hold of the function's return type */
  5375.  
  5376.     assert(fncTyp->tdTypeKind == TYP_FNC);
  5377.  
  5378.     retType = genComp->cmpDirectType(fncTyp->tdFnc.tdfRett);
  5379.  
  5380.     /* Generate the argument list */
  5381.  
  5382.     while (argLst)
  5383.     {
  5384.         assert(argLst->tnOper == TN_LIST);
  5385.         genExpr(argLst->tnOp.tnOp1, true);
  5386.         argLst = argLst->tnOp.tnOp2;
  5387.     }
  5388.  
  5389.     /* Is this an unmanaged virtual call? */
  5390.  
  5391.     if  (umVirt)
  5392.     {
  5393.         unsigned        vtblOffs;
  5394.  
  5395.         /* We need to get to the function's address via the vtable */
  5396.  
  5397.         if  (tempUsed)
  5398.         {
  5399.             /* Load the saved instance pointer from the temp */
  5400.  
  5401.             genLclVarRef(tempNum, false);
  5402.         }
  5403.         else
  5404.         {
  5405.             /* Push another copy of the instance pointer */
  5406.  
  5407.             genExpr(objPtr, true);
  5408.         }
  5409.  
  5410.         /* Indirect through the instance pointer to get the vtable address */
  5411.  
  5412.         genOpcode(opcodesIndLoad[TYP_PTR]);
  5413.  
  5414.         /* Add the vtable offset if non-zero */
  5415.  
  5416.         vtblOffs = fncSym->sdFnc.sdfVtblx; assert(vtblOffs);
  5417.  
  5418. //      printf("Vtable offset is %04X for '%s'\n", sizeof(void*) * (vtblOffs - 1), fncSym->sdSpelling());
  5419.  
  5420.         if  (vtblOffs > 1)
  5421.         {
  5422.             genIntConst(sizeof(void*) * (vtblOffs - 1));
  5423.             genOpcode(CEE_ADD);
  5424.         }
  5425.  
  5426.         /* Finally, load the address of the function */
  5427.  
  5428.         genOpcode(opcodesIndLoad[TYP_PTR]);
  5429.  
  5430.         /* We have an indirect call for sure */
  5431.  
  5432.         indir = true;
  5433.     }
  5434.  
  5435.     genMarkStkMax();
  5436.  
  5437.     /* Argument count is equal to how much stuff we've pushed */
  5438.  
  5439.     argCnt = genCurStkLvl - argCnt;
  5440.  
  5441.     /* Figure out the call descriptor/opcode we need to use */
  5442.  
  5443.     if  (indir)
  5444.     {
  5445.         mdToken         sig;
  5446.  
  5447.         /* We need to add "this" for unmanaged virtual calls */
  5448.  
  5449.         if  (umVirt)
  5450.         {
  5451.             sig = genInfFncRef(fncSym->sdType, objPtr->tnType);
  5452.         }
  5453.         else
  5454.         {
  5455.             Tree            adr = expr->tnOp.tnOp1;
  5456.  
  5457.             assert(adr->tnOper == TN_IND);
  5458.  
  5459.             genExpr(adr->tnOp.tnOp1, true); argCnt++;
  5460.  
  5461.             sig = genInfFncRef(expr->tnOp.tnOp1->tnType, NULL);
  5462.         }
  5463.  
  5464.         genOpcode_tok(CEE_CALLI, sig);
  5465.     }
  5466.     else
  5467.     {
  5468.         /*
  5469.             Strange thing - the metadata token used in a vararg call
  5470.             must be a memberref not a methoddef. That means that when
  5471.             we call a varargs function that is also defined locally,
  5472.             we have to make extra effort to generate a separate ref
  5473.             for it even when no extra arguments are passed.
  5474.  
  5475.          */
  5476.  
  5477.         if  (fncSym->sdType->tdFnc.tdfArgs.adVarArgs)
  5478.             expr->tnFlags |= TNF_CALL_VARARG;
  5479.  
  5480.         if  (expr->tnFlags & TNF_CALL_VARARG)
  5481.         {
  5482.             methRef = genVarargRef(fncSym, expr);
  5483.         }
  5484.         else
  5485.         {
  5486.             methRef = genMethodRef(fncSym, isVirt);
  5487.         }
  5488.  
  5489.         if (isNew)
  5490.         {
  5491.             /* This is a call to new and a constructor */
  5492.  
  5493.             genOpcode_tok(CTcall ? CEE_CALL : CEE_NEWOBJ, methRef);
  5494.  
  5495.             if  (CTcall)
  5496.                 genCurStkLvl--;
  5497.         }
  5498.         else
  5499.         {
  5500.             /* Now issue the call instruction */
  5501.  
  5502.             genOpcode_tok(isVirt ? CEE_CALLVIRT : CEE_CALL, methRef);
  5503.  
  5504.             if  (adrDst)
  5505.             {
  5506.                 /* This is a string concatenation assignment operator */
  5507.  
  5508.                 if  (valUsed)
  5509.                 {
  5510.                     UNIMPL(!"dup result of concat into a temp");
  5511.                 }
  5512.  
  5513.                 genRef(adrDst, true);
  5514.  
  5515.                 assert(argCnt);
  5516.  
  5517.                 if  (strArr)
  5518.                     argCnt -= adrCnt;
  5519.  
  5520. //              printf("[%d] Stk lvl = %d, argCnt = %d, adrCnt = %d\n", strArr, genCurStkLvl, argCnt, adrCnt);
  5521.  
  5522.                 genCurStkLvl -= (argCnt - 1);
  5523.                 return;
  5524.             }
  5525.         }
  5526.     }
  5527.  
  5528.     /* Adjust stack level: the callee will pop its arguments */
  5529.  
  5530.     genCurStkLvl -= argCnt;
  5531.  
  5532.     /* If we've used a temp, free it up now */
  5533.  
  5534.     if  (tempUsed)
  5535.         genTempVarRls(tempType, tempNum);
  5536.  
  5537.     /* Does the function have a non-void return type? */
  5538.  
  5539.     if  (retType->tdTypeKind != TYP_VOID && !isNew)
  5540.     {
  5541.         if  (asgType)
  5542.         {
  5543.             genOpcode_tok(CEE_STOBJ, genValTypeRef(asgType));
  5544.  
  5545.             if  (valUsed && (expr->tnFlags & TNF_CALL_ASGPRE))
  5546.                 genOpcode_tok(CEE_LDOBJ, genValTypeRef(asgType));
  5547.         }
  5548.         else
  5549.         {
  5550.             genCurStkLvl++;
  5551.             genMarkStkMax();
  5552.  
  5553.             if  (!valUsed)
  5554.                 genOpcode(CEE_POP);
  5555.         }
  5556.     }
  5557. }
  5558.  
  5559. /*****************************************************************************
  5560.  *
  5561.  *  Generate a stub for a method of a generic type instance. We simply push
  5562.  *  all the arguments to the method, and then call the corresponding generic
  5563.  *  method to do all of the real work.
  5564.  */
  5565.  
  5566. void                genIL::genInstStub()
  5567. {
  5568.     ArgDef          args;
  5569.     unsigned        argc;
  5570.  
  5571.     assert(genFncSym->sdFnc.sdfInstance);
  5572.     assert(genFncSym->sdFnc.sdfGenSym);
  5573.  
  5574.     argc = 0;
  5575.  
  5576.     if  (!genFncSym->sdIsStatic)
  5577.     {
  5578.         genArgVarRef(0, false); argc++;
  5579.     }
  5580.  
  5581.     for (args = genFncSym->sdType->tdFnc.tdfArgs.adArgs;
  5582.          args;
  5583.          args = args->adNext)
  5584.     {
  5585.         genArgVarRef(argc, false); argc++;
  5586.     }
  5587.  
  5588.     genOpcode_tok(CEE_CALL, genMethodRef(genFncSym->sdFnc.sdfGenSym, false));
  5589.     genOpcode    (CEE_RET);
  5590.  
  5591.     genCurStkLvl = 0;
  5592. }
  5593.  
  5594. #ifdef  SETS
  5595.  
  5596. void                genIL::genConnect(Tree op1, Tree expr1, SymDef addf1,
  5597.                                       Tree op2, Tree expr2, SymDef addf2)
  5598. {
  5599.     /*
  5600.         We simply generate the following code:
  5601.  
  5602.           op1 += expr2;
  5603.           op2 += expr1;
  5604.  
  5605.         The caller supplies the expressions and the += operator symbols.
  5606.      */
  5607.  
  5608.     genExpr(  op1, true);
  5609.     genExpr(expr2, true);
  5610.     genOpcode_tok(CEE_CALL, genMethodRef(addf1, false));
  5611.     genCurStkLvl -= 2;
  5612.  
  5613.     genExpr(  op2, true);
  5614.     genExpr(expr1, true);
  5615.     genOpcode_tok(CEE_CALL, genMethodRef(addf2, false));
  5616.     genCurStkLvl -= 2;
  5617. }
  5618.  
  5619. void                genIL::genSortCmp(Tree val1, Tree val2, bool last)
  5620. {
  5621.     ILblock         labTmp;
  5622.  
  5623.     /* Subtract the two values (unless there is only one) */
  5624.  
  5625.     genExpr(val1, true);
  5626.  
  5627.     if  (val2)
  5628.     {
  5629.         genExpr(val2, true);
  5630.         genOpcode(CEE_SUB);
  5631.     }
  5632.  
  5633.     /* See if the difference in values is positive */
  5634.  
  5635.     genOpcode(CEE_DUP);
  5636.     labTmp = genFwdLabGet();
  5637. assert(val1->tnVtyp == TYP_INT || val1->tnVtyp == TYP_UINT); genIntConst(0);    //  we need to use a 0 with the proper type!!!!!!
  5638.     genOpcode_lab(CEE_BLE, labTmp);
  5639.     genOpcode(CEE_POP);
  5640.     genIntConst(+1);
  5641.     genOpcode(CEE_RET);
  5642.     genFwdLabDef(labTmp);
  5643.  
  5644.     /* See if the difference in values is negative */
  5645.  
  5646.     labTmp = genFwdLabGet();
  5647. assert(val1->tnVtyp == TYP_INT || val1->tnVtyp == TYP_UINT); genIntConst(0);    //  we need to use a 0 with the proper type!!!!!!
  5648.     genOpcode_lab(CEE_BGE, labTmp);
  5649.     genIntConst(-1);
  5650.     genOpcode(CEE_RET);
  5651.     genFwdLabDef(labTmp);
  5652.  
  5653.     /* Values are equal, return 0 if this was the last term */
  5654.  
  5655.     if  (last)
  5656.     {
  5657.         genIntConst(0);
  5658.         genOpcode(CEE_RET);
  5659.     }
  5660. }
  5661.  
  5662. #endif
  5663.  
  5664. /*****************************************************************************
  5665.  *
  5666.  *  Generate MSIL for the given expression.
  5667.  */
  5668.  
  5669. void                genIL::genExpr(Tree expr, bool valUsed)
  5670. {
  5671.     treeOps         oper;
  5672.     unsigned        kind;
  5673.  
  5674. AGAIN:
  5675.  
  5676.     assert(expr);
  5677. #if!MGDDATA
  5678.     assert((int)expr != 0xCCCCCCCC && (int)expr != 0xDDDDDDDD);
  5679. #endif
  5680.     assert(expr->tnOper == TN_ERROR || expr->tnType && expr->tnType->tdTypeKind == expr->tnVtyp || genComp->cmpErrorCount);
  5681.  
  5682.     /* Classify the root node */
  5683.  
  5684.     oper = expr->tnOperGet ();
  5685.     kind = expr->tnOperKind();
  5686.  
  5687.     /* Is this a constant node? */
  5688.  
  5689.     if  (kind & TNK_CONST)
  5690.     {
  5691.         switch (oper)
  5692.         {
  5693.         case TN_CNS_INT:
  5694.             genIntConst((__int32)expr->tnIntCon.tnIconVal);
  5695.             break;
  5696.  
  5697.         case TN_CNS_LNG:
  5698.  
  5699.             genOpcode_I8(CEE_LDC_I8, expr->tnLngCon.tnLconVal);
  5700.             break;
  5701.  
  5702.         case TN_CNS_FLT:
  5703.  
  5704.             genOpcode_R4(CEE_LDC_R4, expr->tnFltCon.tnFconVal);
  5705.             break;
  5706.  
  5707.         case TN_CNS_DBL:
  5708.             genOpcode_R8(CEE_LDC_R8, expr->tnDblCon.tnDconVal);
  5709.             break;
  5710.  
  5711.         case TN_CNS_STR:
  5712.             genStringLit(expr->tnType, expr->tnStrCon.tnSconVal,
  5713.                                        expr->tnStrCon.tnSconLen,
  5714.                                        expr->tnStrCon.tnSconLCH);
  5715.             break;
  5716.  
  5717.         case TN_NULL:
  5718.             if  (expr->tnVtyp == TYP_REF || expr->tnVtyp == TYP_ARRAY)
  5719.                 genOpcode(CEE_LDNULL);
  5720.             else
  5721.                 genIntConst(0);
  5722.             break;
  5723.  
  5724.         default:
  5725. #ifdef DEBUG
  5726.             genComp->cmpParser->parseDispTree(expr);
  5727. #endif
  5728.             assert(!"unexpected const node in genExpr()");
  5729.         }
  5730.  
  5731.         goto DONE;
  5732.     }
  5733.  
  5734.     /* Is this a leaf node? */
  5735.  
  5736.     if  (kind & TNK_LEAF)
  5737.     {
  5738.         switch (oper)
  5739.         {
  5740.         case TN_DBGBRK:
  5741.             assert(valUsed == false);
  5742.             genOpcode(CEE_BREAK);
  5743.             return;
  5744.  
  5745.         default:
  5746. #ifdef DEBUG
  5747.             genComp->cmpParser->parseDispTree(expr);
  5748. #endif
  5749.             assert(!"unexpected leaf node in genExpr()");
  5750.         }
  5751.  
  5752.         goto DONE;
  5753.     }
  5754.  
  5755.     /* Is it a 'simple' unary/binary operator? */
  5756.  
  5757.     if  (kind & TNK_SMPOP)
  5758.     {
  5759.         Tree            op1 = expr->tnOp.tnOp1;
  5760.         Tree            op2 = expr->tnOp.tnOp2;
  5761.  
  5762.         /* Some operators need special operand handling */
  5763.  
  5764.         switch (oper)
  5765.         {
  5766.             unsigned        cnt;
  5767.             unsigned        chk;
  5768.  
  5769.             TypDef          type;
  5770.  
  5771.             var_types       srcType;
  5772.             var_types       dstType;
  5773.  
  5774.         case TN_ASG:
  5775.  
  5776.             /* Special case: struct copy */
  5777.  
  5778.             if  (expr->tnVtyp == TYP_CLASS && !expr->tnType->tdIsIntrinsic)
  5779.             {
  5780.                 /* Are we assigning the result of a 'new' operator? */
  5781.  
  5782.                 if  (op2->tnOper == TN_NEW)
  5783.                 {
  5784.                     genNewExpr(op2, valUsed, op1);
  5785.                     return;
  5786.                 }
  5787.  
  5788.                 /* Special case: function results (including "new") can't be copied */
  5789.  
  5790.                 switch (op2->tnOper)
  5791.                 {
  5792.                 case TN_NEW:
  5793.                     assert(valUsed == false);
  5794.                     cnt = genAdr(op1, true); assert(cnt == 1);
  5795.                     genExpr(op2, true);
  5796.                     genCurStkLvl--;
  5797.                     return;
  5798.  
  5799.                 case TN_UNBOX:
  5800. //              case TN_QMARK:
  5801. //              case TN_FNC_SYM:
  5802.                     assert(valUsed == false);
  5803.                     cnt = genAdr(op1, true); assert(cnt == 1);
  5804.                     genExpr(op2, true);
  5805.                     genOpcode_tok(CEE_STOBJ, genValTypeRef(op1->tnType));
  5806.                     return;
  5807.                 }
  5808.  
  5809.                 /* Is the target an indirection ? */
  5810.  
  5811.                 if  (op1->tnOper == TN_IND ||
  5812.                      op1->tnOper == TN_VAR_SYM && !op1->tnVarSym.tnVarSym->sdIsManaged)
  5813.                 {
  5814.                     cnt = genAdr(op1, true); assert(cnt == 1);
  5815.                     cnt = genAdr(op2, true); assert(cnt == 1);
  5816.                     genOpcode_tok(CEE_CPOBJ, genValTypeRef(op1->tnType));
  5817.                     return;
  5818.                 }
  5819.             }
  5820.             else if (op1->tnOper == TN_BFM_SYM)
  5821.             {
  5822.                 /* Assignment to a bitfield */
  5823.  
  5824.                 genBitFieldSt(op1, op2, NULL, 0, false, valUsed);
  5825.                 return;
  5826.             }
  5827.  
  5828.             /* We have a "simple" assignment */
  5829.  
  5830.             cnt = genAdr(op1);
  5831.  
  5832.             // CONSIDER: see if op2 is of the form "xxx = icon;" and optimize
  5833.  
  5834.             genExpr(op2, true);
  5835.  
  5836.             /* Is the result of assignment used? */
  5837.  
  5838.             if  (valUsed)
  5839.             {
  5840.                 unsigned        tempNum;
  5841.  
  5842.                 //  Only do this if const fits in target!
  5843.  
  5844.                 if  (op2->tnOper == TN_CNS_INT ||
  5845.                      op2->tnOper == TN_CNS_LNG)
  5846.                 {
  5847.                     /* Store the constant in the target */
  5848.  
  5849.                     genRef (op1, true);
  5850.  
  5851.                     /* Load another copy of the constant */
  5852.  
  5853.                     genExpr(op2, true);
  5854.                 }
  5855.                 else if (cnt == 0)
  5856.                 {
  5857.                     genOpcode(CEE_DUP);
  5858.                     genRef(op1, true);
  5859.                 }
  5860.                 else
  5861.                 {
  5862.                     /* Need to duplicate the new value */
  5863.  
  5864.                     tempNum = genTempVarGet(expr->tnType);
  5865.  
  5866.                     /* Copy a value to a temp */
  5867.  
  5868.                     genOpcode(CEE_DUP);
  5869.                     genLclVarRef(tempNum,  true);
  5870.  
  5871.                     /* Store the new value in the destination */
  5872.  
  5873.                     genRef(op1, true);
  5874.  
  5875.                     /* Reload the temp */
  5876.  
  5877.                     genLclVarRef(tempNum, false);
  5878.  
  5879.                     //  target may have smaller size, result must match!!!!
  5880.  
  5881.                     genTempVarRls(expr->tnType, tempNum);
  5882.                 }
  5883.             }
  5884.             else
  5885.             {
  5886.                 /* Simply store the new value */
  5887.  
  5888.                 genRef(op1, true);
  5889.             }
  5890.             return;
  5891.  
  5892.         case TN_IND:
  5893.         case TN_INDEX:
  5894.             genAdr(expr);
  5895.             genRef(expr, false);
  5896.             goto DONE;
  5897.  
  5898.         case TN_NEW:
  5899.             genNewExpr(expr, valUsed);
  5900.             return;
  5901.  
  5902.         case TN_ADDROF:
  5903.  
  5904.             if  (!valUsed)
  5905.             {
  5906.                 genSideEff(op1);
  5907.                 return;
  5908.             }
  5909.  
  5910.             if  (op1->tnOper == TN_FNC_SYM || op1->tnOper == TN_FNC_PTR)
  5911.             {
  5912.                 genFncAddr(op1);
  5913.             }
  5914.             else
  5915.             {
  5916.                 chk = genAdr(op1, true); assert(chk == 1);
  5917.             }
  5918.             return;
  5919.  
  5920.         case TN_CAST:
  5921.  
  5922. #ifndef NDEBUG
  5923.  
  5924.             if  (op1->tnOperIsConst() && op1->tnOper != TN_CNS_STR)
  5925.             {
  5926.                 if  (op1->tnOper == TN_CNS_FLT && _isnan(op1->tnFltCon.tnFconVal) ||
  5927.                      op1->tnOper == TN_CNS_DBL && _isnan(op1->tnDblCon.tnDconVal))
  5928.                 {
  5929.                     /* Constant casts of NaN's don't get folded on purpose */
  5930.                 }
  5931.                 else
  5932.                 {
  5933.                     genComp->cmpParser->parseDispTree(expr);
  5934.                     printf("WARNING: The constant cast shown above hasn't been folded.\n");
  5935.                 }
  5936.             }
  5937.  
  5938. #endif
  5939.  
  5940.             srcType = genComp->cmpActualVtyp( op1->tnType);
  5941.             dstType = genComp->cmpActualVtyp(expr->tnType);
  5942.  
  5943.         CHK_CAST:
  5944.  
  5945.             /* Check for a worthless cast */
  5946.  
  5947.             if  (varTypeIsIntegral(dstType) &&
  5948.                  varTypeIsIntegral(srcType))
  5949.             {
  5950.                 size_t          srcSize = symTab::stIntrTypeSize(srcType);
  5951.                 size_t          dstSize = symTab::stIntrTypeSize(dstType);
  5952.  
  5953.                 /*  cover more cases of worthless casts */
  5954.  
  5955.                 if  (srcSize == dstSize && srcSize >= sizeof(int))
  5956.                 {
  5957.                     if  (srcSize >= sizeof(__int64) || op1->tnOper == TN_CAST)
  5958.                     {
  5959.                         /* Toss the second cast and keep the inner one */
  5960.  
  5961.                         genExpr(op1, valUsed);
  5962.                         return;
  5963.                     }
  5964.                 }
  5965.             }
  5966.  
  5967.             if  (srcType == TYP_CLASS)
  5968.             {
  5969.                 srcType = (var_types)op1 ->tnType->tdClass.tdcIntrType; assert(srcType != TYP_UNDEF);
  5970.                 if  (srcType == dstType)
  5971.                     goto DONE;
  5972.  
  5973.                 op1 ->tnType = genStab->stIntrinsicType(srcType);
  5974.                 op1 ->tnVtyp = srcType;
  5975.                 goto CHK_CAST;
  5976.             }
  5977.  
  5978.             if  (dstType == TYP_CLASS)
  5979.             {
  5980.                 dstType = (var_types)expr->tnType->tdClass.tdcIntrType; assert(dstType != TYP_UNDEF);
  5981.                 if  (srcType == dstType)
  5982.                     goto DONE;
  5983.  
  5984.                 expr->tnType = genStab->stIntrinsicType(dstType);
  5985.                 expr->tnVtyp = dstType;
  5986.                 goto CHK_CAST;
  5987.             }
  5988.  
  5989.             genCast(op1, expr->tnType, expr->tnFlags);
  5990.             goto DONE;
  5991.  
  5992.         case TN_INC_POST: genIncDec(op1, +1,  true, valUsed); return;
  5993.         case TN_DEC_POST: genIncDec(op1, -1,  true, valUsed); return;
  5994.         case TN_INC_PRE : genIncDec(op1, +1, false, valUsed); return;
  5995.         case TN_DEC_PRE : genIncDec(op1, -1, false, valUsed); return;
  5996.  
  5997.         case TN_ASG_ADD:
  5998.         case TN_ASG_SUB:
  5999.         case TN_ASG_MUL:
  6000.         case TN_ASG_DIV:
  6001.         case TN_ASG_MOD:
  6002.         case TN_ASG_AND:
  6003.         case TN_ASG_XOR:
  6004.         case TN_ASG_OR :
  6005.         case TN_ASG_LSH:
  6006.         case TN_ASG_RSH:
  6007.         case TN_ASG_RSZ:
  6008.  
  6009.         case TN_CONCAT_ASG:
  6010.             genAsgOper(expr, valUsed);
  6011.             return;
  6012.  
  6013.         case TN_EQ:
  6014.         case TN_NE:
  6015.         case TN_LT:
  6016.         case TN_LE:
  6017.         case TN_GE:
  6018.         case TN_GT:
  6019.  
  6020. if  (genComp->cmpConfig.ccTgt64bit)
  6021. {
  6022.     static bool b;
  6023.     if  (!b)
  6024.     {
  6025.         printf("WARNING: suppressing CEQ/CLT/etc for 64-bit target\n");
  6026.         b = true;
  6027.     }
  6028.     goto HACK_64;
  6029. }
  6030.  
  6031.             genExpr(op1, true);
  6032.             genExpr(op2, true);
  6033.  
  6034.             if  (valUsed)
  6035.             {
  6036.                 cmpRelDsc *     desc;
  6037.  
  6038.                 desc = varTypeIsUnsigned(genExprVtyp(op1)) ? relToMopUns
  6039.                                                            : relToMopSgn;
  6040.  
  6041.                 desc = desc + (oper - TN_EQ);
  6042.  
  6043.                 genOpcode(desc->crdOpcode);
  6044.  
  6045.                 if  (desc->crdNegate)
  6046.                 {
  6047.                     genOpcode(CEE_LDC_I4_0);
  6048.                     genOpcode(CEE_CEQ);
  6049.                 }
  6050.             }
  6051.             else
  6052.             {
  6053.                 genOpcode(CEE_POP);
  6054.                 genOpcode(CEE_POP);
  6055.             }
  6056.             return;
  6057.  
  6058. HACK_64:
  6059.  
  6060.         case TN_LOG_OR:
  6061.         case TN_LOG_AND:
  6062.  
  6063.         case TN_LOG_NOT:
  6064.             {
  6065.                 ILblock         labTmp;
  6066.                 ILblock         labYes;
  6067.  
  6068.                 genStkMarkTP     stkMark;
  6069.  
  6070.                 labTmp = genFwdLabGet();
  6071.                 labYes = genTestCond(expr, true);
  6072.                 markStkLvl(stkMark);
  6073.  
  6074.                 genIntConst(0);
  6075.                 genOpcode_lab(CEE_BR , labTmp);
  6076.                 genFwdLabDef(labYes);
  6077.                 restStkLvl(stkMark);
  6078.                 genIntConst(1);
  6079.                 genFwdLabDef(labTmp);
  6080.             }
  6081.             goto DONE;
  6082.  
  6083.         case TN_QMARK:
  6084.             {
  6085.                 ILblock         labOp2;
  6086.                 ILblock         labRes;
  6087.  
  6088.                 genStkMarkTP     stkMark;
  6089.  
  6090.                 assert(op2->tnOper == TN_COLON);
  6091.  
  6092.                 labRes = genFwdLabGet();
  6093.                 labOp2 = genTestCond(op1, false);
  6094.                 markStkLvl(stkMark);
  6095.  
  6096.                 genExpr(op2->tnOp.tnOp1, true);
  6097.                 genOpcode_lab(CEE_BR , labRes);
  6098.                 genFwdLabDef(labOp2);
  6099.                 restStkLvl(stkMark);
  6100.                 genExpr(op2->tnOp.tnOp2, true);
  6101.                 genFwdLabDef(labRes);
  6102.             }
  6103.             goto DONE;
  6104.  
  6105.         case TN_COMMA:
  6106.             genExpr(op1, false);
  6107.             expr = op2;
  6108.             goto AGAIN;
  6109.  
  6110.         case TN_ARR_INIT:
  6111.             genArrayInit(expr);
  6112.             goto DONE;
  6113.  
  6114.         case TN_CALL:
  6115.             genCall(expr, valUsed);
  6116.             return;
  6117.  
  6118.         case TN_ISTYPE:
  6119.             assert(op2->tnOper == TN_NONE);
  6120.             genExpr(op1, true);
  6121.             genOpcode_tok(CEE_ISINST, genTypeRef(op2->tnType));
  6122.             genOpcode    (CEE_LDC_I4_0);
  6123.             genOpcode    (CEE_CGT_UN);
  6124.             goto DONE;
  6125.  
  6126.         case TN_BOX:
  6127.  
  6128.             /* Get hold of the operand type and make sure we have a value class */
  6129.  
  6130.             type = op1->tnType;
  6131.             if  (type->tdTypeKind != TYP_CLASS && type->tdTypeKind != TYP_ENUM)
  6132.             {
  6133.                 assert(type->tdTypeKind != TYP_REF);
  6134.  
  6135.                 type = genComp->cmpFindStdValType(genComp->cmpActualVtyp(op1->tnType));
  6136.             }
  6137.  
  6138.             assert(type && (type->tdTypeKind == TYP_CLASS && type->tdClass.tdcValueType ||
  6139.                             type->tdTypeKind == TYP_ENUM));
  6140.  
  6141.             genExpr(op1, true);
  6142.             genOpcode_tok(CEE_BOX, genTypeRef(type));
  6143.  
  6144.             goto DONE;
  6145.  
  6146.         case TN_VARARG_BEG:
  6147.         case TN_VARARG_GET:
  6148.  
  6149.             /*
  6150.                 To get a vararg iterator started, we generate the following
  6151.                 code:
  6152.  
  6153.                     ldloca          <arg_iter_var>
  6154.                     arglist
  6155.                     ldarga          <last_fixed_arg>
  6156.                     call            void System.ArgIterator::<init>(int32,int32)
  6157.  
  6158.                 To fetch the next vararg value, we generate the following
  6159.                 code:
  6160.  
  6161.                     ldloca          <arg_iter_var>
  6162.                     ldtoken         <type>
  6163.                     call            int32 System.ArgIterator::GetNextArg(int32)
  6164.                     ldind.<type>
  6165.  
  6166.                 Actually, not any more - now we generate the following:
  6167.  
  6168.                     ldloca          <arg_iter_var>
  6169.                     call            refany System.ArgIterator::GetNextArg(int32)
  6170.                     refanyval       <type>
  6171.                     ldind.<type>
  6172.              */
  6173.  
  6174.             assert(op1 && op1->tnOper == TN_LIST);
  6175.  
  6176.             assert(op1->tnOp.tnOp1 && op1->tnOp.tnOp1->tnOper == TN_LCL_SYM);
  6177.             genLclVarAdr(op1->tnOp.tnOp1->tnLclSym.tnLclSym);
  6178.  
  6179.             if  (oper == TN_VARARG_BEG)
  6180.             {
  6181.                 genOpcode(CEE_ARGLIST);
  6182.  
  6183.                 assert(op1->tnOp.tnOp2 && op1->tnOp.tnOp2->tnOper == TN_LCL_SYM);
  6184.                 genLclVarAdr(op1->tnOp.tnOp2->tnLclSym.tnLclSym);
  6185.  
  6186.                 genCall(op2, false);
  6187.                 genCurStkLvl -= 3;
  6188.  
  6189.                 assert(valUsed == false);
  6190.                 return;
  6191.             }
  6192.             else
  6193.             {
  6194.                 TypDef          type;
  6195.                 var_types       vtyp;
  6196.  
  6197.                 /* Get hold of the type operand */
  6198.  
  6199.                 assert(op1->tnOp.tnOp2 && op1->tnOp.tnOp2->tnOper == TN_TYPE);
  6200.                 type = op1->tnOp.tnOp2->tnType;
  6201.                 vtyp = type->tdTypeKindGet();
  6202.  
  6203.                 /* Call ArgIterator::GetNextArg */
  6204.  
  6205.                 genCall(op2, true);
  6206.                 genCurStkLvl -= 1;
  6207.  
  6208.                 genOpcode_tok(CEE_REFANYVAL, genTypeRef(type));
  6209.  
  6210.                 /* Load the value of the argument */
  6211.  
  6212.                 assert(vtyp < arraylen(opcodesIndLoad));
  6213.  
  6214.                 genOpcode(opcodesIndLoad[vtyp]);
  6215.  
  6216.                 goto DONE;
  6217.             }
  6218.  
  6219.         case TN_TOKEN:
  6220.  
  6221.             assert(op1 && op1->tnOper == TN_NOP);
  6222.             assert(op2 == NULL);
  6223.  
  6224.             assert(valUsed);
  6225.  
  6226.             genOpcode_tok(CEE_LDTOKEN, genTypeRef(op1->tnType));
  6227.             return;
  6228.  
  6229. #ifdef  SETS
  6230.  
  6231.         case TN_ALL:
  6232.         case TN_EXISTS:
  6233.         case TN_SORT:
  6234.         case TN_FILTER:
  6235.         case TN_GROUPBY:
  6236.         case TN_UNIQUE:
  6237.         case TN_INDEX2:
  6238.         case TN_PROJECT:
  6239.             genComp->cmpGenCollExpr(expr);
  6240.             goto DONE;
  6241.  
  6242. #endif
  6243.  
  6244.         case TN_REFADDR:
  6245.  
  6246.             assert(op1->tnVtyp == TYP_REFANY);
  6247.             genExpr(op1, true);
  6248.  
  6249.             genOpcode_tok(CEE_REFANYVAL, genTypeRef(op2->tnType));
  6250.  
  6251.             goto DONE;
  6252.         }
  6253.  
  6254.         /* Generate one or two operands */
  6255.  
  6256.         if  (op1) genExpr(op1, true);
  6257.         if  (op2) genExpr(op2, true);
  6258.  
  6259.         ILopcodes       op;
  6260.  
  6261.         /* Is this an 'easy' operator? */
  6262.  
  6263.         op = genBinopOpcode(oper, genExprVtyp(expr));
  6264.  
  6265.         if  (op != CEE_NOP)
  6266.         {
  6267. #ifndef NDEBUG
  6268.  
  6269.             /* The type of the operands should agree (more or less) */
  6270.  
  6271.             switch (oper)
  6272.             {
  6273.             case TN_LSH:
  6274.             case TN_RSH:
  6275.             case TN_RSZ:
  6276.  
  6277.                 /* Special case: 'long' shifts have 'int' right operands */
  6278.  
  6279.                 if  (op1->tnVtyp == TYP_LONG)
  6280.                 {
  6281.                     assert(op2 ->tnVtyp <= TYP_UINT);
  6282.                     assert(expr->tnVtyp == TYP_LONG);
  6283.                     break;
  6284.                 }
  6285.  
  6286. //          default:
  6287. //
  6288. //              if  (op1 && op1->tnVtyp != expr->tnVtyp) assert(op1->tnVtyp <= TYP_INT && expr->tnVtyp <= TYP_INT);
  6289. //              if  (op2 && op2->tnVtyp != expr->tnVtyp) assert(op2->tnVtyp <= TYP_INT && expr->tnVtyp <= TYP_INT);
  6290.             }
  6291. #endif
  6292.  
  6293.             genOpcode(op);
  6294.             goto DONE;
  6295.         }
  6296.  
  6297.         /* Generate the appropriate operator MSIL */
  6298.  
  6299.         switch (oper)
  6300.         {
  6301.         case TN_ARR_LEN:
  6302.             genOpcode(CEE_LDLEN);
  6303.             break;
  6304.  
  6305.         case TN_NOT:
  6306.             genOpcode(CEE_NOT);
  6307.             break;
  6308.  
  6309.         case TN_NEG:
  6310.             genOpcode(CEE_NEG);
  6311.             break;
  6312.  
  6313.         case TN_NOP:
  6314.             break;
  6315.  
  6316.         case TN_THROW:
  6317.             genOpcode(op1 ? CEE_THROW : CEE_RETHROW);
  6318.             return;
  6319.  
  6320.         case TN_UNBOX:
  6321.             assert(expr->tnVtyp == TYP_REF || expr->tnVtyp == TYP_PTR);
  6322.             genOpcode_tok(CEE_UNBOX, genTypeRef(expr->tnType->tdRef.tdrBase));
  6323.             goto DONE;
  6324.  
  6325.         case TN_TYPE:
  6326.  
  6327.             /* Assume we must have had errors for this to appear here */
  6328.  
  6329.             assert(genComp->cmpErrorCount);
  6330.             return;
  6331.  
  6332.         case TN_DELETE:
  6333.             genOpcode_tok(CEE_CALL, genMethodRef(genComp->cmpFNumgOperDelGet(), false));
  6334.             genCurStkLvl--;
  6335.             return;
  6336.  
  6337.         case TN_TYPEOF:
  6338.             assert(op1->tnVtyp == TYP_REFANY);
  6339.  
  6340.             genOpcode    (CEE_REFANYTYPE);
  6341.             genOpcode_tok(CEE_CALL, genMethodRef(genComp->cmpFNsymGetTPHget(), false));
  6342.             break;
  6343.  
  6344.         default:
  6345. #ifdef DEBUG
  6346.             genComp->cmpParser->parseDispTree(expr);
  6347. #endif
  6348.             NO_WAY(!"unsupported unary/binary operator in genExpr()");
  6349.             break;
  6350.         }
  6351.  
  6352.         goto DONE;
  6353.     }
  6354.  
  6355.     /* See what kind of a special operator we have here */
  6356.  
  6357.     switch  (oper)
  6358.     {
  6359.         SymDef          sym;
  6360.  
  6361.     case TN_VAR_SYM:
  6362.  
  6363.         /* Is this an instance member of a managed class? */
  6364.  
  6365.         sym = expr->tnVarSym.tnVarSym;
  6366.  
  6367.         if  (sym->sdIsMember && sym->sdIsManaged && !sym->sdIsStatic)
  6368.         {
  6369.             Tree            addr;
  6370.  
  6371.             assert(sym->sdSymKind      == SYM_VAR);
  6372.             assert(sym->sdVar.sdvLocal == false);
  6373.             assert(sym->sdVar.sdvConst == false);
  6374.  
  6375.             /* Get hold of the instance address value */
  6376.  
  6377.             addr = expr->tnVarSym.tnVarObj; assert(addr);
  6378.  
  6379.             if  (addr->tnOper == TN_ADDROF)
  6380.             {
  6381.                 Tree            oper = addr->tnOp.tnOp1;
  6382.  
  6383.                 if  (oper->tnOper == TN_FNC_SYM ||
  6384.                      oper->tnOper == TN_FNC_PTR)
  6385.                 {
  6386.                     unsigned        tempNum;
  6387.  
  6388.                     /* Generate the call and store its result in a temp */
  6389.  
  6390.                     tempNum = genTempVarGet(oper->tnType);
  6391.                     genExpr(oper, true);
  6392.                     genLclVarRef(tempNum, true);
  6393.  
  6394.                     /* Now load the field from the temp */
  6395.  
  6396.                     genLclVarAdr(tempNum);
  6397.                     genOpcode_tok(CEE_LDFLD, genMemberRef(sym));
  6398.  
  6399.                     /* We can free up the temp now */
  6400.  
  6401.                     genTempVarRls(oper->tnType, tempNum);
  6402.                     break;
  6403.                 }
  6404.             }
  6405.         }
  6406.  
  6407.         // Fall through ...
  6408.  
  6409.     case TN_LCL_SYM:
  6410.         genAdr(expr);
  6411.         genRef(expr, false);
  6412.         break;
  6413.  
  6414.     case TN_BFM_SYM:
  6415.         genBitFieldLd(expr, false, valUsed);
  6416.         return;
  6417.  
  6418.     case TN_FNC_SYM:
  6419.         if  (expr->tnFncSym.tnFncSym->sdFnc.sdfDisabled)
  6420.         {
  6421.             assert(valUsed == false);
  6422.         }
  6423.         else
  6424.         {
  6425.             genCall(expr, valUsed);
  6426.         }
  6427.         return;
  6428.  
  6429.     case TN_FNC_PTR:
  6430.         if  (valUsed)
  6431.             genFncAddr(expr);
  6432.         return;
  6433.  
  6434.     case TN_ERROR:
  6435.         return;
  6436.  
  6437.     default:
  6438. #ifdef DEBUG
  6439.         genComp->cmpParser->parseDispTree(expr);
  6440. #endif
  6441.         assert(!"unsupported node in genExpr()");
  6442.         return;
  6443.     }
  6444.  
  6445. DONE:
  6446.  
  6447.     /* If the value isn't used, pop it */
  6448.  
  6449.     if  (!valUsed)
  6450.         genOpcode(CEE_POP);
  6451. }
  6452.  
  6453. /*****************************************************************************
  6454.  *
  6455.  *  Generate code for a 'return' statement.
  6456.  */
  6457.  
  6458. void                genIL::genStmtRet(Tree retv)
  6459. {
  6460.     assert(genCurStkLvl == 0 || genComp->cmpErrorCount != 0);
  6461.  
  6462.     if  (retv)
  6463.         genExpr(retv, true);
  6464.  
  6465.     genOpcode(CEE_RET);
  6466.  
  6467.     genCurStkLvl = 0;
  6468. }
  6469.  
  6470. /*****************************************************************************
  6471.  *
  6472.  *  Generate a string literal value.
  6473.  */
  6474.  
  6475. void                genIL::genStringLit(TypDef type, const char *str,
  6476.                                                      size_t      len, int wide)
  6477. {
  6478.     const   void  * addr;
  6479.     size_t          size;
  6480.  
  6481.     unsigned        offs;
  6482.  
  6483.     var_types       vtyp = type->tdTypeKindGet();
  6484.  
  6485.     assert(vtyp == TYP_REF || vtyp == TYP_PTR);
  6486.  
  6487.     /* Include the terminating null character in the length */
  6488.  
  6489.     len++;
  6490.  
  6491.     /* First figure out whether we need an ANSII or Unicode string */
  6492.  
  6493.     if  (vtyp == TYP_REF || genComp->cmpGetRefBase(type)->tdTypeKind == TYP_WCHAR)
  6494.     {
  6495.         addr = wide ? genComp->cmpUniCnvW(str, &len)
  6496.                     : genComp->cmpUniConv(str,  len);
  6497.  
  6498.         /* Are we generating a Common Type System-style string reference? */
  6499.  
  6500.         if  (vtyp == TYP_REF)
  6501.         {
  6502. //          printf("String = '%ls', len = %u\n", addr, len-1);
  6503.  
  6504.             genOpcode_tok(CEE_LDSTR, genComp->cmpMDstringLit((wchar*)addr, len - 1));
  6505.             return;
  6506.         }
  6507.  
  6508.         size = 2*len;
  6509.     }
  6510.     else
  6511.     {
  6512.         /* There better not be any large characters in this string */
  6513.  
  6514.         assert(wide == false);
  6515.  
  6516.         addr = str;
  6517.         size = len;
  6518.     }
  6519.  
  6520.     /* Add the string to the pool and get its RVA */
  6521.  
  6522.     offs = genStrPoolAdd(addr, size);
  6523.  
  6524.     /*
  6525.        Create a static data member to represent the string literal and
  6526.        push its address.
  6527.      */
  6528.  
  6529.     genOpcode_tok(CEE_LDSFLDA, genComp->cmpStringConstTok(offs, size));
  6530. }
  6531.  
  6532. /*****************************************************************************
  6533.  *
  6534.  *  Initialize the string pool logic.
  6535.  */
  6536.  
  6537. void                genIL::genStrPoolInit()
  6538. {
  6539.     genStrPoolOffs = 0;
  6540.  
  6541.     genStrPoolList =
  6542.     genStrPoolLast = NULL;
  6543. }
  6544.  
  6545. /*****************************************************************************
  6546.  *
  6547.  *  Add the given blob of bits to the string pool and return the blob's
  6548.  *  relative offset.
  6549.  */
  6550.  
  6551. unsigned            genIL::genStrPoolAdd(const void *str, size_t len, int wide)
  6552. {
  6553.     unsigned        offs;
  6554.     unsigned        base;
  6555.  
  6556.     /* Compute the "true" string length (taking large chars into account) */
  6557.  
  6558.     if  (wide)
  6559.     {
  6560.         UNIMPL(!"");
  6561.     }
  6562.  
  6563.     /* Is there enough room for the string in the current blob? */
  6564.  
  6565.     if  (genStrPoolLast == NULL || genStrPoolLast->seFree < len)
  6566.     {
  6567.         StrEntry        entry;
  6568.         genericBuff     block;
  6569.         size_t          bsize;
  6570.  
  6571.         /* Not enough room, need to grab a new blob */
  6572.  
  6573.         bsize = STR_POOL_BLOB_SIZE;
  6574.         if  (bsize < len)
  6575.             bsize = roundUp(len, OS_page_size);
  6576.  
  6577.         /* Allocate the descriptor and the data block */
  6578.  
  6579. #if MGDDATA
  6580.         entry = new StrEntry;
  6581.         block = new BYTE[bsize];
  6582. #else
  6583.         entry = (StrEntry)genComp->cmpAllocPerm.nraAlloc(sizeof(*entry));
  6584.         block = (BYTE *)VirtualAlloc(NULL, bsize, MEM_COMMIT, PAGE_READWRITE);
  6585. #endif
  6586.  
  6587.         if  (!block)
  6588.             genComp->cmpFatal(ERRnoMemory);
  6589.  
  6590.         /* Set up the info in the blob descriptor */
  6591.  
  6592.         entry->seSize =
  6593.         entry->seFree = bsize;
  6594.         entry->seOffs = genStrPoolOffs;
  6595.         entry->seData = block;
  6596.  
  6597.         /* Add the blob to the list */
  6598.  
  6599.         entry->seNext = NULL;
  6600.  
  6601.         if  (genStrPoolList)
  6602.             genStrPoolLast->seNext = entry;
  6603.         else
  6604.             genStrPoolList         = entry;
  6605.  
  6606.         genStrPoolLast = entry;
  6607.     }
  6608.  
  6609.     /* Here we better have enough room in the current blob */
  6610.  
  6611.     assert(genStrPoolLast && genStrPoolLast->seFree >= len);
  6612.  
  6613.     /* Figure out where in the block the data should go */
  6614.  
  6615.     base = genStrPoolLast->seSize - genStrPoolLast->seFree;
  6616.  
  6617.     assert(genStrPoolLast->seSize        >= base + len);
  6618.     assert(genStrPoolLast->seOffs + base == genStrPoolOffs);
  6619.  
  6620.     /* Copy the data to the right spot in the block */
  6621.  
  6622. #if MGDDATA
  6623.     UNIMPL(!"need to call arraycopy");
  6624. #else
  6625.     memcpy(genStrPoolLast->seData + base, str, len);
  6626. #endif
  6627.  
  6628.     /* Update the amount of free space available in the block */
  6629.  
  6630.     genStrPoolLast->seFree -= len;
  6631.  
  6632.     /* Grab the next offset and advance it past the new string */
  6633.  
  6634.     offs = genStrPoolOffs;
  6635.            genStrPoolOffs += len;
  6636.  
  6637.     return  offs;
  6638. }
  6639.  
  6640. /*****************************************************************************
  6641.  *
  6642.  *  Returns the size of the string pool - don't add any more data to the pool
  6643.  *  after calling this function.
  6644.  */
  6645.  
  6646. unsigned            genIL::genStrPoolSize()
  6647. {
  6648.     return  genStrPoolOffs;
  6649. }
  6650.  
  6651. /*****************************************************************************
  6652.  *
  6653.  *  Output the string pool to the specified address.
  6654.  */
  6655.  
  6656. void                genIL::genStrPoolWrt(memBuffPtr dest)
  6657. {
  6658.     StrEntry        entry;
  6659.  
  6660.     for (entry = genStrPoolList; entry; entry = entry->seNext)
  6661.     {
  6662.         unsigned        size = entry->seSize - entry->seFree;
  6663.  
  6664.         assert(size && size <= entry->seSize);
  6665.  
  6666. #if MGDDATA
  6667.         UNIMPL(!"copyarray");
  6668.         dest.buffOffs      +=       size;
  6669. #else
  6670.         memcpy(dest, entry->seData, size);
  6671.                dest        +=       size;
  6672. #endif
  6673.  
  6674.     }
  6675. }
  6676.  
  6677. /*****************************************************************************
  6678.  *
  6679.  *  Initialize the exception handler table logic.
  6680.  */
  6681.  
  6682. void                genIL::genEHtableInit()
  6683. {
  6684.     genEHlist  =
  6685.     genEHlast  = NULL;
  6686.  
  6687.     genEHcount = 0;
  6688. }
  6689.  
  6690. /*****************************************************************************
  6691.  *
  6692.  *  Add an entry to the exception handler table.
  6693.  */
  6694.  
  6695. void                genIL::genEHtableAdd(ILblock tryBegPC,
  6696.                                          ILblock tryEndPC,
  6697.                                          ILblock filterPC,
  6698.                                          ILblock hndBegPC,
  6699.                                          ILblock hndEndPC,
  6700.                                          TypDef  catchTyp, bool isFinally)
  6701. {
  6702.     Handler         newHand;
  6703.  
  6704.     assert(tryBegPC);
  6705.     assert(tryEndPC);
  6706.  
  6707.     genEHcount++;
  6708.  
  6709. #if MGDDATA
  6710.     newHand = new Handler;
  6711. #else
  6712.     newHand =    (Handler)genAlloc->nraAlloc(sizeof(*newHand));
  6713. #endif
  6714.  
  6715.     newHand->EHtryBegPC     = tryBegPC;
  6716.     newHand->EHtryEndPC     = tryEndPC;
  6717.  
  6718.     newHand->EHhndBegPC     = hndBegPC;
  6719.     newHand->EHhndEndPC     = hndEndPC;
  6720.  
  6721.     newHand->EHfilterPC     = filterPC;
  6722.     newHand->EHhndType      = catchTyp ? genTypeRef(catchTyp) : 0;
  6723.  
  6724.     newHand->EHisFinally    = isFinally;
  6725.  
  6726.     newHand->EHnext = NULL;
  6727.  
  6728.     if  (genEHlist)
  6729.         genEHlast->EHnext = newHand;
  6730.     else
  6731.         genEHlist         = newHand;
  6732.  
  6733.     genEHlast = newHand;
  6734. }
  6735.  
  6736. /*****************************************************************************
  6737.  *
  6738.  *  Output the EH table in the format needed by the COR MSIL header helpers.
  6739.  */
  6740.  
  6741. void                genIL::genEHtableWrt(EH_CLAUSE_TAB tbl)
  6742. {
  6743.     Handler         EHlist;
  6744.     unsigned        num;
  6745.  
  6746.     for (EHlist = genEHlist     , num = 0;
  6747.          EHlist;
  6748.          EHlist = EHlist->EHnext, num++)
  6749.     {
  6750.         tbl[num].Flags         = /*COR_ILEXCEPTION_CLAUSE_NONE*/
  6751.                                    COR_ILEXCEPTION_CLAUSE_OFFSETLEN;
  6752.  
  6753.         tbl[num].TryOffset     = genILblockOffsBeg(EHlist->EHtryBegPC);
  6754.         tbl[num].TryLength     = genILblockOffsBeg(EHlist->EHtryEndPC) - tbl[num].TryOffset;
  6755.  
  6756.         tbl[num].HandlerOffset = genILblockOffsBeg(EHlist->EHhndBegPC);
  6757.         tbl[num].HandlerLength = genILblockOffsBeg(EHlist->EHhndEndPC) - tbl[num].HandlerOffset;
  6758.  
  6759.         tbl[num].ClassToken    = EHlist->EHhndType;
  6760.  
  6761.         if (EHlist->EHfilterPC)
  6762.         {
  6763.             tbl[num].Flags      = (CorExceptionFlag)(tbl[num].Flags | COR_ILEXCEPTION_CLAUSE_FILTER);
  6764.             tbl[num].ClassToken = genILblockOffsBeg(EHlist->EHfilterPC);
  6765.         }
  6766.  
  6767.         if (EHlist->EHisFinally)
  6768.             tbl[num].Flags = (CorExceptionFlag)(tbl[num].Flags | COR_ILEXCEPTION_CLAUSE_FINALLY);
  6769.  
  6770. #if 0
  6771.         printf("EH[%3u]: Flags   = %04X\n", num, tbl[num].Flags);
  6772.         printf("         TryBeg  = %04X\n", tbl[num].TryOffset);
  6773.         printf("         TryLen  = %04X\n", tbl[num].TryLength);
  6774.         printf("         HndBeg  = %04X\n", tbl[num].HandlerOffset);
  6775.         printf("         HndLen  = %04X\n", tbl[num].HandlerLength);
  6776.         printf("         Typeref = %08X\n", tbl[num].ClassToken);
  6777. #endif
  6778.  
  6779.     }
  6780.  
  6781.     assert(num == genEHcount);
  6782. }
  6783.  
  6784. /*****************************************************************************
  6785.  *
  6786.  *  Start generating code for a 'catch' handler.
  6787.  */
  6788.  
  6789. void                genIL::genCatchBeg(SymDef argSym)
  6790. {
  6791.     /* The address of the thrown object is pushed on the stack */
  6792.  
  6793.     genCurStkLvl++; genMarkStkMax();
  6794.  
  6795.     /* Save the thrown object's address if it might be used */
  6796.  
  6797.     if  (argSym->sdName)    // ISSUE: should also test "is used" bit
  6798.     {
  6799.         genLclVarRef(argSym->sdVar.sdvILindex, true);
  6800.     }
  6801.     else
  6802.         genOpcode(CEE_POP);
  6803. }
  6804.  
  6805. /*****************************************************************************
  6806.  *
  6807.  *  Start generating code for an 'except' handler.
  6808.  */
  6809.  
  6810. void                genIL::genExcptBeg(SymDef tsym)
  6811. {
  6812.     /* The address of the thrown object is pushed on the stack */
  6813.  
  6814.     genCurStkLvl++; genMarkStkMax();
  6815.  
  6816.     /* Save the thrown object's address */
  6817.  
  6818.     genLclVarRef(tsym->sdVar.sdvILindex, true);
  6819. }
  6820.  
  6821. /*****************************************************************************
  6822.  *
  6823.  *  Generate code for a multi-dimensional rectangular array initializer.
  6824.  */
  6825.  
  6826. void                genIL::genMulDimArrInit(Tree        expr,
  6827.                                             TypDef      type,
  6828.                                             DimDef      dims,
  6829.                                             unsigned    temp,
  6830.                                             mulArrDsc * next,
  6831.                                             mulArrDsc * outer)
  6832. {
  6833.     Tree            list;
  6834.     Tree            cntx;
  6835.  
  6836.     mulArrDsc       desc;
  6837.     TypDef          elem = genComp->cmpDirectType(type->tdArr.tdaElem);
  6838.  
  6839.     assert(expr && expr->tnOper == TN_ARR_INIT);
  6840.  
  6841.     /* Insert this dimension into the list */
  6842.  
  6843.     desc.madOuter = NULL;
  6844.     desc.madIndex = 0;      // should be low bound which can be non-zero, right?
  6845.  
  6846.     if  (next)
  6847.     {
  6848.         assert(next->madOuter == NULL); next->madOuter = &desc;
  6849.     }
  6850.     else
  6851.     {
  6852.         assert(outer          == NULL); outer          = &desc;
  6853.     }
  6854.  
  6855.     /* Get hold of the initalizer list */
  6856.  
  6857.     list = expr->tnOp.tnOp1; assert(list && list->tnOper == TN_LIST);
  6858.     cntx = expr->tnOp.tnOp2; assert(cntx->tnOper == TN_CNS_INT);
  6859.  
  6860.     /* Assign each sub-array or element in the list */
  6861.  
  6862.     dims = dims->ddNext;
  6863.  
  6864.     while (list)
  6865.     {
  6866.         assert(list->tnOper == TN_LIST);
  6867.  
  6868.         /* Is this the innermost dimension? */
  6869.  
  6870.         if  (!dims)
  6871.         {
  6872.             mulArrDsc *     dlst;
  6873.             unsigned        dcnt;
  6874.  
  6875.             /* Load the array base and the element's indices */
  6876.  
  6877.             genLclVarRef(temp, false);
  6878.  
  6879.             for (dlst = outer          , dcnt = 0;
  6880.                  dlst;
  6881.                  dlst = dlst->madOuter, dcnt++)
  6882.             {
  6883.                 genIntConst(dlst->madIndex);
  6884.  
  6885.                 assert(dlst->madOuter || dlst == &desc);
  6886.             }
  6887.  
  6888.             genExpr(list->tnOp.tnOp1, true);
  6889.  
  6890.             genOpcode_tok(CEE_CALL, genComp->cmpArrayEAtoken(type, dcnt, true));
  6891.             genCurStkLvl -= (dcnt + 2);
  6892.         }
  6893.         else
  6894.         {
  6895.             genMulDimArrInit(list->tnOp.tnOp1, type, dims, temp, &desc, outer);
  6896.         }
  6897.  
  6898.         /* Move to the next sub-array or element, if any */
  6899.  
  6900.         desc.madIndex++;
  6901.  
  6902.         list = list->tnOp.tnOp2;
  6903.     }
  6904.  
  6905.     assert(desc.madIndex == (unsigned)cntx->tnIntCon.tnIconVal);
  6906.  
  6907.     /* Remove our entry from the list */
  6908.  
  6909.     if  (next)
  6910.     {
  6911.         assert(next->madOuter == &desc); next->madOuter = NULL;
  6912.     }
  6913. }
  6914.  
  6915. /*****************************************************************************
  6916.  *
  6917.  *  Generate code for a dynamic array initializer.
  6918.  */
  6919.  
  6920. void                genIL::genArrayInit(Tree expr)
  6921. {
  6922.     TypDef          type;
  6923.     TypDef          elem;
  6924.     var_types       evtp;
  6925.  
  6926.     Tree            list;
  6927.     Tree            cntx;
  6928.  
  6929.     bool            rect;
  6930.  
  6931.     unsigned        tnum;
  6932.     unsigned        index;
  6933.     unsigned        store;
  6934.  
  6935.     assert(expr->tnOper == TN_ARR_INIT);
  6936.  
  6937.     type = expr->tnType    ; assert(type->tdTypeKind == TYP_ARRAY);
  6938.     elem = genComp->cmpActualType(type->tdArr.tdaElem);
  6939.     evtp = elem->tdTypeKindGet();
  6940.  
  6941.     list = expr->tnOp.tnOp1; assert(list == NULL || list->tnOper == TN_LIST);
  6942.     cntx = expr->tnOp.tnOp2; assert(cntx->tnOper == TN_CNS_INT);
  6943.  
  6944.     /* Do we have a multi-dimensional rectangular array? */
  6945.  
  6946.     if  (type->tdArr.tdaDims &&
  6947.          type->tdArr.tdaDims->ddNext)
  6948.     {
  6949.         Tree            bnds;
  6950.         unsigned        dcnt;
  6951.  
  6952.         rect = true;
  6953.  
  6954.         /* Generate the dimensions and then the "new" opcode */
  6955.  
  6956.         bnds = expr; assert(bnds);
  6957.         dcnt = 0;
  6958.  
  6959.         do
  6960.         {
  6961.             assert(bnds->tnOp.tnOp2);
  6962.             assert(bnds->tnOp.tnOp2->tnOper == TN_CNS_INT);
  6963.  
  6964.             genIntConst(bnds->tnOp.tnOp2->tnIntCon.tnIconVal); dcnt++;
  6965.  
  6966.             bnds = bnds->tnOp.tnOp1; assert(bnds && bnds->tnOper == TN_LIST);
  6967.             bnds = bnds->tnOp.tnOp1; assert(bnds);
  6968.         }
  6969.         while (bnds->tnOper == TN_ARR_INIT);
  6970.  
  6971.         genOpcode_tok(CEE_NEWOBJ, genComp->cmpArrayCTtoken(type, elem, dcnt));
  6972.  
  6973.         /* The dimensions will all be popped by the 'new' opcode */
  6974.  
  6975.         genCurStkLvl -= dcnt;
  6976.     }
  6977.     else
  6978.     {
  6979.         rect = false;
  6980.  
  6981.         /* Generate the dimension and the "new" opcode */
  6982.  
  6983.         genIntConst(cntx->tnIntCon.tnIconVal);
  6984.         genOpcode_tok(CEE_NEWARR, genTypeRef(elem));
  6985.  
  6986.         if  (list == NULL)
  6987.         {
  6988.             assert(cntx->tnIntCon.tnIconVal == 0);
  6989.             return;
  6990.         }
  6991.     }
  6992.  
  6993.     /* Store the array address in a temp */
  6994.  
  6995.     tnum = genTempVarGet(type);
  6996.     genLclVarRef(tnum,  true);
  6997.  
  6998.     /* Figure out which opcode to use for storing the elements */
  6999.  
  7000.     assert(evtp < arraylen(opcodesArrStore));
  7001.     store = opcodesArrStore[evtp];
  7002.  
  7003.     /* Do we have a multi-dimensional rectangular array? */
  7004.  
  7005.     if  (type->tdArr.tdaDims &&
  7006.          type->tdArr.tdaDims->ddNext)
  7007.     {
  7008.         genMulDimArrInit(expr, type, type->tdArr.tdaDims, tnum, NULL, NULL);
  7009.         goto DONE;
  7010.     }
  7011.  
  7012.     /* Now assign each element of the array */
  7013.  
  7014.     for (index = 0; list; index++)
  7015.     {
  7016.         /* Load the array base and the element's index */
  7017.  
  7018.         genLclVarRef(tnum, false);
  7019.         genIntConst(index);
  7020.  
  7021.         /* Generate and store the element's value */
  7022.  
  7023.         assert(list->tnOper == TN_LIST);
  7024.  
  7025.         if  (evtp == TYP_CLASS)
  7026.         {
  7027.             Tree            addr;
  7028.  
  7029.             /* Push the address of the destination element */
  7030.  
  7031.             genOpcode_tok(CEE_LDELEMA, genValTypeRef(elem));
  7032.  
  7033.             /* Get hold of the initializer expression */
  7034.  
  7035.             addr = list->tnOp.tnOp1;
  7036.  
  7037.             if  (addr->tnOper == TN_NEW || addr->tnOper == TN_FNC_SYM)
  7038.             {
  7039.                 /* The call/new will construct the value into the element */
  7040.  
  7041.                 addr->tnFlags |= TNF_CALL_GOTADR;
  7042.  
  7043.                 genCall(list->tnOp.tnOp1, true);
  7044.  
  7045.                 if  (addr->tnOper == TN_FNC_SYM)
  7046.                     genOpcode_tok(CEE_STOBJ, genValTypeRef(elem));
  7047.             }
  7048.             else
  7049.             {
  7050.                 unsigned        chk;
  7051.  
  7052.                 /* Compute the address of the initializer and copy it */
  7053.  
  7054.                 chk = genAdr(addr, true); assert(chk == 1);
  7055.                 genOpcode_tok(CEE_CPOBJ, genValTypeRef(elem));
  7056.             }
  7057.         }
  7058.         else
  7059.         {
  7060.             genExpr(list->tnOp.tnOp1, true);
  7061.             genOpcode(store);
  7062.         }
  7063.  
  7064.         /* Move to the next element, if any */
  7065.  
  7066.         list = list->tnOp.tnOp2;
  7067.     }
  7068.  
  7069.     assert(index == (unsigned)cntx->tnIntCon.tnIconVal);
  7070.  
  7071. DONE:
  7072.  
  7073.     /* Finally, load the temp as the result and free it up */
  7074.  
  7075.     genLclVarRef(tnum, false);
  7076.     genTempVarRls(type, tnum);
  7077. }
  7078.  
  7079. /*****************************************************************************
  7080.  *
  7081.  *  Initialize the line# recording logic - called once per function.
  7082.  */
  7083.  
  7084. void                genIL::genLineNumInit()
  7085. {
  7086.     genLineNumList     =
  7087.     genLineNumLast     = NULL;
  7088.  
  7089.     genLineNumLastLine = 0;
  7090.  
  7091.     genLineNumLastBlk  = NULL;
  7092.     genLineNumLastOfs  = 0;
  7093.  
  7094.     genLineNums        = genComp->cmpConfig.ccLineNums |
  7095.                          genComp->cmpConfig.ccGenDebug;
  7096. }
  7097.  
  7098. /*****************************************************************************
  7099.  *
  7100.  *  Shut down  the line# recording logic - called once per function.
  7101.  */
  7102.  
  7103. inline
  7104. void                genIL::genLineNumDone()
  7105. {
  7106. }
  7107.  
  7108. /*****************************************************************************
  7109.  *
  7110.  *  If we're generating line number info, record the line# / MSIL offset
  7111.  *  for the given expression node.
  7112.  */
  7113.  
  7114. void                genIL::genRecExprAdr(Tree expr)
  7115. {
  7116.     LineInfo        line;
  7117.  
  7118.     /* Bail if we're not generating debug info */
  7119.  
  7120.     if  (!genLineNums)
  7121.         return;
  7122.  
  7123.     /* Ignore anything that was added by the compiler */
  7124.  
  7125.     if  (expr->tnFlags & TNF_NOT_USER)
  7126.         return;
  7127.  
  7128.     /* Weed out those statements that never generate code */
  7129.  
  7130.     switch (expr->tnOper)
  7131.     {
  7132.     case TN_TRY:
  7133.     case TN_LIST:
  7134.     case TN_BLOCK:
  7135.     case TN_CATCH:
  7136.     case TN_DCL_VAR:
  7137.         return;
  7138.  
  7139.     case TN_VAR_DECL:
  7140.         if  (!(expr->tnFlags & TNF_VAR_INIT))
  7141.             return;
  7142.         break;
  7143.     }
  7144.  
  7145.     assert(expr->tnLineNo != 0xDDDDDDDD);
  7146.  
  7147.     /* Bail if we have the same line# as last time */
  7148.  
  7149.     if  (genLineNumLastLine == expr->tnLineNo)
  7150.         return;
  7151.  
  7152.     /* Bail if the code position is the same as last time */
  7153.  
  7154.     if  (genLineNumLastBlk  == genBuffCurAddr() &&
  7155.          genLineNumLastOfs  == genBuffCurOffs())
  7156.     {
  7157.         return;
  7158.     }
  7159.  
  7160. #ifdef  DEBUG
  7161. //  if  (genDispCode) genDumpSourceLines(expr->tnLineNo);
  7162. #endif
  7163.  
  7164. //  printf("Record line# %u\n", expr->tnLineNo);
  7165.  
  7166.     /* Allocate a line# record and append it to the list */
  7167.  
  7168. #if MGDDATA
  7169.     line = new LineInfo;
  7170. #else
  7171.     line =    (LineInfo)genAlloc->nraAlloc(sizeof(*line));
  7172. #endif
  7173.  
  7174.     line->lndLineNum = genLineNumLastLine = expr->tnLineNo;
  7175.  
  7176.     line->lndBlkAddr = genLineNumLastBlk  = genBuffCurAddr();
  7177.     line->lndBlkOffs = genLineNumLastOfs  = genBuffCurOffs();
  7178.  
  7179.     line->lndNext    = NULL;
  7180.  
  7181.     if  (genLineNumLast)
  7182.         genLineNumLast->lndNext = line;
  7183.     else
  7184.         genLineNumList          = line;
  7185.  
  7186.     genLineNumLast = line;
  7187. }
  7188.  
  7189. /*****************************************************************************
  7190.  *
  7191.  *  Generate the line# table for the current function; returns the number
  7192.  *  of line number entries (if the argument[s] is/are NULL, this is just
  7193.  *  a 'dry run' to get the size of the table, no data is written).
  7194.  */
  7195.  
  7196. size_t              genIL::genLineNumOutput(unsigned *offsTab, unsigned *lineTab)
  7197. {
  7198.     LineInfo        line;
  7199.  
  7200.     int             offs;
  7201.     int             last = (unsigned)-1;
  7202.  
  7203.     assert(genLineNums);
  7204.  
  7205.     unsigned        count = 0;
  7206.  
  7207.     for (line = genLineNumList; line; line = line->lndNext)
  7208.     {
  7209.         offs = genCodeAddr(line->lndBlkAddr,
  7210.                            line->lndBlkOffs);
  7211.  
  7212.         if  (offs > last)
  7213.         {
  7214.             if  (offsTab)
  7215.             {
  7216.                 assert(lineTab);
  7217.  
  7218. //              if  (!strcmp(genFncSym->sdParent->sdSpelling(), "Guid"))
  7219. //                  printf("    Line %04u is at MSIL offset 0x%04X\n", line->lndLineNum, offs);
  7220.  
  7221.                 offsTab[count] = offs;
  7222.                 lineTab[count] = line->lndLineNum;
  7223.             }
  7224.  
  7225.             last = offs;
  7226.             count++;
  7227.         }
  7228.     }
  7229.  
  7230.     return count;
  7231. }
  7232.  
  7233. /*****************************************************************************
  7234.  *
  7235.  *  Generate MSIL for a function - start.
  7236.  */
  7237.  
  7238. void                genIL::genFuncBeg(SymTab stab,
  7239.                                       SymDef fncSym, unsigned lclCnt)
  7240. {
  7241.     genStab   = stab;
  7242.     genFncSym = fncSym;
  7243.  
  7244. #if DISP_IL_CODE
  7245.  
  7246.     genDispCode      = genComp->cmpConfig.ccDispCode;
  7247.     genILblockLabNum = 0;
  7248.  
  7249.     if  (genDispCode)
  7250.     {
  7251.         printf("\nGenerating MSIL for '%s'\n", stab->stTypeName(fncSym->sdType, fncSym, NULL, NULL, true));
  7252.         printf("======================================================\n");
  7253.         printf("[offs:sl]");
  7254.         if  (genComp->cmpConfig.ccDispILcd)
  7255.             printf("%*s ", -(int)IL_OPCDSP_LEN, "");
  7256.         printf("\n");
  7257.         printf("======================================================\n");
  7258.     }
  7259.  
  7260. #endif
  7261.  
  7262.     genCurStkLvl     = 0;
  7263.     genILblockOffs   = 0;
  7264.  
  7265.     genEHtableInit();
  7266.  
  7267.     genTempVarBeg(lclCnt);
  7268.     genSectionBeg();
  7269.  
  7270.     genLineNumInit();
  7271. }
  7272.  
  7273. /*****************************************************************************
  7274.  *
  7275.  *  Generate MSIL for a function - finish up and return the function's RVA.
  7276.  */
  7277.  
  7278. unsigned            genIL::genFuncEnd(mdSignature sigTok, bool hadErrs)
  7279. {
  7280.     Compiler        comp = genComp;
  7281.  
  7282.     size_t          size;
  7283.     unsigned        fncRVA;
  7284.  
  7285.     size_t          EHsize;
  7286.     unsigned        EHcount;
  7287.  
  7288.     BYTE    *       codeAddr;
  7289.  
  7290.     /* Finish the last section of code */
  7291.  
  7292.     size = genSectionEnd();
  7293.  
  7294.     /* Shut down the temp logic */
  7295.  
  7296.     genTempVarEnd();
  7297.  
  7298.     /* Bail if we had errors */
  7299.  
  7300.     if  (hadErrs)
  7301.         return  0;
  7302.  
  7303.     /* Figure out how much space we will need */
  7304.  
  7305.     size_t                  tsiz = size;
  7306.  
  7307.     COR_ILMETHOD_FAT        hdr;
  7308.     size_t                  hdrs;
  7309.     size_t                  align;
  7310.     EH_CLAUSE_TAB           EHlist;
  7311.     bool                    addSects;
  7312.  
  7313.     /* Do we need any additional header sections? */
  7314.  
  7315.     addSects = false;
  7316.  
  7317.     /* Do we have any exception handlers? */
  7318.  
  7319.     EHcount = genEHtableCnt();
  7320.     if  (EHcount)
  7321.     {
  7322.         addSects = true;
  7323.  
  7324.         /* The extra section needs to be aligned */
  7325.  
  7326.         tsiz = roundUp(tsiz, sizeof(int));
  7327.     }
  7328.  
  7329.     /* Start filling in the method header */
  7330.  
  7331.     hdr.Flags          = (comp->cmpConfig.ccSafeMode) ? CorILMethod_InitLocals : 0;
  7332.     hdr.Size           = sizeof(hdr) / sizeof(int);
  7333.     hdr.MaxStack       = genMaxStkLvl;
  7334.     hdr.CodeSize       = size;
  7335.     hdr.LocalVarSigTok = sigTok;
  7336.  
  7337.     /* Compute the total header size */
  7338.  
  7339.     hdrs  = WRAPPED_IlmethodSize(&hdr, addSects);
  7340.     tsiz += hdrs;
  7341.  
  7342.     /* Reserve extra space for the EH tables */
  7343.  
  7344.     if  (EHcount)
  7345.     {
  7346.         /* Create the EH table */
  7347.  
  7348. #if MGDDATA
  7349.         EHlist = new EH_CLAUSE[EHcount];
  7350. #else
  7351.         EHlist = (EH_CLAUSE_TAB)genAlloc->nraAlloc(EHcount * sizeof(*EHlist));
  7352. #endif
  7353.  
  7354.         genEHtableWrt(EHlist);
  7355.  
  7356.         /* Now we can figure out the size of the thing */
  7357.  
  7358.         EHsize = WRAPPED_SectEH_SizeExact(EHcount, EHlist);
  7359.         tsiz   = roundUp(tsiz + EHsize);
  7360.     }
  7361.     else
  7362.         EHlist = NULL;
  7363.  
  7364.     /* Figure out the header alignment (tiny headers don't need any) */
  7365.  
  7366.     align = (hdrs == 1) ? 1 : sizeof(int);
  7367.  
  7368.     /* Allocate space in the code section of the output file */
  7369.  
  7370.     fncRVA = genPEwriter->WPEallocCode(tsiz, align, codeAddr);
  7371.  
  7372. //  if  (!strcmp(genFncSym->sdSpelling(), "xxxxx")) printf("RVA=%08X '%s'\n", fncRVA, genStab->stTypeName(NULL, genFncSym, NULL, NULL, true));
  7373.  
  7374.     if  (codeAddr)
  7375.     {
  7376.         BYTE    *           fnBase = codeAddr;
  7377.  
  7378. #if 0
  7379.         printf("Header is   at %08X\n", codeAddr);
  7380.         printf("Code starts at %08X\n", codeAddr + hdrs);
  7381.         printf("EHtable is  at %08X\n", codeAddr + hdrs + size);
  7382.         printf("Very end is at %08X\n", codeAddr + tsiz);
  7383. #endif
  7384.  
  7385. #ifdef  DEBUG
  7386. //      IMAGE_COR_ILMETHOD_FAT  * hdrPtr = (IMAGE_COR_ILMETHOD_FAT*)codeAddr;
  7387. #endif
  7388.  
  7389.         /* Emit the header and skip over it */
  7390.  
  7391.         codeAddr += WRAPPED_IlmethodEmit(hdrs, &hdr, addSects, codeAddr);
  7392.  
  7393.         /* Make sure the address is aligned properly */
  7394.  
  7395. #if 0
  7396.         printf("Base is at %08X\n", hdrPtr);
  7397.         printf("Code is at %08X\n", hdrPtr->GetCode());
  7398.         printf("Addr is at %08X\n", codeAddr);
  7399. #endif
  7400.  
  7401. //      assert(hdrPtr->GetCode() == codeAddr);      ISSUE: why does this fail?
  7402.  
  7403. #ifndef NDEBUG
  7404.         BYTE    *           codeBase = codeAddr;
  7405. #endif
  7406.  
  7407.         /* Store the MSIL next */
  7408.  
  7409.         codeAddr = genSectionCopy(codeAddr, codeAddr + fncRVA - fnBase);
  7410.  
  7411.         /* Make sure the we output the expected amount of code */
  7412.  
  7413.         assert(codeAddr == codeBase + size);
  7414.  
  7415.         /* Append the EH tables */
  7416.  
  7417.         if  (EHcount)
  7418.         {
  7419.             /* Make sure the EH table is aligned and output it */
  7420.  
  7421.             if  ((NatUns)codeAddr & 3)
  7422.                 codeAddr += 4 - ((NatUns)codeAddr & 3);
  7423.  
  7424.             codeAddr += WRAPPED_SectEH_Emit(EHsize, EHcount, EHlist, false, codeAddr);
  7425.         }
  7426.  
  7427.         /* Make sure we've generated the right amount of junk */
  7428.  
  7429. #if 0
  7430.         printf("Header size = %u\n", hdrs);
  7431.         printf("Code   size = %u\n", size);
  7432.         printf("Total  size = %u\n", tsiz);
  7433.         printf("Actual size = %u\n", codeAddr - (BYTE *)hdrPtr);
  7434. #endif
  7435.  
  7436.         assert(codeAddr == fnBase + tsiz);
  7437.     }
  7438.  
  7439.     return  fncRVA;
  7440. }
  7441.  
  7442. /*****************************************************************************/
  7443.