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