1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5//
6// This class contains all the data & functionality for code generation
7// of a method, except for the target-specific elements, which are
8// primarily in the Target class.
9//
10
11#ifndef _CODEGEN_H_
12#define _CODEGEN_H_
13#include "compiler.h" // temporary??
14#include "codegeninterface.h"
15#include "regset.h"
16#include "jitgcinfo.h"
17
18#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) || defined(_TARGET_ARM_)
19#define FOREACH_REGISTER_FILE(file) \
20 for ((file) = &(this->intRegState); (file) != NULL; \
21 (file) = ((file) == &(this->intRegState)) ? &(this->floatRegState) : NULL)
22#else
23#define FOREACH_REGISTER_FILE(file) (file) = &(this->intRegState);
24#endif
25
26class CodeGen : public CodeGenInterface
27{
28 friend class emitter;
29 friend class DisAssembler;
30
31public:
32 // This could use further abstraction
33 CodeGen(Compiler* theCompiler);
34
35 virtual void genGenerateCode(void** codePtr, ULONG* nativeSizeOfCode);
36 // TODO-Cleanup: Abstract out the part of this that finds the addressing mode, and
37 // move it to Lower
38 virtual bool genCreateAddrMode(GenTree* addr,
39 bool fold,
40 bool* revPtr,
41 GenTree** rv1Ptr,
42 GenTree** rv2Ptr,
43#if SCALED_ADDR_MODES
44 unsigned* mulPtr,
45#endif // SCALED_ADDR_MODES
46 ssize_t* cnsPtr);
47
48private:
49#if defined(_TARGET_XARCH_)
50 // Bit masks used in negating a float or double number.
51 // This is to avoid creating more than one data constant for these bitmasks when a
52 // method has more than one GT_NEG operation on floating point values.
53 CORINFO_FIELD_HANDLE negBitmaskFlt;
54 CORINFO_FIELD_HANDLE negBitmaskDbl;
55
56 // Bit masks used in computing Math.Abs() of a float or double number.
57 CORINFO_FIELD_HANDLE absBitmaskFlt;
58 CORINFO_FIELD_HANDLE absBitmaskDbl;
59
60 // Bit mask used in U8 -> double conversion to adjust the result.
61 CORINFO_FIELD_HANDLE u8ToDblBitmask;
62
63 // Generates SSE2 code for the given tree as "Operand BitWiseOp BitMask"
64 void genSSE2BitwiseOp(GenTree* treeNode);
65
66 // Generates SSE41 code for the given tree as a round operation
67 void genSSE41RoundOp(GenTreeOp* treeNode);
68#endif // defined(_TARGET_XARCH_)
69
70 void genPrepForCompiler();
71
72 void genPrepForEHCodegen();
73
74 inline RegState* regStateForType(var_types t)
75 {
76 return varTypeIsFloating(t) ? &floatRegState : &intRegState;
77 }
78 inline RegState* regStateForReg(regNumber reg)
79 {
80 return genIsValidFloatReg(reg) ? &floatRegState : &intRegState;
81 }
82
83 regNumber genFramePointerReg()
84 {
85 if (isFramePointerUsed())
86 {
87 return REG_FPBASE;
88 }
89 else
90 {
91 return REG_SPBASE;
92 }
93 }
94
95 enum CompareKind
96 {
97 CK_SIGNED,
98 CK_UNSIGNED,
99 CK_LOGICAL
100 };
101 static emitJumpKind genJumpKindForOper(genTreeOps cmp, CompareKind compareKind);
102
103 // For a given compare oper tree, returns the conditions to use with jmp/set in 'jmpKind' array.
104 // The corresponding elements of jmpToTrueLabel indicate whether the target of the jump is to the
105 // 'true' label or a 'false' label.
106 //
107 // 'true' label corresponds to jump target of the current basic block i.e. the target to
108 // branch to on compare condition being true. 'false' label corresponds to the target to
109 // branch to on condition being false.
110 static void genJumpKindsForTree(GenTree* cmpTree, emitJumpKind jmpKind[2], bool jmpToTrueLabel[2]);
111
112 static bool genShouldRoundFP();
113
114 GenTreeIndir indirForm(var_types type, GenTree* base);
115
116 GenTreeIntCon intForm(var_types type, ssize_t value);
117
118 void genRangeCheck(GenTree* node);
119
120 void genLockedInstructions(GenTreeOp* node);
121#ifdef _TARGET_XARCH_
122 void genCodeForLockAdd(GenTreeOp* node);
123#endif
124
125#ifdef REG_OPT_RSVD
126 // On some targets such as the ARM we may need to have an extra reserved register
127 // that is used when addressing stack based locals and stack based temps.
128 // This method returns the regNumber that should be used when an extra register
129 // is needed to access the stack based locals and stack based temps.
130 //
131 regNumber rsGetRsvdReg()
132 {
133 // We should have already added this register to the mask
134 // of reserved registers in regSet.rdMaskResvd
135 noway_assert((regSet.rsMaskResvd & RBM_OPT_RSVD) != 0);
136
137 return REG_OPT_RSVD;
138 }
139#endif // REG_OPT_RSVD
140
141 //-------------------------------------------------------------------------
142
143 bool genUseBlockInit; // true if we plan to block-initialize the local stack frame
144 unsigned genInitStkLclCnt; // The count of local variables that we need to zero init
145
146 // Keeps track of how many bytes we've pushed on the processor's stack.
147 //
148 unsigned genStackLevel;
149
150 void SubtractStackLevel(unsigned adjustment)
151 {
152 assert(genStackLevel >= adjustment);
153 unsigned newStackLevel = genStackLevel - adjustment;
154 if (genStackLevel != newStackLevel)
155 {
156 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
157 }
158 genStackLevel = newStackLevel;
159 }
160
161 void AddStackLevel(unsigned adjustment)
162 {
163 unsigned newStackLevel = genStackLevel + adjustment;
164 if (genStackLevel != newStackLevel)
165 {
166 JITDUMP("Adjusting stack level from %d to %d\n", genStackLevel, newStackLevel);
167 }
168 genStackLevel = newStackLevel;
169 }
170
171 void SetStackLevel(unsigned newStackLevel)
172 {
173 if (genStackLevel != newStackLevel)
174 {
175 JITDUMP("Setting stack level from %d to %d\n", genStackLevel, newStackLevel);
176 }
177 genStackLevel = newStackLevel;
178 }
179
180#if STACK_PROBES
181 // Stack Probes
182 bool genNeedPrologStackProbe;
183
184 void genGenerateStackProbe();
185#endif
186
187 //-------------------------------------------------------------------------
188
189 void genReportEH();
190
191 // Allocates storage for the GC info, writes the GC info into that storage, records the address of the
192 // GC info of the method with the EE, and returns a pointer to the "info" portion (just post-header) of
193 // the GC info. Requires "codeSize" to be the size of the generated code, "prologSize" and "epilogSize"
194 // to be the sizes of the prolog and epilog, respectively. In DEBUG, makes a check involving the
195 // "codePtr", assumed to be a pointer to the start of the generated code.
196 CLANG_FORMAT_COMMENT_ANCHOR;
197
198#ifdef JIT32_GCENCODER
199 void* genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
200 void* genCreateAndStoreGCInfoJIT32(unsigned codeSize,
201 unsigned prologSize,
202 unsigned epilogSize DEBUGARG(void* codePtr));
203#else // !JIT32_GCENCODER
204 void genCreateAndStoreGCInfo(unsigned codeSize, unsigned prologSize, unsigned epilogSize DEBUGARG(void* codePtr));
205 void genCreateAndStoreGCInfoX64(unsigned codeSize, unsigned prologSize DEBUGARG(void* codePtr));
206#endif // !JIT32_GCENCODER
207
208 /**************************************************************************
209 * PROTECTED
210 *************************************************************************/
211
212protected:
213 // the current (pending) label ref, a label which has been referenced but not yet seen
214 BasicBlock* genPendingCallLabel;
215
216#ifdef DEBUG
217 // Last instr we have displayed for dspInstrs
218 unsigned genCurDispOffset;
219
220 static const char* genInsName(instruction ins);
221#endif // DEBUG
222
223 //-------------------------------------------------------------------------
224
225 // JIT-time constants for use in multi-dimensional array code generation.
226 unsigned genOffsetOfMDArrayLowerBound(var_types elemType, unsigned rank, unsigned dimension);
227 unsigned genOffsetOfMDArrayDimensionSize(var_types elemType, unsigned rank, unsigned dimension);
228
229#ifdef DEBUG
230 static const char* genSizeStr(emitAttr size);
231#endif // DEBUG
232
233 void genCodeForBBlist();
234
235public:
236 void genSpillVar(GenTree* tree);
237
238protected:
239 void genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize, regNumber callTarget = REG_NA);
240
241 void genGCWriteBarrier(GenTree* tgt, GCInfo::WriteBarrierForm wbf);
242
243 BasicBlock* genCreateTempLabel();
244
245 void genDefineTempLabel(BasicBlock* label);
246
247 void genAdjustSP(target_ssize_t delta);
248
249 void genAdjustStackLevel(BasicBlock* block);
250
251 void genExitCode(BasicBlock* block);
252
253 void genJumpToThrowHlpBlk(emitJumpKind jumpKind, SpecialCodeKind codeKind, GenTree* failBlk = nullptr);
254
255 void genCheckOverflow(GenTree* tree);
256
257 //-------------------------------------------------------------------------
258 //
259 // Prolog/epilog generation
260 //
261 //-------------------------------------------------------------------------
262
263 //
264 // Prolog functions and data (there are a few exceptions for more generally used things)
265 //
266
267 void genEstablishFramePointer(int delta, bool reportUnwindData);
268 void genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbered, RegState* regState);
269 void genEnregisterIncomingStackArgs();
270 void genCheckUseBlockInit();
271#if defined(UNIX_AMD64_ABI) && defined(FEATURE_SIMD)
272 void genClearStackVec3ArgUpperBits();
273#endif // UNIX_AMD64_ABI && FEATURE_SIMD
274
275#if defined(_TARGET_ARM64_)
276 bool genInstrWithConstant(instruction ins,
277 emitAttr attr,
278 regNumber reg1,
279 regNumber reg2,
280 ssize_t imm,
281 regNumber tmpReg,
282 bool inUnwindRegion = false);
283
284 void genStackPointerAdjustment(ssize_t spAdjustment, regNumber tmpReg, bool* pTmpRegIsZero);
285
286 void genPrologSaveRegPair(regNumber reg1,
287 regNumber reg2,
288 int spOffset,
289 int spDelta,
290 bool lastSavedWasPreviousPair,
291 regNumber tmpReg,
292 bool* pTmpRegIsZero);
293
294 void genPrologSaveReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
295
296 void genEpilogRestoreRegPair(
297 regNumber reg1, regNumber reg2, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
298
299 void genEpilogRestoreReg(regNumber reg1, int spOffset, int spDelta, regNumber tmpReg, bool* pTmpRegIsZero);
300
301#ifdef DEBUG
302 static void genCheckSPOffset(bool isRegsCountOdd, int spOffset, int slotSize);
303#endif // DEBUG
304
305 // A simple struct to keep register pairs for prolog and epilog.
306 struct RegPair
307 {
308 regNumber reg1;
309 regNumber reg2;
310
311 RegPair(regNumber reg1) : reg1(reg1), reg2(REG_NA)
312 {
313 }
314
315 RegPair(regNumber reg1, regNumber reg2) : reg1(reg1), reg2(reg2)
316 {
317 assert(reg2 == REG_NEXT(reg1));
318 }
319 };
320
321 static void genBuildRegPairsStack(regMaskTP regsMask, ArrayStack<RegPair>* regStack);
322
323 static int genGetSlotSizeForRegsInMask(regMaskTP regsMask);
324
325 int genSaveCalleeSavedRegisterGroup(regMaskTP regsMask,
326 int spDelta,
327 int spOffset DEBUGARG(bool isRegsToSaveCountOdd));
328 int genRestoreCalleeSavedRegisterGroup(regMaskTP regsMask,
329 int spDelta,
330 int spOffset DEBUGARG(bool isRegsToRestoreCountOdd));
331
332 void genSaveCalleeSavedRegistersHelp(regMaskTP regsToSaveMask, int lowestCalleeSavedOffset, int spDelta);
333 void genRestoreCalleeSavedRegistersHelp(regMaskTP regsToRestoreMask, int lowestCalleeSavedOffset, int spDelta);
334
335 void genPushCalleeSavedRegisters(regNumber initReg, bool* pInitRegZeroed);
336#else
337 void genPushCalleeSavedRegisters();
338#endif
339
340 void genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pInitRegZeroed, regMaskTP maskArgRegsLiveIn);
341
342#if defined(_TARGET_ARM_)
343
344 void genPushFltRegs(regMaskTP regMask);
345 void genPopFltRegs(regMaskTP regMask);
346 regMaskTP genStackAllocRegisterMask(unsigned frameSize, regMaskTP maskCalleeSavedFloat);
347
348 regMaskTP genJmpCallArgMask();
349
350 void genFreeLclFrame(unsigned frameSize,
351 /* IN OUT */ bool* pUnwindStarted,
352 bool jmpEpilog);
353
354 void genMov32RelocatableDisplacement(BasicBlock* block, regNumber reg);
355 void genMov32RelocatableDataLabel(unsigned value, regNumber reg);
356 void genMov32RelocatableImmediate(emitAttr size, BYTE* addr, regNumber reg);
357
358 bool genUsedPopToReturn; // True if we use the pop into PC to return,
359 // False if we didn't and must branch to LR to return.
360
361 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
362 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
363 // same.
364 struct FuncletFrameInfoDsc
365 {
366 regMaskTP fiSaveRegs; // Set of registers saved in the funclet prolog (includes LR)
367 unsigned fiFunctionCallerSPtoFPdelta; // Delta between caller SP and the frame pointer
368 unsigned fiSpDelta; // Stack pointer delta
369 unsigned fiPSP_slot_SP_offset; // PSP slot offset from SP
370 int fiPSP_slot_CallerSP_offset; // PSP slot offset from Caller SP
371 };
372
373 FuncletFrameInfoDsc genFuncletInfo;
374
375#elif defined(_TARGET_ARM64_)
376
377 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
378 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
379 // same.
380 struct FuncletFrameInfoDsc
381 {
382 regMaskTP fiSaveRegs; // Set of callee-saved registers saved in the funclet prolog (includes LR)
383 int fiFunction_CallerSP_to_FP_delta; // Delta between caller SP and the frame pointer in the parent function
384 // (negative)
385 int fiSP_to_FPLR_save_delta; // FP/LR register save offset from SP (positive)
386 int fiSP_to_PSP_slot_delta; // PSP slot offset from SP (positive)
387 int fiSP_to_CalleeSave_delta; // First callee-saved register slot offset from SP (positive)
388 int fiCallerSP_to_PSP_slot_delta; // PSP slot offset from Caller SP (negative)
389 int fiFrameType; // Funclet frame types are numbered. See genFuncletProlog() for details.
390 int fiSpDelta1; // Stack pointer delta 1 (negative)
391 int fiSpDelta2; // Stack pointer delta 2 (negative)
392 };
393
394 FuncletFrameInfoDsc genFuncletInfo;
395
396#elif defined(_TARGET_AMD64_)
397
398 // A set of information that is used by funclet prolog and epilog generation. It is collected once, before
399 // funclet prologs and epilogs are generated, and used by all funclet prologs and epilogs, which must all be the
400 // same.
401 struct FuncletFrameInfoDsc
402 {
403 unsigned fiFunction_InitialSP_to_FP_delta; // Delta between Initial-SP and the frame pointer
404 unsigned fiSpDelta; // Stack pointer delta
405 int fiPSP_slot_InitialSP_offset; // PSP slot offset from Initial-SP
406 };
407
408 FuncletFrameInfoDsc genFuncletInfo;
409
410#endif // _TARGET_AMD64_
411
412#if defined(_TARGET_XARCH_)
413
414 // Save/Restore callee saved float regs to stack
415 void genPreserveCalleeSavedFltRegs(unsigned lclFrameSize);
416 void genRestoreCalleeSavedFltRegs(unsigned lclFrameSize);
417 // Generate VZeroupper instruction to avoid AVX/SSE transition penalty
418 void genVzeroupperIfNeeded(bool check256bitOnly = true);
419
420#endif // _TARGET_XARCH_
421
422 void genZeroInitFltRegs(const regMaskTP& initFltRegs, const regMaskTP& initDblRegs, const regNumber& initReg);
423
424 regNumber genGetZeroReg(regNumber initReg, bool* pInitRegZeroed);
425
426 void genZeroInitFrame(int untrLclHi, int untrLclLo, regNumber initReg, bool* pInitRegZeroed);
427
428 void genReportGenericContextArg(regNumber initReg, bool* pInitRegZeroed);
429
430 void genSetGSSecurityCookie(regNumber initReg, bool* pInitRegZeroed);
431
432 void genFinalizeFrame();
433
434#ifdef PROFILING_SUPPORTED
435 void genProfilingEnterCallback(regNumber initReg, bool* pInitRegZeroed);
436 void genProfilingLeaveCallback(unsigned helper = CORINFO_HELP_PROF_FCN_LEAVE);
437#endif // PROFILING_SUPPORTED
438
439 void genPrologPadForReJit();
440
441 // clang-format off
442 void genEmitCall(int callType,
443 CORINFO_METHOD_HANDLE methHnd,
444 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
445 void* addr
446 X86_ARG(int argSize),
447 emitAttr retSize
448 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
449 IL_OFFSETX ilOffset,
450 regNumber base = REG_NA,
451 bool isJump = false);
452 // clang-format on
453
454 // clang-format off
455 void genEmitCall(int callType,
456 CORINFO_METHOD_HANDLE methHnd,
457 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
458 GenTreeIndir* indir
459 X86_ARG(int argSize),
460 emitAttr retSize
461 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
462 IL_OFFSETX ilOffset);
463 // clang-format on
464
465 //
466 // Epilog functions
467 //
468 CLANG_FORMAT_COMMENT_ANCHOR;
469
470#if defined(_TARGET_ARM_)
471 bool genCanUsePopToReturn(regMaskTP maskPopRegsInt, bool jmpEpilog);
472#endif
473
474#if defined(_TARGET_ARM64_)
475
476 void genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog);
477
478#else // !defined(_TARGET_ARM64_)
479
480 void genPopCalleeSavedRegisters(bool jmpEpilog = false);
481
482#endif // !defined(_TARGET_ARM64_)
483
484 //
485 // Common or driving functions
486 //
487
488 void genReserveProlog(BasicBlock* block); // currently unused
489 void genReserveEpilog(BasicBlock* block);
490 void genFnProlog();
491 void genFnEpilog(BasicBlock* block);
492
493#if FEATURE_EH_FUNCLETS
494
495 void genReserveFuncletProlog(BasicBlock* block);
496 void genReserveFuncletEpilog(BasicBlock* block);
497 void genFuncletProlog(BasicBlock* block);
498 void genFuncletEpilog();
499 void genCaptureFuncletPrologEpilogInfo();
500
501 void genSetPSPSym(regNumber initReg, bool* pInitRegZeroed);
502
503 void genUpdateCurrentFunclet(BasicBlock* block);
504#if defined(_TARGET_ARM_)
505 void genInsertNopForUnwinder(BasicBlock* block);
506#endif
507
508#else // FEATURE_EH_FUNCLETS
509
510 // This is a no-op when there are no funclets!
511 void genUpdateCurrentFunclet(BasicBlock* block)
512 {
513 return;
514 }
515
516#if defined(_TARGET_ARM_)
517 void genInsertNopForUnwinder(BasicBlock* block)
518 {
519 return;
520 }
521#endif
522
523#endif // FEATURE_EH_FUNCLETS
524
525 void genGeneratePrologsAndEpilogs();
526
527#if defined(DEBUG) && defined(_TARGET_ARM64_)
528 void genArm64EmitterUnitTests();
529#endif
530
531#if defined(DEBUG) && defined(LATE_DISASM) && defined(_TARGET_AMD64_)
532 void genAmd64EmitterUnitTests();
533#endif
534
535 //-------------------------------------------------------------------------
536 //
537 // End prolog/epilog generation
538 //
539 //-------------------------------------------------------------------------
540
541 void genSinglePush();
542 void genSinglePop();
543 regMaskTP genPushRegs(regMaskTP regs, regMaskTP* byrefRegs, regMaskTP* noRefRegs);
544 void genPopRegs(regMaskTP regs, regMaskTP byrefRegs, regMaskTP noRefRegs);
545
546/*
547XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
548XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
549XX XX
550XX Debugging Support XX
551XX XX
552XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
553XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
554*/
555
556#ifdef DEBUG
557 void genIPmappingDisp(unsigned mappingNum, Compiler::IPmappingDsc* ipMapping);
558 void genIPmappingListDisp();
559#endif // DEBUG
560
561 void genIPmappingAdd(IL_OFFSETX offset, bool isLabel);
562 void genIPmappingAddToFront(IL_OFFSETX offset);
563 void genIPmappingGen();
564
565 void genEnsureCodeEmitted(IL_OFFSETX offsx);
566
567 //-------------------------------------------------------------------------
568 // scope info for the variables
569
570 void genSetScopeInfo(unsigned which,
571 UNATIVE_OFFSET startOffs,
572 UNATIVE_OFFSET length,
573 unsigned varNum,
574 unsigned LVnum,
575 bool avail,
576 Compiler::siVarLoc& loc);
577
578 void genSetScopeInfo();
579
580protected:
581 /*
582 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
583 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
584 XX XX
585 XX ScopeInfo XX
586 XX XX
587 XX Keeps track of the scopes during code-generation. XX
588 XX This is used to translate the local-variable debugging information XX
589 XX from IL offsets to native code offsets. XX
590 XX XX
591 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
592 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
593 */
594
595 /*****************************************************************************/
596 /*****************************************************************************
597 * ScopeInfo
598 *
599 * This class is called during code gen at block-boundaries, and when the
600 * set of live variables changes. It keeps track of the scope of the variables
601 * in terms of the native code PC.
602 */
603
604public:
605 void siInit();
606
607 void siBeginBlock(BasicBlock* block);
608
609 void siEndBlock(BasicBlock* block);
610
611 virtual void siUpdate();
612
613 void siCheckVarScope(unsigned varNum, IL_OFFSET offs);
614
615 void siCloseAllOpenScopes();
616
617#ifdef DEBUG
618 void siDispOpenScopes();
619#endif
620
621 /**************************************************************************
622 * PROTECTED
623 *************************************************************************/
624
625protected:
626 struct siScope
627 {
628 emitLocation scStartLoc; // emitter location of start of scope
629 emitLocation scEndLoc; // emitter location of end of scope
630
631 unsigned scVarNum; // index into lvaTable
632 unsigned scLVnum; // 'which' in eeGetLVinfo()
633
634 unsigned scStackLevel; // Only for stk-vars
635 bool scAvailable : 1; // It has a home / Home recycled - TODO-Cleanup: it appears this is unused (always true)
636
637 siScope* scPrev;
638 siScope* scNext;
639 };
640
641 siScope siOpenScopeList, siScopeList, *siOpenScopeLast, *siScopeLast;
642
643 unsigned siScopeCnt;
644
645 VARSET_TP siLastLife; // Life at last call to siUpdate()
646
647 // Tracks the last entry for each tracked register variable
648
649 siScope** siLatestTrackedScopes;
650
651 IL_OFFSET siLastEndOffs; // IL offset of the (exclusive) end of the last block processed
652
653#if FEATURE_EH_FUNCLETS
654 bool siInFuncletRegion; // Have we seen the start of the funclet region?
655#endif // FEATURE_EH_FUNCLETS
656
657 // Functions
658
659 siScope* siNewScope(unsigned LVnum, unsigned varNum);
660
661 void siRemoveFromOpenScopeList(siScope* scope);
662
663 void siEndTrackedScope(unsigned varIndex);
664
665 void siEndScope(unsigned varNum);
666
667 void siEndScope(siScope* scope);
668
669#ifdef DEBUG
670 bool siVerifyLocalVarTab();
671#endif
672
673#ifdef LATE_DISASM
674public:
675 /* virtual */
676 const char* siRegVarName(size_t offs, size_t size, unsigned reg);
677
678 /* virtual */
679 const char* siStackVarName(size_t offs, size_t size, unsigned reg, unsigned stkOffs);
680#endif // LATE_DISASM
681
682public:
683 /*
684 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
685 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
686 XX XX
687 XX PrologScopeInfo XX
688 XX XX
689 XX We need special handling in the prolog block, as the parameter variables XX
690 XX may not be in the same position described by genLclVarTable - they all XX
691 XX start out on the stack XX
692 XX XX
693 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
694 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
695 */
696
697public:
698 void psiBegProlog();
699
700 void psiAdjustStackLevel(unsigned size);
701
702 void psiMoveESPtoEBP();
703
704 void psiMoveToReg(unsigned varNum, regNumber reg = REG_NA, regNumber otherReg = REG_NA);
705
706 void psiMoveToStack(unsigned varNum);
707
708 void psiEndProlog();
709
710 /**************************************************************************
711 * PROTECTED
712 *************************************************************************/
713
714protected:
715 struct psiScope
716 {
717 emitLocation scStartLoc; // emitter location of start of scope
718 emitLocation scEndLoc; // emitter location of end of scope
719
720 unsigned scSlotNum; // index into lclVarTab
721 unsigned scLVnum; // 'which' in eeGetLVinfo()
722
723 bool scRegister;
724
725 union {
726 struct
727 {
728 regNumberSmall scRegNum;
729
730 // Used for:
731 // - "other half" of long var on architectures with 32 bit size registers - x86.
732 // - for System V structs it stores the second register
733 // used to pass a register passed struct.
734 regNumberSmall scOtherReg;
735 } u1;
736
737 struct
738 {
739 regNumberSmall scBaseReg;
740 NATIVE_OFFSET scOffset;
741 } u2;
742 };
743
744 psiScope* scPrev;
745 psiScope* scNext;
746 };
747
748 psiScope psiOpenScopeList, psiScopeList, *psiOpenScopeLast, *psiScopeLast;
749
750 unsigned psiScopeCnt;
751
752 // Implementation Functions
753
754 psiScope* psiNewPrologScope(unsigned LVnum, unsigned slotNum);
755
756 void psiEndPrologScope(psiScope* scope);
757
758 void psSetScopeOffset(psiScope* newScope, LclVarDsc* lclVarDsc1);
759
760/*****************************************************************************
761 * TrnslLocalVarInfo
762 *
763 * This struct holds the LocalVarInfo in terms of the generated native code
764 * after a call to genSetScopeInfo()
765 */
766
767#ifdef DEBUG
768
769 struct TrnslLocalVarInfo
770 {
771 unsigned tlviVarNum;
772 unsigned tlviLVnum;
773 VarName tlviName;
774 UNATIVE_OFFSET tlviStartPC;
775 size_t tlviLength;
776 bool tlviAvailable;
777 Compiler::siVarLoc tlviVarLoc;
778 };
779
780 // Array of scopes of LocalVars in terms of native code
781
782 TrnslLocalVarInfo* genTrnslLocalVarInfo;
783 unsigned genTrnslLocalVarCount;
784#endif
785
786 void genSetRegToConst(regNumber targetReg, var_types targetType, GenTree* tree);
787 void genCodeForTreeNode(GenTree* treeNode);
788 void genCodeForBinary(GenTreeOp* treeNode);
789
790#if defined(_TARGET_X86_)
791 void genCodeForLongUMod(GenTreeOp* node);
792#endif // _TARGET_X86_
793
794 void genCodeForDivMod(GenTreeOp* treeNode);
795 void genCodeForMul(GenTreeOp* treeNode);
796 void genCodeForMulHi(GenTreeOp* treeNode);
797 void genLeaInstruction(GenTreeAddrMode* lea);
798 void genSetRegToCond(regNumber dstReg, GenTree* tree);
799
800#if defined(_TARGET_ARMARCH_)
801 void genScaledAdd(emitAttr attr, regNumber targetReg, regNumber baseReg, regNumber indexReg, int scale);
802#endif // _TARGET_ARMARCH_
803
804#if defined(_TARGET_ARM_)
805 void genCodeForMulLong(GenTreeMultiRegOp* treeNode);
806#endif // _TARGET_ARM_
807
808#if !defined(_TARGET_64BIT_)
809 void genLongToIntCast(GenTree* treeNode);
810#endif
811
812 struct GenIntCastDesc
813 {
814 enum CheckKind
815 {
816 CHECK_NONE,
817 CHECK_SMALL_INT_RANGE,
818 CHECK_POSITIVE,
819#ifdef _TARGET_64BIT_
820 CHECK_UINT_RANGE,
821 CHECK_POSITIVE_INT_RANGE,
822 CHECK_INT_RANGE,
823#endif
824 };
825
826 enum ExtendKind
827 {
828 COPY,
829 ZERO_EXTEND_SMALL_INT,
830 SIGN_EXTEND_SMALL_INT,
831#ifdef _TARGET_64BIT_
832 ZERO_EXTEND_INT,
833 SIGN_EXTEND_INT,
834#endif
835 };
836
837 private:
838 CheckKind m_checkKind;
839 unsigned m_checkSrcSize;
840 int m_checkSmallIntMin;
841 int m_checkSmallIntMax;
842 ExtendKind m_extendKind;
843 unsigned m_extendSrcSize;
844
845 public:
846 GenIntCastDesc(GenTreeCast* cast);
847
848 CheckKind CheckKind() const
849 {
850 return m_checkKind;
851 }
852
853 unsigned CheckSrcSize() const
854 {
855 assert(m_checkKind != CHECK_NONE);
856 return m_checkSrcSize;
857 }
858
859 int CheckSmallIntMin() const
860 {
861 assert(m_checkKind == CHECK_SMALL_INT_RANGE);
862 return m_checkSmallIntMin;
863 }
864
865 int CheckSmallIntMax() const
866 {
867 assert(m_checkKind == CHECK_SMALL_INT_RANGE);
868 return m_checkSmallIntMax;
869 }
870
871 ExtendKind ExtendKind() const
872 {
873 return m_extendKind;
874 }
875
876 unsigned ExtendSrcSize() const
877 {
878 return m_extendSrcSize;
879 }
880 };
881
882 void genIntCastOverflowCheck(GenTreeCast* cast, const GenIntCastDesc& desc, regNumber reg);
883 void genIntToIntCast(GenTreeCast* cast);
884 void genFloatToFloatCast(GenTree* treeNode);
885 void genFloatToIntCast(GenTree* treeNode);
886 void genIntToFloatCast(GenTree* treeNode);
887 void genCkfinite(GenTree* treeNode);
888 void genCodeForCompare(GenTreeOp* tree);
889 void genIntrinsic(GenTree* treeNode);
890 void genPutArgStk(GenTreePutArgStk* treeNode);
891 void genPutArgReg(GenTreeOp* tree);
892#if FEATURE_ARG_SPLIT
893 void genPutArgSplit(GenTreePutArgSplit* treeNode);
894#endif // FEATURE_ARG_SPLIT
895
896#if defined(_TARGET_XARCH_)
897 unsigned getBaseVarForPutArgStk(GenTree* treeNode);
898#endif // _TARGET_XARCH_
899
900 unsigned getFirstArgWithStackSlot();
901
902 void genCompareFloat(GenTree* treeNode);
903 void genCompareInt(GenTree* treeNode);
904
905#ifdef FEATURE_SIMD
906 enum SIMDScalarMoveType{
907 SMT_ZeroInitUpper, // zero initlaize target upper bits
908 SMT_ZeroInitUpper_SrcHasUpperZeros, // zero initialize target upper bits; source upper bits are known to be zero
909 SMT_PreserveUpper // preserve target upper bits
910 };
911
912#ifdef _TARGET_ARM64_
913 insOpts genGetSimdInsOpt(emitAttr size, var_types elementType);
914#endif
915 instruction getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival = nullptr);
916 void genSIMDScalarMove(
917 var_types targetType, var_types type, regNumber target, regNumber src, SIMDScalarMoveType moveType);
918 void genSIMDZero(var_types targetType, var_types baseType, regNumber targetReg);
919 void genSIMDIntrinsicInit(GenTreeSIMD* simdNode);
920 void genSIMDIntrinsicInitN(GenTreeSIMD* simdNode);
921 void genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode);
922 void genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode);
923 void genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode);
924 void genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode);
925 void genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode);
926 void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
927 void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
928 void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
929 void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
930 void genSIMDLo64BitConvert(SIMDIntrinsicID intrinsicID,
931 var_types simdType,
932 var_types baseType,
933 regNumber tmpReg,
934 regNumber tmpIntReg,
935 regNumber targetReg);
936 void genSIMDIntrinsic32BitConvert(GenTreeSIMD* simdNode);
937 void genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode);
938 void genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode);
939 void genSIMDExtractUpperHalf(GenTreeSIMD* simdNode, regNumber srcReg, regNumber tgtReg);
940 void genSIMDIntrinsicWiden(GenTreeSIMD* simdNode);
941 void genSIMDIntrinsic(GenTreeSIMD* simdNode);
942
943 // TYP_SIMD12 (i.e Vector3 of size 12 bytes) is not a hardware supported size and requires
944 // two reads/writes on 64-bit targets. These routines abstract reading/writing of Vector3
945 // values through an indirection. Note that Vector3 locals allocated on stack would have
946 // their size rounded to TARGET_POINTER_SIZE (which is 8 bytes on 64-bit targets) and hence
947 // Vector3 locals could be treated as TYP_SIMD16 while reading/writing.
948 void genStoreIndTypeSIMD12(GenTree* treeNode);
949 void genLoadIndTypeSIMD12(GenTree* treeNode);
950 void genStoreLclTypeSIMD12(GenTree* treeNode);
951 void genLoadLclTypeSIMD12(GenTree* treeNode);
952#ifdef _TARGET_X86_
953 void genStoreSIMD12ToStack(regNumber operandReg, regNumber tmpReg);
954 void genPutArgStkSIMD12(GenTree* treeNode);
955#endif // _TARGET_X86_
956#endif // FEATURE_SIMD
957
958#ifdef FEATURE_HW_INTRINSICS
959 void genHWIntrinsic(GenTreeHWIntrinsic* node);
960#if defined(_TARGET_XARCH_)
961 void genHWIntrinsic_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
962 void genHWIntrinsic_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
963 void genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins, emitAttr attr);
964 void genHWIntrinsic_R_R_RM(
965 GenTreeHWIntrinsic* node, instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, GenTree* op2);
966 void genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins, int8_t ival);
967 void genHWIntrinsic_R_R_RM_R(GenTreeHWIntrinsic* node, instruction ins);
968 void genHWIntrinsic_R_R_R_RM(
969 instruction ins, emitAttr attr, regNumber targetReg, regNumber op1Reg, regNumber op2Reg, GenTree* op3);
970 void genBaseIntrinsic(GenTreeHWIntrinsic* node);
971 void genSSEIntrinsic(GenTreeHWIntrinsic* node);
972 void genSSE2Intrinsic(GenTreeHWIntrinsic* node);
973 void genSSE41Intrinsic(GenTreeHWIntrinsic* node);
974 void genSSE42Intrinsic(GenTreeHWIntrinsic* node);
975 void genAvxOrAvx2Intrinsic(GenTreeHWIntrinsic* node);
976 void genAESIntrinsic(GenTreeHWIntrinsic* node);
977 void genBMI1OrBMI2Intrinsic(GenTreeHWIntrinsic* node);
978 void genFMAIntrinsic(GenTreeHWIntrinsic* node);
979 void genLZCNTIntrinsic(GenTreeHWIntrinsic* node);
980 void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node);
981 void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node);
982 void genXCNTIntrinsic(GenTreeHWIntrinsic* node, instruction ins);
983 template <typename HWIntrinsicSwitchCaseBody>
984 void genHWIntrinsicJumpTableFallback(NamedIntrinsic intrinsic,
985 regNumber nonConstImmReg,
986 regNumber baseReg,
987 regNumber offsReg,
988 HWIntrinsicSwitchCaseBody emitSwCase);
989#endif // defined(_TARGET_XARCH_)
990#if defined(_TARGET_ARM64_)
991 instruction getOpForHWIntrinsic(GenTreeHWIntrinsic* node, var_types instrType);
992 void genHWIntrinsicUnaryOp(GenTreeHWIntrinsic* node);
993 void genHWIntrinsicCrcOp(GenTreeHWIntrinsic* node);
994 void genHWIntrinsicSimdBinaryOp(GenTreeHWIntrinsic* node);
995 void genHWIntrinsicSimdExtractOp(GenTreeHWIntrinsic* node);
996 void genHWIntrinsicSimdInsertOp(GenTreeHWIntrinsic* node);
997 void genHWIntrinsicSimdSelectOp(GenTreeHWIntrinsic* node);
998 void genHWIntrinsicSimdSetAllOp(GenTreeHWIntrinsic* node);
999 void genHWIntrinsicSimdUnaryOp(GenTreeHWIntrinsic* node);
1000 void genHWIntrinsicSimdBinaryRMWOp(GenTreeHWIntrinsic* node);
1001 void genHWIntrinsicSimdTernaryRMWOp(GenTreeHWIntrinsic* node);
1002 void genHWIntrinsicShaHashOp(GenTreeHWIntrinsic* node);
1003 void genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node);
1004 template <typename HWIntrinsicSwitchCaseBody>
1005 void genHWIntrinsicSwitchTable(regNumber swReg, regNumber tmpReg, int swMax, HWIntrinsicSwitchCaseBody emitSwCase);
1006#endif // defined(_TARGET_XARCH_)
1007#endif // FEATURE_HW_INTRINSICS
1008
1009#if !defined(_TARGET_64BIT_)
1010
1011 // CodeGen for Long Ints
1012
1013 void genStoreLongLclVar(GenTree* treeNode);
1014
1015#endif // !defined(_TARGET_64BIT_)
1016
1017 void genProduceReg(GenTree* tree);
1018 void genUnspillRegIfNeeded(GenTree* tree);
1019 regNumber genConsumeReg(GenTree* tree);
1020 void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
1021 void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
1022
1023 void genConsumeIfReg(GenTree* tree)
1024 {
1025 if (!tree->isContained())
1026 {
1027 (void)genConsumeReg(tree);
1028 }
1029 }
1030
1031 void genRegCopy(GenTree* tree);
1032 void genTransferRegGCState(regNumber dst, regNumber src);
1033 void genConsumeAddress(GenTree* addr);
1034 void genConsumeAddrMode(GenTreeAddrMode* mode);
1035 void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
1036 void genConsumeBlockSrc(GenTreeBlk* blkNode);
1037 void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
1038 void genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg);
1039
1040#ifdef FEATURE_PUT_STRUCT_ARG_STK
1041 void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode,
1042 regNumber dstReg,
1043 regNumber srcReg,
1044 regNumber sizeReg);
1045#endif // FEATURE_PUT_STRUCT_ARG_STK
1046#if FEATURE_ARG_SPLIT
1047 void genConsumeArgSplitStruct(GenTreePutArgSplit* putArgNode);
1048#endif // FEATURE_ARG_SPLIT
1049
1050 void genConsumeRegs(GenTree* tree);
1051 void genConsumeOperands(GenTreeOp* tree);
1052 void genEmitGSCookieCheck(bool pushReg);
1053 void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
1054 void genCodeForShift(GenTree* tree);
1055
1056#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
1057 void genCodeForShiftLong(GenTree* tree);
1058#endif
1059
1060#ifdef _TARGET_XARCH_
1061 void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
1062 void genCodeForBT(GenTreeOp* bt);
1063#endif // _TARGET_XARCH_
1064
1065 void genCodeForCast(GenTreeOp* tree);
1066 void genCodeForLclAddr(GenTree* tree);
1067 void genCodeForIndexAddr(GenTreeIndexAddr* tree);
1068 void genCodeForIndir(GenTreeIndir* tree);
1069 void genCodeForNegNot(GenTree* tree);
1070 void genCodeForBswap(GenTree* tree);
1071 void genCodeForLclVar(GenTreeLclVar* tree);
1072 void genCodeForLclFld(GenTreeLclFld* tree);
1073 void genCodeForStoreLclFld(GenTreeLclFld* tree);
1074 void genCodeForStoreLclVar(GenTreeLclVar* tree);
1075 void genCodeForReturnTrap(GenTreeOp* tree);
1076 void genCodeForJcc(GenTreeCC* tree);
1077 void genCodeForSetcc(GenTreeCC* setcc);
1078 void genCodeForStoreInd(GenTreeStoreInd* tree);
1079 void genCodeForSwap(GenTreeOp* tree);
1080 void genCodeForCpObj(GenTreeObj* cpObjNode);
1081 void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
1082 void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
1083 void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
1084 void genCodeForPhysReg(GenTreePhysReg* tree);
1085 void genCodeForNullCheck(GenTreeOp* tree);
1086 void genCodeForCmpXchg(GenTreeCmpXchg* tree);
1087
1088 void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
1089 void genAlignStackBeforeCall(GenTreeCall* call);
1090 void genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias = 0);
1091
1092#if defined(UNIX_X86_ABI)
1093
1094 unsigned curNestedAlignment; // Keep track of alignment adjustment required during codegen.
1095 unsigned maxNestedAlignment; // The maximum amount of alignment adjustment required.
1096
1097 void SubtractNestedAlignment(unsigned adjustment)
1098 {
1099 assert(curNestedAlignment >= adjustment);
1100 unsigned newNestedAlignment = curNestedAlignment - adjustment;
1101 if (curNestedAlignment != newNestedAlignment)
1102 {
1103 JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1104 }
1105 curNestedAlignment = newNestedAlignment;
1106 }
1107
1108 void AddNestedAlignment(unsigned adjustment)
1109 {
1110 unsigned newNestedAlignment = curNestedAlignment + adjustment;
1111 if (curNestedAlignment != newNestedAlignment)
1112 {
1113 JITDUMP("Adjusting stack nested alignment from %d to %d\n", curNestedAlignment, newNestedAlignment);
1114 }
1115 curNestedAlignment = newNestedAlignment;
1116
1117 if (curNestedAlignment > maxNestedAlignment)
1118 {
1119 JITDUMP("Max stack nested alignment changed from %d to %d\n", maxNestedAlignment, curNestedAlignment);
1120 maxNestedAlignment = curNestedAlignment;
1121 }
1122 }
1123
1124#endif
1125
1126#ifndef _TARGET_X86_
1127 void genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArgVarNum);
1128#endif // !_TARGET_X86_
1129
1130#ifdef FEATURE_PUT_STRUCT_ARG_STK
1131#ifdef _TARGET_X86_
1132 bool genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk);
1133 void genPushReg(var_types type, regNumber srcReg);
1134 void genPutArgStkFieldList(GenTreePutArgStk* putArgStk);
1135#endif // _TARGET_X86_
1136
1137 void genPutStructArgStk(GenTreePutArgStk* treeNode);
1138
1139 unsigned genMove8IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1140 unsigned genMove4IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1141 unsigned genMove2IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1142 unsigned genMove1IfNeeded(unsigned size, regNumber tmpReg, GenTree* srcAddr, unsigned offset);
1143 void genStructPutArgRepMovs(GenTreePutArgStk* putArgStkNode);
1144 void genStructPutArgUnroll(GenTreePutArgStk* putArgStkNode);
1145 void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
1146#endif // FEATURE_PUT_STRUCT_ARG_STK
1147
1148 void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
1149 void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
1150
1151#ifdef _TARGET_ARM64_
1152 void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
1153 void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
1154#endif // _TARGET_ARM64_
1155
1156 void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
1157 void genCodeForInitBlk(GenTreeBlk* initBlkNode);
1158 void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
1159 void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
1160 void genJumpTable(GenTree* tree);
1161 void genTableBasedSwitch(GenTree* tree);
1162 void genCodeForArrIndex(GenTreeArrIndex* treeNode);
1163 void genCodeForArrOffset(GenTreeArrOffs* treeNode);
1164 instruction genGetInsForOper(genTreeOps oper, var_types type);
1165 bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
1166 void genCallInstruction(GenTreeCall* call);
1167 void genJmpMethod(GenTree* jmp);
1168 BasicBlock* genCallFinally(BasicBlock* block);
1169 void genCodeForJumpTrue(GenTree* tree);
1170#ifdef _TARGET_ARM64_
1171 void genCodeForJumpCompare(GenTreeOp* tree);
1172#endif // _TARGET_ARM64_
1173
1174#if FEATURE_EH_FUNCLETS
1175 void genEHCatchRet(BasicBlock* block);
1176#else // !FEATURE_EH_FUNCLETS
1177 void genEHFinallyOrFilterRet(BasicBlock* block);
1178#endif // !FEATURE_EH_FUNCLETS
1179
1180 void genMultiRegCallStoreToLocal(GenTree* treeNode);
1181
1182 // Deals with codegen for muti-register struct returns.
1183 bool isStructReturn(GenTree* treeNode);
1184 void genStructReturn(GenTree* treeNode);
1185
1186#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
1187 void genLongReturn(GenTree* treeNode);
1188#endif // _TARGET_X86_ || _TARGET_ARM_
1189
1190#if defined(_TARGET_X86_)
1191 void genFloatReturn(GenTree* treeNode);
1192#endif // _TARGET_X86_
1193
1194#if defined(_TARGET_ARM64_)
1195 void genSimpleReturn(GenTree* treeNode);
1196#endif // _TARGET_ARM64_
1197
1198 void genReturn(GenTree* treeNode);
1199
1200 void genLclHeap(GenTree* tree);
1201
1202 bool genIsRegCandidateLocal(GenTree* tree)
1203 {
1204 if (!tree->IsLocal())
1205 {
1206 return false;
1207 }
1208 const LclVarDsc* varDsc = &compiler->lvaTable[tree->gtLclVarCommon.gtLclNum];
1209 return (varDsc->lvIsRegCandidate());
1210 }
1211
1212#ifdef FEATURE_PUT_STRUCT_ARG_STK
1213#ifdef _TARGET_X86_
1214 bool m_pushStkArg;
1215#else // !_TARGET_X86_
1216 unsigned m_stkArgVarNum;
1217 unsigned m_stkArgOffset;
1218#endif // !_TARGET_X86_
1219#endif // !FEATURE_PUT_STRUCT_ARG_STK
1220
1221#if defined(DEBUG) && defined(_TARGET_XARCH_)
1222 void genStackPointerCheck(bool doStackPointerCheck, unsigned lvaStackPointerVar);
1223#endif // defined(DEBUG) && defined(_TARGET_XARCH_)
1224
1225#ifdef DEBUG
1226 GenTree* lastConsumedNode;
1227 void genNumberOperandUse(GenTree* const operand, int& useNum) const;
1228 void genCheckConsumeNode(GenTree* const node);
1229#else // !DEBUG
1230 inline void genCheckConsumeNode(GenTree* treeNode)
1231 {
1232 }
1233#endif // DEBUG
1234
1235 /*
1236 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1237 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1238 XX XX
1239 XX Instruction XX
1240 XX XX
1241 XX The interface to generate a machine-instruction. XX
1242 XX Currently specific to x86 XX
1243 XX TODO-Cleanup: Consider factoring this out of CodeGen XX
1244 XX XX
1245 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1246 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1247 */
1248
1249public:
1250 void instInit();
1251
1252 void instGen(instruction ins);
1253#ifdef _TARGET_XARCH_
1254 void instNop(unsigned size);
1255#endif
1256
1257 void inst_JMP(emitJumpKind jmp, BasicBlock* tgtBlock);
1258
1259 void inst_SET(emitJumpKind condition, regNumber reg);
1260
1261 void inst_RV(instruction ins, regNumber reg, var_types type, emitAttr size = EA_UNKNOWN);
1262
1263 void inst_RV_RV(instruction ins,
1264 regNumber reg1,
1265 regNumber reg2,
1266 var_types type = TYP_I_IMPL,
1267 emitAttr size = EA_UNKNOWN,
1268 insFlags flags = INS_FLAGS_DONT_CARE);
1269
1270 void inst_RV_RV_RV(instruction ins,
1271 regNumber reg1,
1272 regNumber reg2,
1273 regNumber reg3,
1274 emitAttr size,
1275 insFlags flags = INS_FLAGS_DONT_CARE);
1276
1277 void inst_IV(instruction ins, int val);
1278 void inst_IV_handle(instruction ins, int val);
1279
1280 void inst_RV_IV(
1281 instruction ins, regNumber reg, target_ssize_t val, emitAttr size, insFlags flags = INS_FLAGS_DONT_CARE);
1282
1283 void inst_ST_RV(instruction ins, TempDsc* tmp, unsigned ofs, regNumber reg, var_types type);
1284 void inst_ST_IV(instruction ins, TempDsc* tmp, unsigned ofs, int val, var_types type);
1285
1286 void inst_SA_RV(instruction ins, unsigned ofs, regNumber reg, var_types type);
1287 void inst_SA_IV(instruction ins, unsigned ofs, int val, var_types type);
1288
1289 void inst_RV_ST(
1290 instruction ins, regNumber reg, TempDsc* tmp, unsigned ofs, var_types type, emitAttr size = EA_UNKNOWN);
1291 void inst_FS_ST(instruction ins, emitAttr size, TempDsc* tmp, unsigned ofs);
1292
1293 void inst_TT(instruction ins, GenTree* tree, unsigned offs = 0, int shfv = 0, emitAttr size = EA_UNKNOWN);
1294
1295 void inst_TT_RV(instruction ins,
1296 GenTree* tree,
1297 regNumber reg,
1298 unsigned offs = 0,
1299 emitAttr size = EA_UNKNOWN,
1300 insFlags flags = INS_FLAGS_DONT_CARE);
1301
1302 void inst_RV_TT(instruction ins,
1303 regNumber reg,
1304 GenTree* tree,
1305 unsigned offs = 0,
1306 emitAttr size = EA_UNKNOWN,
1307 insFlags flags = INS_FLAGS_DONT_CARE);
1308
1309 void inst_FS_TT(instruction ins, GenTree* tree);
1310
1311 void inst_RV_SH(instruction ins, emitAttr size, regNumber reg, unsigned val, insFlags flags = INS_FLAGS_DONT_CARE);
1312
1313 void inst_TT_SH(instruction ins, GenTree* tree, unsigned val, unsigned offs = 0);
1314
1315 void inst_RV_CL(instruction ins, regNumber reg, var_types type = TYP_I_IMPL);
1316
1317 void inst_TT_CL(instruction ins, GenTree* tree, unsigned offs = 0);
1318
1319#if defined(_TARGET_XARCH_)
1320 void inst_RV_RV_IV(instruction ins, emitAttr size, regNumber reg1, regNumber reg2, unsigned ival);
1321#endif
1322
1323 void inst_RV_RR(instruction ins, emitAttr size, regNumber reg1, regNumber reg2);
1324
1325 void inst_RV_ST(instruction ins, emitAttr size, regNumber reg, GenTree* tree);
1326
1327 void inst_mov_RV_ST(regNumber reg, GenTree* tree);
1328
1329 void inst_set_SV_var(GenTree* tree);
1330
1331#ifdef _TARGET_ARM_
1332 bool arm_Valid_Imm_For_Instr(instruction ins, target_ssize_t imm, insFlags flags);
1333 bool arm_Valid_Disp_For_LdSt(target_ssize_t disp, var_types type);
1334 bool arm_Valid_Imm_For_Alu(target_ssize_t imm);
1335 bool arm_Valid_Imm_For_Mov(target_ssize_t imm);
1336 bool arm_Valid_Imm_For_Small_Mov(regNumber reg, target_ssize_t imm, insFlags flags);
1337 bool arm_Valid_Imm_For_Add(target_ssize_t imm, insFlags flag);
1338 bool arm_Valid_Imm_For_Add_SP(target_ssize_t imm);
1339 bool arm_Valid_Imm_For_BL(ssize_t addr);
1340
1341 bool ins_Writes_Dest(instruction ins);
1342#endif
1343
1344 bool isMoveIns(instruction ins);
1345 instruction ins_Move_Extend(var_types srcType, bool srcInReg);
1346
1347 instruction ins_Copy(var_types dstType);
1348 instruction ins_CopyIntToFloat(var_types srcType, var_types dstTyp);
1349 instruction ins_CopyFloatToInt(var_types srcType, var_types dstTyp);
1350 static instruction ins_FloatStore(var_types type = TYP_DOUBLE);
1351 static instruction ins_FloatCopy(var_types type = TYP_DOUBLE);
1352 instruction ins_FloatConv(var_types to, var_types from);
1353 instruction ins_FloatCompare(var_types type);
1354 instruction ins_MathOp(genTreeOps oper, var_types type);
1355 instruction ins_FloatSqrt(var_types type);
1356
1357 void instGen_Return(unsigned stkArgSize);
1358
1359#ifdef _TARGET_ARM64_
1360 void instGen_MemoryBarrier(insBarrier barrierType = INS_BARRIER_ISH);
1361#else
1362 void instGen_MemoryBarrier();
1363#endif
1364
1365 void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);
1366
1367 void instGen_Set_Reg_To_Imm(emitAttr size, regNumber reg, ssize_t imm, insFlags flags = INS_FLAGS_DONT_CARE);
1368
1369 void instGen_Compare_Reg_To_Zero(emitAttr size, regNumber reg);
1370
1371 void instGen_Compare_Reg_To_Reg(emitAttr size, regNumber reg1, regNumber reg2);
1372
1373 void instGen_Compare_Reg_To_Imm(emitAttr size, regNumber reg, target_ssize_t imm);
1374
1375 void instGen_Load_Reg_From_Lcl(var_types srcType, regNumber dstReg, int varNum, int offs);
1376
1377 void instGen_Store_Reg_Into_Lcl(var_types dstType, regNumber srcReg, int varNum, int offs);
1378
1379 void instGen_Store_Imm_Into_Lcl(
1380 var_types dstType, emitAttr sizeAttr, ssize_t imm, int varNum, int offs, regNumber regToUse = REG_NA);
1381
1382#ifdef DEBUG
1383 void __cdecl instDisp(instruction ins, bool noNL, const char* fmt, ...);
1384#endif
1385
1386#ifdef _TARGET_XARCH_
1387 instruction genMapShiftInsToShiftByConstantIns(instruction ins, int shiftByValue);
1388#endif // _TARGET_XARCH_
1389};
1390
1391/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1392XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1393XX XX
1394XX Instruction XX
1395XX Inline functions XX
1396XX XX
1397XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1398XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1399*/
1400
1401#ifdef _TARGET_XARCH_
1402/*****************************************************************************
1403 *
1404 * Generate a floating-point instruction that has one operand given by
1405 * a tree (which has been made addressable).
1406 */
1407
1408inline void CodeGen::inst_FS_TT(instruction ins, GenTree* tree)
1409{
1410 assert(instIsFP(ins));
1411
1412 assert(varTypeIsFloating(tree->gtType));
1413
1414 inst_TT(ins, tree, 0);
1415}
1416#endif
1417
1418/*****************************************************************************
1419 *
1420 * Generate a "shift reg, cl" instruction.
1421 */
1422
1423inline void CodeGen::inst_RV_CL(instruction ins, regNumber reg, var_types type)
1424{
1425 inst_RV(ins, reg, type);
1426}
1427
1428#endif // _CODEGEN_H_
1429