summaryrefslogtreecommitdiff
path: root/src/jit/codegenclassic.h
blob: 81b7b34194f631457d07e1d9b6fb2ab8fed70836 (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
// 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 genIncRegBy(regNumber reg, ssize_t ival, GenTreePtr tree, var_types dstType = TYP_INT, bool ovfl = false);

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_