summaryrefslogtreecommitdiff
path: root/src/jit/codegenclassic.h
blob: 46a70aade2be795126e21e309af6237c1c864dc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//
// This file contains the members of CodeGen that are defined and used
// only by the "classic" JIT backend.  It is included by CodeGen.h in the
// definition of the CodeGen class.
// 

#ifndef _CODEGENCLASSIC_H_
#define _CODEGENCLASSIC_H_

#ifdef LEGACY_BACKEND // Not necessary (it's this way in the #include location), but helpful to IntelliSense

public:

    regNumber           genIsEnregisteredIntVariable(GenTreePtr tree);

    void                sched_AM        (instruction    ins,
                                         emitAttr       size,
                                         regNumber      ireg,
                                         bool           rdst,
                                         GenTreePtr     tree,
                                         unsigned       offs,
                                         bool           cons  = false,
                                         int            cval  = 0,
                                         insFlags       flags = INS_FLAGS_DONT_CARE);

protected:

#if FEATURE_STACK_FP_X87
    VARSET_TP           genFPregVars;       // mask corresponding to genFPregCnt
    unsigned            genFPdeadRegCnt;    // The dead unpopped part of genFPregCnt
#endif // FEATURE_STACK_FP_X87


    //-------------------------------------------------------------------------

    void                genSetRegToIcon     (regNumber      reg,
                                             ssize_t        val,
                                             var_types      type  = TYP_INT,
                                             insFlags       flags = INS_FLAGS_DONT_CARE);

    regNumber           genGetRegSetToIcon  (ssize_t        val,
                                             regMaskTP      regBest = 0,
                                             var_types      type    = TYP_INT);
    void                genDecRegBy         (regNumber      reg,
                                             ssize_t        ival,
                                             GenTreePtr     tree);

    void                genMulRegBy         (regNumber      reg,
                                             ssize_t        ival,
                                             GenTreePtr     tree,
                                             var_types      dstType = TYP_INT,
                                             bool           ovfl    = false);

    //-------------------------------------------------------------------------

    bool                genRegTrashable     (regNumber      reg,
                                             GenTreePtr     tree);

    //
    // Prolog functions and data (there are a few exceptions for more generally used things)
    //

    regMaskTP           genPInvokeMethodProlog(regMaskTP    initRegs);

    void                genPInvokeMethodEpilog();    

    regNumber           genPInvokeCallProlog(LclVarDsc*     varDsc,
                                             int            argSize,
                                      CORINFO_METHOD_HANDLE methodToken,
                                             BasicBlock*    returnLabel);

    void                genPInvokeCallEpilog(LclVarDsc*     varDsc,
                                             regMaskTP      retVal);

    regNumber           genLclHeap          (GenTreePtr     size);

    void                genSinglePush       ();

    void                genSinglePop        ();


    void                genDyingVars        (VARSET_VALARG_TP      beforeSet,
                                             VARSET_VALARG_TP      afterSet);

    bool                genContainsVarDeath (GenTreePtr from, GenTreePtr to, unsigned varNum);

    void                genComputeReg       (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::ExactReg       mustReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           freeOnly = false);

    void                genCompIntoFreeReg  (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg);

    void                genReleaseReg       (GenTreePtr     tree);

    void                genRecoverReg       (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg);

    void                genMoveRegPairHalf  (GenTreePtr     tree,
                                             regNumber      dst,
                                             regNumber      src,
                                             int            off = 0);

    void                genMoveRegPair      (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             regPairNo      newPair);

    void                genComputeRegPair   (GenTreePtr     tree,
                                             regPairNo      needRegPair,
                                             regMaskTP      avoidReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           freeOnly = false);

    void              genCompIntoFreeRegPair(GenTreePtr     tree,
                                             regMaskTP      avoidReg,
                                             RegSet::KeepReg        keepReg);

    void               genComputeAddressable(GenTreePtr     tree,
                                             regMaskTP      addrReg,
                                             RegSet::KeepReg        keptReg,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           freeOnly = false);

    void                genReleaseRegPair   (GenTreePtr     tree);

    void                genRecoverRegPair   (GenTreePtr     tree,
                                             regPairNo      regPair,
                                             RegSet::KeepReg        keepReg);

    void              genEvalIntoFreeRegPair(GenTreePtr     tree,
                                             regPairNo      regPair,
                                             regMaskTP      avoidReg);

    void             genMakeRegPairAvailable(regPairNo regPair);

    bool                genMakeIndAddrMode  (GenTreePtr     addr,
                                             GenTreePtr     oper,
                                             bool           forLea,
                                             regMaskTP      regMask,
                                             RegSet::KeepReg        keepReg,
                                             regMaskTP*     useMaskPtr,
                                             bool           deferOp = false);

    regMaskTP           genMakeRvalueAddressable(GenTreePtr tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           forLoadStore,
                                             bool           smallOK = false);

    regMaskTP           genMakeAddressable  (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           smallOK = false,
                                             bool           deferOK = false);

    regMaskTP           genMakeAddrArrElem  (GenTreePtr     arrElem,
                                             GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg);

    regMaskTP           genMakeAddressable2 (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             RegSet::KeepReg        keepReg,
                                             bool           forLoadStore,
                                             bool           smallOK = false,
                                             bool           deferOK = false,
                                             bool           evalSideEffs = false);

    bool                genStillAddressable (GenTreePtr     tree);


    regMaskTP           genRestoreAddrMode  (GenTreePtr     addr,
                                             GenTreePtr     tree,
                                             bool           lockPhase);

    regMaskTP           genRestAddressable  (GenTreePtr     tree,
                                             regMaskTP      addrReg,
                                             regMaskTP      lockMask);

    regMaskTP           genKeepAddressable  (GenTreePtr     tree,
                                             regMaskTP      addrReg,
                                             regMaskTP      avoidMask = RBM_NONE);

    void                genDoneAddressable  (GenTreePtr     tree,
                                             regMaskTP      addrReg,
                                             RegSet::KeepReg        keptReg);

    GenTreePtr          genMakeAddrOrFPstk  (GenTreePtr     tree,
                                             regMaskTP*     regMaskPtr,
                                             bool           roundResult);

    void                genEmitGSCookieCheck(bool           pushReg);

    void                genEvalSideEffects  (GenTreePtr     tree);


    void                genCondJump         (GenTreePtr     cond,
                                             BasicBlock*    destTrue  = NULL,
                                             BasicBlock*    destFalse = NULL,
                                             bool           bStackFPFixup = true);


    emitJumpKind        genCondSetFlags     (GenTreePtr     cond);


    void                genJCC              (genTreeOps     cmp,
                                             BasicBlock*    block,
                                             var_types      type);

    void                genJccLongHi        (genTreeOps     cmp,
                                             BasicBlock*    jumpTrue,
                                             BasicBlock*    jumpFalse,
                                             bool           unsOper = false);

    void                genJccLongLo        (genTreeOps     cmp,
                                             BasicBlock*    jumpTrue,
                                             BasicBlock*    jumpFalse);

    void                genCondJumpLng      (GenTreePtr     cond,
                                             BasicBlock*    jumpTrue,
                                             BasicBlock*    jumpFalse,
                                             bool bFPTransition = false);

    bool                genUse_fcomip();

    void                genTableSwitch      (regNumber      reg,
                                             unsigned       jumpCnt,
                                             BasicBlock**  jumpTab);

    regMaskTP           WriteBarrier        (GenTreePtr     tgt,
                                             GenTreePtr     assignVal,
                                             regMaskTP      addrReg);

    void                genCodeForTreeConst (GenTreePtr     tree,
                                             regMaskTP      destReg,
                                             regMaskTP      bestReg = RBM_NONE);

    void                genCodeForTreeLeaf  (GenTreePtr     tree,
                                             regMaskTP      destReg,
                                             regMaskTP      bestReg = RBM_NONE);

    // If "tree" is a comma node, generates code for the left comma arguments,
    // in order, returning the first right argument in the list that is not
    // a comma node.
    GenTreePtr          genCodeForCommaTree (GenTreePtr     tree);

    void                genCodeForTreeLeaf_GT_JMP (GenTreePtr     tree);

    static Compiler::fgWalkPreFn  fgIsVarAssignedTo;

    void                genCodeForQmark     (GenTreePtr tree,
                                             regMaskTP  destReg,
                                             regMaskTP  bestReg);

    bool                genCodeForQmarkWithCMOV (GenTreePtr tree,
                                                 regMaskTP  destReg,
                                                 regMaskTP  bestReg);

#ifdef _TARGET_XARCH_
    void                genCodeForMultEAX   (GenTreePtr     tree);
#endif
#ifdef _TARGET_ARM_
    void                genCodeForMult64    (GenTreePtr     tree,
                                             regMaskTP      destReg,
                                             regMaskTP      bestReg);
#endif

    void                genCodeForTreeSmpBinArithLogOp      (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForTreeSmpBinArithLogAsgOp   (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForUnsignedMod               (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForSignedMod                 (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForUnsignedDiv               (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForSignedDiv                 (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForGeneralDivide             (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForAsgShift                  (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForShift                     (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForRelop                     (GenTreePtr tree,
                                                             regMaskTP  destReg,
                                                             regMaskTP  bestReg);

    void                genCodeForCopyObj                   (GenTreePtr tree,
                                                             regMaskTP  destReg);

    void                genCodeForBlkOp                     (GenTreePtr tree,
                                                             regMaskTP  destReg);

    void                genCodeForTreeSmpOp (GenTreePtr     tree,
                                             regMaskTP      destReg,
                                             regMaskTP      bestReg = RBM_NONE);

    regNumber           genIntegerCast(GenTree* tree, regMaskTP needReg, regMaskTP bestReg);
    
    void                genCodeForNumericCast(GenTreePtr     tree,
                                              regMaskTP      destReg,
                                              regMaskTP      bestReg);

    void                genCodeForTreeSmpOp_GT_ADDR (GenTreePtr     tree,
                                                     regMaskTP      destReg,
                                                     regMaskTP      bestReg = RBM_NONE);

    void                genCodeForTreeSmpOpAsg (GenTreePtr     tree);

    void                genCodeForTreeSmpOpAsg_DONE_ASSG(GenTreePtr tree,
                                                         regMaskTP  addrReg,
                                                         regNumber  reg,
                                                         bool       ovfl);

    void                genCodeForTreeSpecialOp (GenTreePtr     tree,
                                                 regMaskTP      destReg,
                                                 regMaskTP      bestReg = RBM_NONE);

    void                genCodeForTree      (GenTreePtr     tree,
                                             regMaskTP      destReg,
                                             regMaskTP      bestReg = RBM_NONE);

    void                genCodeForTree_DONE_LIFE (GenTreePtr     tree,
                                                  regNumber      reg)
    {
        /* We've computed the value of 'tree' into 'reg' */

        assert(reg != 0xFEEFFAAFu);
        assert(!IsUninitialized(reg));

        genMarkTreeInReg(tree, reg);
    }

    void                genCodeForTree_DONE_LIFE (GenTreePtr     tree,
                                                  regPairNo      regPair)
    {
        /* We've computed the value of 'tree' into 'regPair' */

        genMarkTreeInRegPair(tree, regPair);
    }

    void                genCodeForTree_DONE (GenTreePtr     tree,
                                             regNumber      reg)
    {
        /* Check whether this subtree has freed up any variables */

        genUpdateLife(tree);

        genCodeForTree_DONE_LIFE(tree, reg);
    }

    void                genCodeForTree_REG_VAR1 (GenTreePtr     tree)
    {
        /* Value is already in a register */

        regNumber reg   = tree->gtRegNum;

        gcInfo.gcMarkRegPtrVal(reg, tree->TypeGet());

        genCodeForTree_DONE(tree, reg);
    }

    void                genCodeForTreeLng   (GenTreePtr     tree,
                                             regMaskTP      needReg,
                                             regMaskTP      avoidReg);

    regPairNo           genCodeForLongModInt(GenTreePtr     tree,
                                             regMaskTP      needReg);

    unsigned            genRegCountForLiveIntEnregVars(GenTreePtr tree);

#ifdef _TARGET_ARM_
    void                genStoreFromFltRetRegs    (GenTreePtr tree);
    void                genLoadIntoFltRetRegs     (GenTreePtr tree);
    void                genLdStFltRetRegsPromotedVar (LclVarDsc* varDsc, bool isLoadIntoFltReg);
#endif

#if CPU_HAS_FP_SUPPORT
    void                genRoundFpExpression(GenTreePtr     op,
                                             var_types      type = TYP_UNDEF);
    void                genCodeForTreeFlt   (GenTreePtr     tree,
                                             regMaskTP      needReg = RBM_ALLFLOAT,
                                             regMaskTP      bestReg = RBM_NONE);
#endif

// FP stuff
#include        "fp.h"

    void                genCodeForJumpTable   (GenTreePtr     tree);
    void                genCodeForSwitchTable (GenTreePtr     tree);
    void                genCodeForSwitch      (GenTreePtr     tree);

    regMaskTP           genPushRegs         (regMaskTP      regs,
                                             regMaskTP*     byrefRegs,
                                             regMaskTP*     noRefRegs);
    void                genPopRegs          (regMaskTP      regs,
                                             regMaskTP      byrefRegs,
                                             regMaskTP      noRefRegs);

    size_t              genPushArgList      (GenTreePtr     call);

#ifdef _TARGET_ARM_
    // We are generating code for a promoted struct local variable.  Fill the next slot (register or
    // 4-byte stack slot) with one or more field variables of the promoted struct local -- or 2 such slots
    // if the next field is a 64-bit value.
    // The arguments are:
    //    "arg" is the current argument node.
    //
    //    "curArgTabEntry" arg table entry pointer for "arg".
    //
    //    "promotedStructLocalVarDesc" describes the struct local being copied, assumed non-NULL.
    // 
    //    "fieldSize" is somewhat misnamed; it must be the element in the struct's GC layout describing the next slot
    //       of the struct -- it will be EA_4BYTE, EA_GCREF, or EA_BYREF.
    // 
    //    "*pNextPromotedStructFieldVar" must be the the local variable number of the next field variable to copy;
    //       this location will be updated by the call to reflect the bytes that are copied.
    // 
    //    "*pBytesOfNextSlotOfCurPromotedStruct" must be the number of bytes within the struct local at which the next
    //       slot to be copied starts.  This location will be updated by the call to reflect the bytes that are copied.
    //
    //    "*pCurRegNum" must be the current argument register number, and will be updated if argument registers are filled.
    //
    //    "argOffset" must be the offset of the next slot to be filled in the outgoing argument area, if the argument is to be
    //       put in the outgoing arg area of the stack (or else should be INT_MAX if the next slot to be filled is a register).
    //       (Strictly speaking, after the addition of "argOffsetOfFirstStackSlot", this arg is redundant, and is only used
    //       in assertions, and could be removed.)
    //
    //    "fieldOffsetOfFirstStackSlot" must be the offset within the promoted struct local of the first slot that should be
    //       copied to the outgoing argument area -- non-zero only in the case of a struct that spans registers and stack slots.
    //
    //    "argOffsetOfFirstStackSlot" must be the 4-byte-aligned offset of the first offset in the outgoing argument area which could
    //       contain part of the struct.  (Explicit alignment may mean it doesn't actually contain part of the struct.)
    //
    //    "*deadFieldVarRegs" is an out parameter, the set of registers containing promoted field variables that become dead after
    //       this (implicit) use.
    //
    //    "*pRegTmp" -- if a temporary register is needed, and this is not REG_STK, uses that register.  Otherwise, if it is REG_STK,
    //       allocates a register, uses it, and sets "*pRegTmp" to the allocated register.
    //
    // Returns "true" iff it filled two slots with an 8-byte value.
    bool                genFillSlotFromPromotedStruct(GenTreePtr arg,
                                                      fgArgTabEntryPtr curArgTabEntry,
                                                      LclVarDsc* promotedStructLocalVarDesc, 
                                                      emitAttr fieldSize,
                                                      unsigned* pNextPromotedStructFieldVar,         // IN/OUT
                                                      unsigned* pBytesOfNextSlotOfCurPromotedStruct, // IN/OUT
                                                      regNumber* pCurRegNum,                         // IN/OUT
                                                      int argOffset,
                                                      int fieldOffsetOfFirstStackSlot,
                                                      int argOffsetOfFirstStackSlot,
                                                      regMaskTP* deadFieldVarRegs,                   // OUT
                                                      regNumber* pRegTmp);                           // IN/OUT


#endif // _TARGET_ARM_
    // Requires that "curr" is a cpblk.  If the RHS is a promoted struct local,
    // then returns a regMaskTP representing the set of registers holding
    // fieldVars of the RHS that go dead with this use (as determined by the live set
    // of cpBlk).
    regMaskTP           genFindDeadFieldRegs(GenTreePtr cpBlk);

    void                SetupLateArgs       (GenTreePtr     call);

#ifdef _TARGET_ARM_
    void                PushMkRefAnyArg  (GenTreePtr       mkRefAnyTree,
                                          fgArgTabEntryPtr curArgTabEntry,
                                          regMaskTP        regNeedMask);
#endif // _TARGET_ARM_

    regMaskTP           genLoadIndirectCallTarget(GenTreePtr  call);

    regMaskTP           genCodeForCall      (GenTreePtr     call,
                                             bool           valUsed);

    GenTreePtr          genGetAddrModeBase  (GenTreePtr     tree);

    GenTreePtr          genIsAddrMode       (GenTreePtr     tree,
                                             GenTreePtr*    indxPtr);
private:

    bool                genIsLocalLastUse   (GenTreePtr     tree);

    bool                genIsRegCandidateLocal(GenTreePtr     tree);

    //=========================================================================
    //  Debugging support
    //=========================================================================



#if FEATURE_STACK_FP_X87
    /*
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XX                                                                           XX
    XX                   Flat FP model                                           XX
    XX                                                                           XX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    */

    bool            StackFPIsSameAsFloat                    (double d);
    bool            FlatFPSameRegisters                     (FlatFPStateX87* pState, regMaskTP mask);

    // FlatFPStateX87_ functions are the actual verbs to do stuff
    // like doing a transition, loading   register, etc. It's also
    // responsible for emitting the x87 code to do so. We keep
    // them in Compiler because we don't want to store a pointer to the
    // emitter.
    void            FlatFPX87_Kill                          (FlatFPStateX87* pState, unsigned iVirtual);
    void            FlatFPX87_PushVirtual                   (FlatFPStateX87* pState, unsigned iRegister, bool bEmitCode = true);
    unsigned        FlatFPX87_Pop                           (FlatFPStateX87* pState, bool bEmitCode = true);
    unsigned        FlatFPX87_Top                           (FlatFPStateX87* pState, bool bEmitCode = true);
    void            FlatFPX87_Unload                        (FlatFPStateX87* pState, unsigned iVirtual, bool bEmitCode = true);
#endif  

    // Codegen functions. This is the API that codegen will use
    regMaskTP       genPushArgumentStackFP                   (GenTreePtr     arg);
    void            genRoundFpExpressionStackFP              (GenTreePtr op, var_types type = TYP_UNDEF);
    void            genCodeForTreeStackFP_Const              (GenTreePtr tree);
    void            genCodeForTreeStackFP_Leaf               (GenTreePtr tree);
    void            genCodeForTreeStackFP_SmpOp              (GenTreePtr tree);
    void            genCodeForTreeStackFP_Special            (GenTreePtr tree);
    void            genCodeForTreeStackFP_Cast               (GenTreePtr tree);
    void            genCodeForTreeStackFP                    (GenTreePtr tree);
    void            genCondJumpFltStackFP                    (GenTreePtr     cond,
                                                             BasicBlock*    jumpTrue,
                                                             BasicBlock*    jumpFalse,
                                                             bool bDoTransition = true);
    void            genCondJumpFloat                         (GenTreePtr     cond,
                                                             BasicBlock*    jumpTrue,
                                                             BasicBlock*    jumpFalse);
    void            genCondJumpLngStackFP                    (GenTreePtr     cond,
                                                             BasicBlock*    jumpTrue,
                                                             BasicBlock*    jumpFalse);

    void            genFloatConst(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genFloatLeaf(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genFloatSimple(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genFloatMath(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genFloatCheckFinite(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genLoadFloat(GenTreePtr tree, regNumber reg);
    void            genFloatAssign(GenTree* tree);
    void            genFloatArith(GenTree* tree, RegSet::RegisterPreference* pref);
    void            genFloatAsgArith(GenTree* tree);

    regNumber       genAssignArithFloat(genTreeOps oper, 
                                        GenTreePtr dst, regNumber dstreg, 
                                        GenTreePtr src, regNumber srcreg);


    GenTreePtr      genMakeAddressableFloat(GenTreePtr tree, 
                                            regMaskTP*   regMaskIntPtr, regMaskTP*   regMaskFltPtr, 
                                            bool bCollapseConstantDoubles = true);

    void            genCodeForTreeFloat(GenTreePtr tree,
                                        RegSet::RegisterPreference* pref = NULL);

    void            genCodeForTreeFloat(GenTreePtr tree,
                                        regMaskTP  needReg, regMaskTP bestReg);

    regNumber       genArithmFloat(genTreeOps oper, 
                                   GenTreePtr dst, regNumber dstreg, 
                                   GenTreePtr src, regNumber srcreg, 
                                   bool bReverse);
    void            genCodeForTreeCastFloat(GenTreePtr tree, RegSet::RegisterPreference* pref);
    void            genCodeForTreeCastToFloat(GenTreePtr tree, RegSet::RegisterPreference* pref);
    void            genCodeForTreeCastFromFloat(GenTreePtr tree, RegSet::RegisterPreference* pref);
    void            genKeepAddressableFloat(GenTreePtr tree, regMaskTP*  regMaskIntPtr, regMaskTP*  regMaskFltPtr);
    void            genDoneAddressableFloat(GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg);
    void            genComputeAddressableFloat(GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg, regMaskTP needReg, RegSet::KeepReg keepReg, bool freeOnly = false);
    void            genRoundFloatExpression(GenTreePtr op, var_types type);



#if FEATURE_STACK_FP_X87
    // Assumes then block will be generated before else block.
    struct QmarkStateStackFP
    {
        FlatFPStateX87 stackState;
    };

    void            genQMarkRegVarTransition                (GenTreePtr nextNode, VARSET_VALARG_TP liveset);
    void            genQMarkBeforeElseStackFP               (QmarkStateStackFP*  pState, VARSET_VALARG_TP varsetCond, GenTreePtr nextNode);
    void            genQMarkAfterElseBlockStackFP           (QmarkStateStackFP*  pState, VARSET_VALARG_TP varsetCond, GenTreePtr nextNode);
    void            genQMarkAfterThenBlockStackFP           (QmarkStateStackFP*  pState);

#endif

    GenTreePtr      genMakeAddressableStackFP               (GenTreePtr tree, regMaskTP*   regMaskIntPtr, regMaskTP*   regMaskFltPtr, bool bCollapseConstantDoubles = true);
    void            genKeepAddressableStackFP               (GenTreePtr tree, regMaskTP*   regMaskIntPtr, regMaskTP*   regMaskFltPtr);
    void            genDoneAddressableStackFP               (GenTreePtr tree, regMaskTP addrRegInt, regMaskTP addrRegFlt, RegSet::KeepReg keptReg);


    void            genCodeForTreeStackFP_Asg               (GenTreePtr tree);
    void            genCodeForTreeStackFP_AsgArithm         (GenTreePtr tree);
    void            genCodeForTreeStackFP_Arithm            (GenTreePtr tree);
    void            genCodeForTreeStackFP_DONE              (GenTreePtr tree, regNumber reg);
    void            genCodeForTreeFloat_DONE                (GenTreePtr tree, regNumber reg);

    void            genSetupStateStackFP                     (BasicBlock* block);
    regMaskTP       genRegMaskFromLivenessStackFP            (VARSET_VALARG_TP varset);

    // bReverse means make op1 addressable and codegen for op2.
    // If op1 or op2 are comma expressions, will do code-gen for their non-last comma parts,
    // and set op1 and op2 to the remaining non-comma expressions.
    void            genSetupForOpStackFP                     (GenTreePtr& op1, GenTreePtr& op2,
                                                             bool bReverse,
                                                             bool bMakeOp1Addressable,
                                                             bool bOp1ReadOnly,
                                                             bool bOp2ReadOnly);


#if FEATURE_STACK_FP_X87

#ifdef  DEBUG
    bool            ConsistentAfterStatementStackFP        ();
#endif

private:
    void            SpillTempsStackFP                      (regMaskTP canSpillMask);
    void            SpillForCallStackFP                    ();
    void            UnspillRegVarsStackFp                  ();

    // Transition API. Takes care of the stack matching of basicblock boundaries
    void            genCodeForPrologStackFP                ();
    void            genCodeForEndBlockTransitionStackFP    (BasicBlock* block);

    void            genCodeForBBTransitionStackFP          (BasicBlock* pDst);
    void            genCodeForTransitionStackFP            (FlatFPStateX87* pSrc, FlatFPStateX87* pDst);
    void            genCodeForTransitionFromMask           (FlatFPStateX87* pSrc, regMaskTP mask, bool bEmitCode = true);
    BasicBlock*     genTransitionBlockStackFP              (FlatFPStateX87* pState, BasicBlock* pFrom, BasicBlock* pTarget);

    // This is the API codegen will use to emit virtual fp code. In theory, nobody above this API
    // should know about x87 instructions.

    int             genNumberTemps                         ();
    void            genDiscardStackFP                      (GenTreePtr tree);
    void            genRegRenameWithMasks                  (regNumber dstReg, regNumber srcReg);
    void            genRegVarBirthStackFP                  (GenTreePtr tree);
    void            genRegVarBirthStackFP                  (LclVarDsc* varDsc);
    void            genRegVarDeathStackFP                  (GenTreePtr tree);
    void            genRegVarDeathStackFP                  (LclVarDsc* varDsc);
    void            genLoadStackFP                         (GenTreePtr tree, regNumber reg);
    void            genMovStackFP                          (GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg);
    bool            genCompInsStackFP                      (GenTreePtr tos, GenTreePtr other);
    regNumber       genArithmStackFP                       (genTreeOps oper, GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg, bool bReverse);
    regNumber       genAsgArithmStackFP                    (genTreeOps oper, GenTreePtr dst, regNumber dstreg, GenTreePtr src, regNumber srcreg);
    void            genCondJmpInsStackFP                   (emitJumpKind   jumpKind,
                                                            BasicBlock*    jumpTrue,
                                                            BasicBlock*    jumpFalse,
                                                            bool bDoTransition = true);
    void            genTableSwitchStackFP                  (regNumber      reg,
                                                            unsigned       jumpCnt,
                                                            BasicBlock**   jumpTab);

    void            JitDumpFPState                          ();
#else // !FEATURE_STACK_FP_X87
    void            SpillForCallRegisterFP                 (regMaskTP noSpillMask);
#endif // !FEATURE_STACK_FP_X87

    // When bOnlyNoMemAccess = true, the load will be generated only for constant loading that doesn't
    // involve memory accesses, (ie: fldz for positive zero, or fld1 for 1). Will return true the function
    // did the load
    bool            genConstantLoadStackFP                 (GenTreePtr tree,
                                                            bool bOnlyNoMemAccess = false);
    void            genEndOfStatement                      ();


#if FEATURE_STACK_FP_X87
    struct genRegVarDiesInSubTreeData
    {
        regNumber reg;
        bool      result;
    };
    static Compiler::fgWalkPreFn genRegVarDiesInSubTreeWorker;
    bool   genRegVarDiesInSubTree                          (GenTreePtr tree, regNumber reg);
#endif // FEATURE_STACK_FP_X87

    // Float spill
    void            UnspillFloat                           (RegSet::SpillDsc* spillDsc);
    void            UnspillFloat                           (GenTreePtr tree);
    void            UnspillFloat                           (LclVarDsc*  varDsc);
    void            UnspillFloatMachineDep                 (RegSet::SpillDsc* spillDsc);
    void            UnspillFloatMachineDep                 (RegSet::SpillDsc* spillDsc, bool useSameReg);
    void            RemoveSpillDsc                         (RegSet::SpillDsc* spillDsc);

protected :
    struct genLivenessSet
    {
        VARSET_TP      liveSet;
        VARSET_TP      varPtrSet;
        regMaskSmall   maskVars;
        regMaskSmall   gcRefRegs;
        regMaskSmall   byRefRegs;

        genLivenessSet() : VARSET_INIT_NOCOPY(liveSet, VarSetOps::UninitVal()),
                           VARSET_INIT_NOCOPY(varPtrSet, VarSetOps::UninitVal())
        {}
    };

    void saveLiveness    (genLivenessSet*  ls);
    void restoreLiveness (genLivenessSet*  ls);
    void checkLiveness   (genLivenessSet*  ls);
    void unspillLiveness (genLivenessSet*  ls);

    //-------------------------------------------------------------------------
    //
    //  If we know that the flags register is set to a value that corresponds
    //  to the current value of a register or variable, the following values
    //  record that information.
    //

    emitLocation        genFlagsEqLoc;
    regNumber           genFlagsEqReg;
    unsigned            genFlagsEqVar;

    void                genFlagsEqualToNone ();
    void                genFlagsEqualToReg  (GenTreePtr tree, regNumber reg);
    void                genFlagsEqualToVar  (GenTreePtr tree, unsigned  var);
    bool                genFlagsAreReg      (regNumber reg);
    bool                genFlagsAreVar      (unsigned  var);

#endif // LEGACY_BACKEND

#endif // _CODEGENCLASSIC_H_