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/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX Code Generation Support Methods for Linear Codegen XX
9XX XX
10XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12*/
13#include "jitpch.h"
14#ifdef _MSC_VER
15#pragma hdrstop
16#endif
17
18#include "emit.h"
19#include "codegen.h"
20
21//------------------------------------------------------------------------
22// genCodeForBBlist: Generate code for all the blocks in a method
23//
24// Arguments:
25// None
26//
27// Notes:
28// This is the main method for linear codegen. It calls genCodeForTreeNode
29// to generate the code for each node in each BasicBlock, and handles BasicBlock
30// boundaries and branches.
31//
32void CodeGen::genCodeForBBlist()
33{
34 unsigned varNum;
35 LclVarDsc* varDsc;
36
37 unsigned savedStkLvl;
38
39#ifdef DEBUG
40 genInterruptibleUsed = true;
41
42 // You have to be careful if you create basic blocks from now on
43 compiler->fgSafeBasicBlockCreation = false;
44#endif // DEBUG
45
46#if defined(DEBUG) && defined(_TARGET_X86_)
47
48 // Check stack pointer on call stress mode is not compatible with fully interruptible GC. REVIEW: why?
49 //
50 if (genInterruptible && compiler->opts.compStackCheckOnCall)
51 {
52 compiler->opts.compStackCheckOnCall = false;
53 }
54
55#endif // defined(DEBUG) && defined(_TARGET_X86_)
56
57#if defined(DEBUG) && defined(_TARGET_XARCH_)
58
59 // Check stack pointer on return stress mode is not compatible with fully interruptible GC. REVIEW: why?
60 // It is also not compatible with any function that makes a tailcall: we aren't smart enough to only
61 // insert the SP check in the non-tailcall returns.
62 //
63 if ((genInterruptible || compiler->compTailCallUsed) && compiler->opts.compStackCheckOnRet)
64 {
65 compiler->opts.compStackCheckOnRet = false;
66 }
67
68#endif // defined(DEBUG) && defined(_TARGET_XARCH_)
69
70 // Prepare the blocks for exception handling codegen: mark the blocks that needs labels.
71 genPrepForEHCodegen();
72
73 assert(!compiler->fgFirstBBScratch ||
74 compiler->fgFirstBB == compiler->fgFirstBBScratch); // compiler->fgFirstBBScratch has to be first.
75
76 /* Initialize the spill tracking logic */
77
78 regSet.rsSpillBeg();
79
80 /* Initialize the line# tracking logic */
81
82 if (compiler->opts.compScopeInfo)
83 {
84 siInit();
85 }
86
87 // The current implementation of switch tables requires the first block to have a label so it
88 // can generate offsets to the switch label targets.
89 // TODO-CQ: remove this when switches have been re-implemented to not use this.
90 if (compiler->fgHasSwitch)
91 {
92 compiler->fgFirstBB->bbFlags |= BBF_JMP_TARGET;
93 }
94
95 genPendingCallLabel = nullptr;
96
97 /* Initialize the pointer tracking code */
98
99 gcInfo.gcRegPtrSetInit();
100 gcInfo.gcVarPtrSetInit();
101
102 /* If any arguments live in registers, mark those regs as such */
103
104 for (varNum = 0, varDsc = compiler->lvaTable; varNum < compiler->lvaCount; varNum++, varDsc++)
105 {
106 /* Is this variable a parameter assigned to a register? */
107
108 if (!varDsc->lvIsParam || !varDsc->lvRegister)
109 {
110 continue;
111 }
112
113 /* Is the argument live on entry to the method? */
114
115 if (!VarSetOps::IsMember(compiler, compiler->fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
116 {
117 continue;
118 }
119
120 /* Is this a floating-point argument? */
121
122 if (varDsc->IsFloatRegType())
123 {
124 continue;
125 }
126
127 noway_assert(!varTypeIsFloating(varDsc->TypeGet()));
128
129 /* Mark the register as holding the variable */
130
131 assert(varDsc->lvRegNum != REG_STK);
132 if (!varDsc->lvAddrExposed)
133 {
134 regSet.verifyRegUsed(varDsc->lvRegNum);
135 }
136 }
137
138 unsigned finallyNesting = 0;
139
140 // Make sure a set is allocated for compiler->compCurLife (in the long case), so we can set it to empty without
141 // allocation at the start of each basic block.
142 VarSetOps::AssignNoCopy(compiler, compiler->compCurLife, VarSetOps::MakeEmpty(compiler));
143
144 /*-------------------------------------------------------------------------
145 *
146 * Walk the basic blocks and generate code for each one
147 *
148 */
149
150 BasicBlock* block;
151
152 for (block = compiler->fgFirstBB; block != nullptr; block = block->bbNext)
153 {
154#ifdef DEBUG
155 if (compiler->verbose)
156 {
157 printf("\n=============== Generating ");
158 block->dspBlockHeader(compiler, true, true);
159 compiler->fgDispBBLiveness(block);
160 }
161#endif // DEBUG
162
163 assert(LIR::AsRange(block).CheckLIR(compiler));
164
165 // Figure out which registers hold variables on entry to this block
166
167 regSet.ClearMaskVars();
168 gcInfo.gcRegGCrefSetCur = RBM_NONE;
169 gcInfo.gcRegByrefSetCur = RBM_NONE;
170
171 compiler->m_pLinearScan->recordVarLocationsAtStartOfBB(block);
172
173 genUpdateLife(block->bbLiveIn);
174
175 // Even if liveness didn't change, we need to update the registers containing GC references.
176 // genUpdateLife will update the registers live due to liveness changes. But what about registers that didn't
177 // change? We cleared them out above. Maybe we should just not clear them out, but update the ones that change
178 // here. That would require handling the changes in recordVarLocationsAtStartOfBB().
179
180 regMaskTP newLiveRegSet = RBM_NONE;
181 regMaskTP newRegGCrefSet = RBM_NONE;
182 regMaskTP newRegByrefSet = RBM_NONE;
183#ifdef DEBUG
184 VARSET_TP removedGCVars(VarSetOps::MakeEmpty(compiler));
185 VARSET_TP addedGCVars(VarSetOps::MakeEmpty(compiler));
186#endif
187 VarSetOps::Iter iter(compiler, block->bbLiveIn);
188 unsigned varIndex = 0;
189 while (iter.NextElem(&varIndex))
190 {
191 unsigned varNum = compiler->lvaTrackedToVarNum[varIndex];
192 LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
193
194 if (varDsc->lvIsInReg())
195 {
196 newLiveRegSet |= varDsc->lvRegMask();
197 if (varDsc->lvType == TYP_REF)
198 {
199 newRegGCrefSet |= varDsc->lvRegMask();
200 }
201 else if (varDsc->lvType == TYP_BYREF)
202 {
203 newRegByrefSet |= varDsc->lvRegMask();
204 }
205#ifdef DEBUG
206 if (verbose && VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varIndex))
207 {
208 VarSetOps::AddElemD(compiler, removedGCVars, varIndex);
209 }
210#endif // DEBUG
211 VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varIndex);
212 }
213 else if (compiler->lvaIsGCTracked(varDsc))
214 {
215#ifdef DEBUG
216 if (verbose && !VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varIndex))
217 {
218 VarSetOps::AddElemD(compiler, addedGCVars, varIndex);
219 }
220#endif // DEBUG
221 VarSetOps::AddElemD(compiler, gcInfo.gcVarPtrSetCur, varIndex);
222 }
223 }
224
225 regSet.rsMaskVars = newLiveRegSet;
226
227#ifdef DEBUG
228 if (compiler->verbose)
229 {
230 if (!VarSetOps::IsEmpty(compiler, addedGCVars))
231 {
232 printf("\t\t\t\t\t\t\tAdded GCVars: ");
233 dumpConvertedVarSet(compiler, addedGCVars);
234 printf("\n");
235 }
236 if (!VarSetOps::IsEmpty(compiler, removedGCVars))
237 {
238 printf("\t\t\t\t\t\t\tRemoved GCVars: ");
239 dumpConvertedVarSet(compiler, removedGCVars);
240 printf("\n");
241 }
242 }
243#endif // DEBUG
244
245 gcInfo.gcMarkRegSetGCref(newRegGCrefSet DEBUGARG(true));
246 gcInfo.gcMarkRegSetByref(newRegByrefSet DEBUGARG(true));
247
248 /* Blocks with handlerGetsXcptnObj()==true use GT_CATCH_ARG to
249 represent the exception object (TYP_REF).
250 We mark REG_EXCEPTION_OBJECT as holding a GC object on entry
251 to the block, it will be the first thing evaluated
252 (thanks to GTF_ORDER_SIDEEFF).
253 */
254
255 if (handlerGetsXcptnObj(block->bbCatchTyp))
256 {
257 for (GenTree* node : LIR::AsRange(block))
258 {
259 if (node->OperGet() == GT_CATCH_ARG)
260 {
261 gcInfo.gcMarkRegSetGCref(RBM_EXCEPTION_OBJECT);
262 break;
263 }
264 }
265 }
266
267#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
268 genInsertNopForUnwinder(block);
269#endif
270
271 /* Start a new code output block */
272
273 genUpdateCurrentFunclet(block);
274
275#ifdef _TARGET_XARCH_
276 if (genAlignLoops && block->bbFlags & BBF_LOOP_HEAD)
277 {
278 getEmitter()->emitLoopAlign();
279 }
280#endif
281
282#ifdef DEBUG
283 if (compiler->opts.dspCode)
284 {
285 printf("\n L_M%03u_" FMT_BB ":\n", Compiler::s_compMethodsCount, block->bbNum);
286 }
287#endif
288
289 block->bbEmitCookie = nullptr;
290
291 if (block->bbFlags & (BBF_JMP_TARGET | BBF_HAS_LABEL))
292 {
293 /* Mark a label and update the current set of live GC refs */
294
295 block->bbEmitCookie = getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
296 gcInfo.gcRegByrefSetCur, FALSE);
297 }
298
299 if (block == compiler->fgFirstColdBlock)
300 {
301#ifdef DEBUG
302 if (compiler->verbose)
303 {
304 printf("\nThis is the start of the cold region of the method\n");
305 }
306#endif
307 // We should never have a block that falls through into the Cold section
308 noway_assert(!block->bbPrev->bbFallsThrough());
309
310 // We require the block that starts the Cold section to have a label
311 noway_assert(block->bbEmitCookie);
312 getEmitter()->emitSetFirstColdIGCookie(block->bbEmitCookie);
313 }
314
315 /* Both stacks are always empty on entry to a basic block */
316
317 SetStackLevel(0);
318 genAdjustStackLevel(block);
319 savedStkLvl = genStackLevel;
320
321 /* Tell everyone which basic block we're working on */
322
323 compiler->compCurBB = block;
324
325 siBeginBlock(block);
326
327 // BBF_INTERNAL blocks don't correspond to any single IL instruction.
328 if (compiler->opts.compDbgInfo && (block->bbFlags & BBF_INTERNAL) &&
329 !compiler->fgBBisScratch(block)) // If the block is the distinguished first scratch block, then no need to
330 // emit a NO_MAPPING entry, immediately after the prolog.
331 {
332 genIPmappingAdd((IL_OFFSETX)ICorDebugInfo::NO_MAPPING, true);
333 }
334
335 bool firstMapping = true;
336
337#if FEATURE_EH_FUNCLETS
338 if (block->bbFlags & BBF_FUNCLET_BEG)
339 {
340 genReserveFuncletProlog(block);
341 }
342#endif // FEATURE_EH_FUNCLETS
343
344 // Clear compCurStmt and compCurLifeTree.
345 compiler->compCurStmt = nullptr;
346 compiler->compCurLifeTree = nullptr;
347
348 // Traverse the block in linear order, generating code for each node as we
349 // as we encounter it.
350 CLANG_FORMAT_COMMENT_ANCHOR;
351
352#ifdef DEBUG
353 // Set the use-order numbers for each node.
354 {
355 int useNum = 0;
356 for (GenTree* node : LIR::AsRange(block).NonPhiNodes())
357 {
358 assert((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) == 0);
359
360 node->gtUseNum = -1;
361 if (node->isContained() || node->IsCopyOrReload())
362 {
363 continue;
364 }
365
366 for (GenTree* operand : node->Operands())
367 {
368 genNumberOperandUse(operand, useNum);
369 }
370 }
371 }
372#endif // DEBUG
373
374 IL_OFFSETX currentILOffset = BAD_IL_OFFSET;
375 for (GenTree* node : LIR::AsRange(block).NonPhiNodes())
376 {
377 // Do we have a new IL offset?
378 if (node->OperGet() == GT_IL_OFFSET)
379 {
380 genEnsureCodeEmitted(currentILOffset);
381 currentILOffset = node->gtStmt.gtStmtILoffsx;
382 genIPmappingAdd(currentILOffset, firstMapping);
383 firstMapping = false;
384 }
385
386#ifdef DEBUG
387 if (node->OperGet() == GT_IL_OFFSET)
388 {
389 noway_assert(node->gtStmt.gtStmtLastILoffs <= compiler->info.compILCodeSize ||
390 node->gtStmt.gtStmtLastILoffs == BAD_IL_OFFSET);
391
392 if (compiler->opts.dspCode && compiler->opts.dspInstrs &&
393 node->gtStmt.gtStmtLastILoffs != BAD_IL_OFFSET)
394 {
395 while (genCurDispOffset <= node->gtStmt.gtStmtLastILoffs)
396 {
397 genCurDispOffset += dumpSingleInstr(compiler->info.compCode, genCurDispOffset, "> ");
398 }
399 }
400 }
401#endif // DEBUG
402
403 genCodeForTreeNode(node);
404 if (node->gtHasReg() && node->IsUnusedValue())
405 {
406 genConsumeReg(node);
407 }
408 } // end for each node in block
409
410#ifdef DEBUG
411 // The following set of register spill checks and GC pointer tracking checks used to be
412 // performed at statement boundaries. Now, with LIR, there are no statements, so they are
413 // performed at the end of each block.
414 // TODO: could these checks be performed more frequently? E.g., at each location where
415 // the register allocator says there are no live non-variable registers. Perhaps this could
416 // be done by using the map maintained by LSRA (operandToLocationInfoMap) to mark a node
417 // somehow when, after the execution of that node, there will be no live non-variable registers.
418
419 regSet.rsSpillChk();
420
421 /* Make sure we didn't bungle pointer register tracking */
422
423 regMaskTP ptrRegs = gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur;
424 regMaskTP nonVarPtrRegs = ptrRegs & ~regSet.rsMaskVars;
425
426 // If return is a GC-type, clear it. Note that if a common
427 // epilog is generated (genReturnBB) it has a void return
428 // even though we might return a ref. We can't use the compRetType
429 // as the determiner because something we are tracking as a byref
430 // might be used as a return value of a int function (which is legal)
431 GenTree* blockLastNode = block->lastNode();
432 if ((blockLastNode != nullptr) && (blockLastNode->gtOper == GT_RETURN) &&
433 (varTypeIsGC(compiler->info.compRetType) ||
434 (blockLastNode->gtOp.gtOp1 != nullptr && varTypeIsGC(blockLastNode->gtOp.gtOp1->TypeGet()))))
435 {
436 nonVarPtrRegs &= ~RBM_INTRET;
437 }
438
439 if (nonVarPtrRegs)
440 {
441 printf("Regset after " FMT_BB " gcr=", block->bbNum);
442 printRegMaskInt(gcInfo.gcRegGCrefSetCur & ~regSet.rsMaskVars);
443 compiler->getEmitter()->emitDispRegSet(gcInfo.gcRegGCrefSetCur & ~regSet.rsMaskVars);
444 printf(", byr=");
445 printRegMaskInt(gcInfo.gcRegByrefSetCur & ~regSet.rsMaskVars);
446 compiler->getEmitter()->emitDispRegSet(gcInfo.gcRegByrefSetCur & ~regSet.rsMaskVars);
447 printf(", regVars=");
448 printRegMaskInt(regSet.rsMaskVars);
449 compiler->getEmitter()->emitDispRegSet(regSet.rsMaskVars);
450 printf("\n");
451 }
452
453 noway_assert(nonVarPtrRegs == RBM_NONE);
454#endif // DEBUG
455
456#if defined(DEBUG)
457 if (block->bbNext == nullptr)
458 {
459// Unit testing of the emitter: generate a bunch of instructions into the last block
460// (it's as good as any, but better than the prologue, which can only be a single instruction
461// group) then use COMPlus_JitLateDisasm=* to see if the late disassembler
462// thinks the instructions are the same as we do.
463#if defined(_TARGET_AMD64_) && defined(LATE_DISASM)
464 genAmd64EmitterUnitTests();
465#elif defined(_TARGET_ARM64_)
466 genArm64EmitterUnitTests();
467#endif // _TARGET_ARM64_
468 }
469#endif // defined(DEBUG)
470
471 // It is possible to reach the end of the block without generating code for the current IL offset.
472 // For example, if the following IR ends the current block, no code will have been generated for
473 // offset 21:
474 //
475 // ( 0, 0) [000040] ------------ il_offset void IL offset: 21
476 //
477 // N001 ( 0, 0) [000039] ------------ nop void
478 //
479 // This can lead to problems when debugging the generated code. To prevent these issues, make sure
480 // we've generated code for the last IL offset we saw in the block.
481 genEnsureCodeEmitted(currentILOffset);
482
483 if (compiler->opts.compScopeInfo && (compiler->info.compVarScopesCount > 0))
484 {
485 siEndBlock(block);
486
487 /* Is this the last block, and are there any open scopes left ? */
488
489 bool isLastBlockProcessed = (block->bbNext == nullptr);
490 if (block->isBBCallAlwaysPair())
491 {
492 isLastBlockProcessed = (block->bbNext->bbNext == nullptr);
493 }
494
495 if (isLastBlockProcessed && siOpenScopeList.scNext)
496 {
497 /* This assert no longer holds, because we may insert a throw
498 block to demarcate the end of a try or finally region when they
499 are at the end of the method. It would be nice if we could fix
500 our code so that this throw block will no longer be necessary. */
501
502 // noway_assert(block->bbCodeOffsEnd != compiler->info.compILCodeSize);
503
504 siCloseAllOpenScopes();
505 }
506 }
507
508 SubtractStackLevel(savedStkLvl);
509
510#ifdef DEBUG
511 // compCurLife should be equal to the liveOut set, except that we don't keep
512 // it up to date for vars that are not register candidates
513 // (it would be nice to have a xor set function)
514
515 VARSET_TP mismatchLiveVars(VarSetOps::Diff(compiler, block->bbLiveOut, compiler->compCurLife));
516 VarSetOps::UnionD(compiler, mismatchLiveVars,
517 VarSetOps::Diff(compiler, compiler->compCurLife, block->bbLiveOut));
518 VarSetOps::Iter mismatchLiveVarIter(compiler, mismatchLiveVars);
519 unsigned mismatchLiveVarIndex = 0;
520 bool foundMismatchedRegVar = false;
521 while (mismatchLiveVarIter.NextElem(&mismatchLiveVarIndex))
522 {
523 unsigned varNum = compiler->lvaTrackedToVarNum[mismatchLiveVarIndex];
524 LclVarDsc* varDsc = compiler->lvaTable + varNum;
525 if (varDsc->lvIsRegCandidate())
526 {
527 if (!foundMismatchedRegVar)
528 {
529 JITDUMP("Mismatched live reg vars after BB%02u:", block->bbNum);
530 foundMismatchedRegVar = true;
531 }
532 JITDUMP(" V%02u", varNum);
533 }
534 }
535 if (foundMismatchedRegVar)
536 {
537 assert(!"Found mismatched live reg var(s) after block");
538 JITDUMP("\n");
539 }
540#endif
541
542 /* Both stacks should always be empty on exit from a basic block */
543 noway_assert(genStackLevel == 0);
544
545#ifdef _TARGET_AMD64_
546 // On AMD64, we need to generate a NOP after a call that is the last instruction of the block, in several
547 // situations, to support proper exception handling semantics. This is mostly to ensure that when the stack
548 // walker computes an instruction pointer for a frame, that instruction pointer is in the correct EH region.
549 // The document "X64 and ARM ABIs.docx" has more details. The situations:
550 // 1. If the call instruction is in a different EH region as the instruction that follows it.
551 // 2. If the call immediately precedes an OS epilog. (Note that what the JIT or VM consider an epilog might
552 // be slightly different from what the OS considers an epilog, and it is the OS-reported epilog that matters
553 // here.)
554 // We handle case #1 here, and case #2 in the emitter.
555 if (getEmitter()->emitIsLastInsCall())
556 {
557 // Ok, the last instruction generated is a call instruction. Do any of the other conditions hold?
558 // Note: we may be generating a few too many NOPs for the case of call preceding an epilog. Technically,
559 // if the next block is a BBJ_RETURN, an epilog will be generated, but there may be some instructions
560 // generated before the OS epilog starts, such as a GS cookie check.
561 if ((block->bbNext == nullptr) || !BasicBlock::sameEHRegion(block, block->bbNext))
562 {
563 // We only need the NOP if we're not going to generate any more code as part of the block end.
564
565 switch (block->bbJumpKind)
566 {
567 case BBJ_ALWAYS:
568 case BBJ_THROW:
569 case BBJ_CALLFINALLY:
570 case BBJ_EHCATCHRET:
571 // We're going to generate more code below anyway, so no need for the NOP.
572
573 case BBJ_RETURN:
574 case BBJ_EHFINALLYRET:
575 case BBJ_EHFILTERRET:
576 // These are the "epilog follows" case, handled in the emitter.
577
578 break;
579
580 case BBJ_NONE:
581 if (block->bbNext == nullptr)
582 {
583 // Call immediately before the end of the code; we should never get here .
584 instGen(INS_BREAKPOINT); // This should never get executed
585 }
586 else
587 {
588 // We need the NOP
589 instGen(INS_nop);
590 }
591 break;
592
593 case BBJ_COND:
594 case BBJ_SWITCH:
595 // These can't have a call as the last instruction!
596
597 default:
598 noway_assert(!"Unexpected bbJumpKind");
599 break;
600 }
601 }
602 }
603#endif // _TARGET_AMD64_
604
605 /* Do we need to generate a jump or return? */
606
607 switch (block->bbJumpKind)
608 {
609 case BBJ_ALWAYS:
610 inst_JMP(EJ_jmp, block->bbJumpDest);
611 break;
612
613 case BBJ_RETURN:
614 genExitCode(block);
615 break;
616
617 case BBJ_THROW:
618 // If we have a throw at the end of a function or funclet, we need to emit another instruction
619 // afterwards to help the OS unwinder determine the correct context during unwind.
620 // We insert an unexecuted breakpoint instruction in several situations
621 // following a throw instruction:
622 // 1. If the throw is the last instruction of the function or funclet. This helps
623 // the OS unwinder determine the correct context during an unwind from the
624 // thrown exception.
625 // 2. If this is this is the last block of the hot section.
626 // 3. If the subsequent block is a special throw block.
627 // 4. On AMD64, if the next block is in a different EH region.
628 if ((block->bbNext == nullptr) || (block->bbNext->bbFlags & BBF_FUNCLET_BEG) ||
629 !BasicBlock::sameEHRegion(block, block->bbNext) ||
630 (!isFramePointerUsed() && compiler->fgIsThrowHlpBlk(block->bbNext)) ||
631 block->bbNext == compiler->fgFirstColdBlock)
632 {
633 instGen(INS_BREAKPOINT); // This should never get executed
634 }
635 // Do likewise for blocks that end in DOES_NOT_RETURN calls
636 // that were not caught by the above rules. This ensures that
637 // gc register liveness doesn't change across call instructions
638 // in fully-interruptible mode.
639 else
640 {
641 GenTree* call = block->lastNode();
642
643 if ((call != nullptr) && (call->gtOper == GT_CALL))
644 {
645 if ((call->gtCall.gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) != 0)
646 {
647 instGen(INS_BREAKPOINT); // This should never get executed
648 }
649 }
650 }
651
652 break;
653
654 case BBJ_CALLFINALLY:
655 block = genCallFinally(block);
656 break;
657
658#if FEATURE_EH_FUNCLETS
659
660 case BBJ_EHCATCHRET:
661 genEHCatchRet(block);
662 __fallthrough;
663
664 case BBJ_EHFINALLYRET:
665 case BBJ_EHFILTERRET:
666 genReserveFuncletEpilog(block);
667 break;
668
669#else // !FEATURE_EH_FUNCLETS
670
671 case BBJ_EHCATCHRET:
672 noway_assert(!"Unexpected BBJ_EHCATCHRET"); // not used on x86
673
674 case BBJ_EHFINALLYRET:
675 case BBJ_EHFILTERRET:
676 genEHFinallyOrFilterRet(block);
677 break;
678
679#endif // !FEATURE_EH_FUNCLETS
680
681 case BBJ_NONE:
682 case BBJ_COND:
683 case BBJ_SWITCH:
684 break;
685
686 default:
687 noway_assert(!"Unexpected bbJumpKind");
688 break;
689 }
690
691#ifdef DEBUG
692 compiler->compCurBB = nullptr;
693#endif
694
695 } //------------------ END-FOR each block of the method -------------------
696
697 /* Nothing is live at this point */
698 genUpdateLife(VarSetOps::MakeEmpty(compiler));
699
700 /* Finalize the spill tracking logic */
701
702 regSet.rsSpillEnd();
703
704 /* Finalize the temp tracking logic */
705
706 regSet.tmpEnd();
707
708#ifdef DEBUG
709 if (compiler->verbose)
710 {
711 printf("\n# ");
712 printf("compCycleEstimate = %6d, compSizeEstimate = %5d ", compiler->compCycleEstimate,
713 compiler->compSizeEstimate);
714 printf("%s\n", compiler->info.compFullName);
715 }
716#endif
717}
718
719/*
720XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
721XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
722XX XX
723XX Register Management XX
724XX XX
725XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
726XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
727*/
728
729//------------------------------------------------------------------------
730// genSpillVar: Spill a local variable
731//
732// Arguments:
733// tree - the lclVar node for the variable being spilled
734//
735// Return Value:
736// None.
737//
738// Assumptions:
739// The lclVar must be a register candidate (lvRegCandidate)
740
741void CodeGen::genSpillVar(GenTree* tree)
742{
743 unsigned varNum = tree->gtLclVarCommon.gtLclNum;
744 LclVarDsc* varDsc = &(compiler->lvaTable[varNum]);
745
746 assert(varDsc->lvIsRegCandidate());
747
748 // We don't actually need to spill if it is already living in memory
749 bool needsSpill = ((tree->gtFlags & GTF_VAR_DEF) == 0 && varDsc->lvIsInReg());
750 if (needsSpill)
751 {
752 // In order for a lclVar to have been allocated to a register, it must not have been aliasable, and can
753 // therefore be store-normalized (rather than load-normalized). In fact, not performing store normalization
754 // can lead to problems on architectures where a lclVar may be allocated to a register that is not
755 // addressable at the granularity of the lclVar's defined type (e.g. x86).
756 var_types lclTyp = genActualType(varDsc->TypeGet());
757 emitAttr size = emitTypeSize(lclTyp);
758
759 instruction storeIns = ins_Store(lclTyp, compiler->isSIMDTypeLocalAligned(varNum));
760 assert(varDsc->lvRegNum == tree->gtRegNum);
761 inst_TT_RV(storeIns, tree, tree->gtRegNum, 0, size);
762
763 genUpdateRegLife(varDsc, /*isBorn*/ false, /*isDying*/ true DEBUGARG(tree));
764 gcInfo.gcMarkRegSetNpt(varDsc->lvRegMask());
765
766 if (VarSetOps::IsMember(compiler, gcInfo.gcTrkStkPtrLcls, varDsc->lvVarIndex))
767 {
768#ifdef DEBUG
769 if (!VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex))
770 {
771 JITDUMP("\t\t\t\t\t\t\tVar V%02u becoming live\n", varNum);
772 }
773 else
774 {
775 JITDUMP("\t\t\t\t\t\t\tVar V%02u continuing live\n", varNum);
776 }
777#endif
778 VarSetOps::AddElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex);
779 }
780 }
781
782 tree->gtFlags &= ~GTF_SPILL;
783 varDsc->lvRegNum = REG_STK;
784 if (varTypeIsMultiReg(tree))
785 {
786 varDsc->lvOtherReg = REG_STK;
787 }
788}
789
790//------------------------------------------------------------------------
791// genUpdateVarReg: Update the current register location for a lclVar
792//
793// Arguments:
794// varDsc - the LclVarDsc for the lclVar
795// tree - the lclVar node
796//
797// inline
798void CodeGenInterface::genUpdateVarReg(LclVarDsc* varDsc, GenTree* tree)
799{
800 assert(tree->OperIsScalarLocal() || (tree->gtOper == GT_COPY));
801 varDsc->lvRegNum = tree->gtRegNum;
802}
803
804//------------------------------------------------------------------------
805// sameRegAsDst: Return the child that has the same reg as the dst (if any)
806//
807// Arguments:
808// tree - the node of interest
809// other - an out parameter to return the other child
810//
811// Notes:
812// If 'tree' has a child with the same assigned register as its target reg,
813// that child will be returned, and 'other' will contain the non-matching child.
814// Otherwise, both other and the return value will be nullptr.
815//
816GenTree* sameRegAsDst(GenTree* tree, GenTree*& other /*out*/)
817{
818 if (tree->gtRegNum == REG_NA)
819 {
820 other = nullptr;
821 return nullptr;
822 }
823
824 GenTree* op1 = tree->gtOp.gtOp1;
825 GenTree* op2 = tree->gtOp.gtOp2;
826 if (op1->gtRegNum == tree->gtRegNum)
827 {
828 other = op2;
829 return op1;
830 }
831 if (op2->gtRegNum == tree->gtRegNum)
832 {
833 other = op1;
834 return op2;
835 }
836 else
837 {
838 other = nullptr;
839 return nullptr;
840 }
841}
842
843//------------------------------------------------------------------------
844// genUnspillRegIfNeeded: Reload the value into a register, if needed
845//
846// Arguments:
847// tree - the node of interest.
848//
849// Notes:
850// In the normal case, the value will be reloaded into the register it
851// was originally computed into. However, if that register is not available,
852// the register allocator will have allocated a different register, and
853// inserted a GT_RELOAD to indicate the register into which it should be
854// reloaded.
855//
856void CodeGen::genUnspillRegIfNeeded(GenTree* tree)
857{
858 regNumber dstReg = tree->gtRegNum;
859 GenTree* unspillTree = tree;
860
861 if (tree->gtOper == GT_RELOAD)
862 {
863 unspillTree = tree->gtOp.gtOp1;
864 }
865
866 if ((unspillTree->gtFlags & GTF_SPILLED) != 0)
867 {
868 if (genIsRegCandidateLocal(unspillTree))
869 {
870 // Reset spilled flag, since we are going to load a local variable from its home location.
871 unspillTree->gtFlags &= ~GTF_SPILLED;
872
873 GenTreeLclVarCommon* lcl = unspillTree->AsLclVarCommon();
874 LclVarDsc* varDsc = &compiler->lvaTable[lcl->gtLclNum];
875
876// TODO-Cleanup: The following code could probably be further merged and cleaned up.
877#ifdef _TARGET_XARCH_
878 // Load local variable from its home location.
879 // In most cases the tree type will indicate the correct type to use for the load.
880 // However, if it is NOT a normalizeOnLoad lclVar (i.e. NOT a small int that always gets
881 // widened when loaded into a register), and its size is not the same as genActualType of
882 // the type of the lclVar, then we need to change the type of the tree node when loading.
883 // This situation happens due to "optimizations" that avoid a cast and
884 // simply retype the node when using long type lclVar as an int.
885 // While loading the int in that case would work for this use of the lclVar, if it is
886 // later used as a long, we will have incorrectly truncated the long.
887 // In the normalizeOnLoad case ins_Load will return an appropriate sign- or zero-
888 // extending load.
889
890 var_types treeType = unspillTree->TypeGet();
891 if (treeType != genActualType(varDsc->lvType) && !varTypeIsGC(treeType) && !varDsc->lvNormalizeOnLoad())
892 {
893 assert(!varTypeIsGC(varDsc));
894 var_types spillType = genActualType(varDsc->lvType);
895 unspillTree->gtType = spillType;
896 inst_RV_TT(ins_Load(spillType, compiler->isSIMDTypeLocalAligned(lcl->gtLclNum)), dstReg, unspillTree);
897 unspillTree->gtType = treeType;
898 }
899 else
900 {
901 inst_RV_TT(ins_Load(treeType, compiler->isSIMDTypeLocalAligned(lcl->gtLclNum)), dstReg, unspillTree);
902 }
903#elif defined(_TARGET_ARM64_)
904 var_types targetType = unspillTree->gtType;
905 if (targetType != genActualType(varDsc->lvType) && !varTypeIsGC(targetType) && !varDsc->lvNormalizeOnLoad())
906 {
907 assert(!varTypeIsGC(varDsc));
908 targetType = genActualType(varDsc->lvType);
909 }
910 instruction ins = ins_Load(targetType, compiler->isSIMDTypeLocalAligned(lcl->gtLclNum));
911 emitAttr attr = emitTypeSize(targetType);
912 emitter* emit = getEmitter();
913
914 // Fixes Issue #3326
915 attr = varTypeIsFloating(targetType) ? attr : emit->emitInsAdjustLoadStoreAttr(ins, attr);
916
917 // Load local variable from its home location.
918 inst_RV_TT(ins, dstReg, unspillTree, 0, attr);
919#elif defined(_TARGET_ARM_)
920 var_types targetType = unspillTree->gtType;
921 instruction ins = ins_Load(targetType, compiler->isSIMDTypeLocalAligned(lcl->gtLclNum));
922 emitAttr attr = emitTypeSize(targetType);
923
924 // Load local variable from its home location.
925 inst_RV_TT(ins, dstReg, unspillTree, 0, attr);
926#else
927 NYI("Unspilling not implemented for this target architecture.");
928#endif
929
930 // TODO-Review: We would like to call:
931 // genUpdateRegLife(varDsc, /*isBorn*/ true, /*isDying*/ false DEBUGARG(tree));
932 // instead of the following code, but this ends up hitting this assert:
933 // assert((regSet.rsMaskVars & regMask) == 0);
934 // due to issues with LSRA resolution moves.
935 // So, just force it for now. This probably indicates a condition that creates a GC hole!
936 //
937 // Extra note: I think we really want to call something like gcInfo.gcUpdateForRegVarMove,
938 // because the variable is not really going live or dead, but that method is somewhat poorly
939 // factored because it, in turn, updates rsMaskVars which is part of RegSet not GCInfo.
940 // TODO-Cleanup: This code exists in other CodeGen*.cpp files, and should be moved to CodeGenCommon.cpp.
941
942 // Don't update the variable's location if we are just re-spilling it again.
943
944 if ((unspillTree->gtFlags & GTF_SPILL) == 0)
945 {
946 genUpdateVarReg(varDsc, tree);
947#ifdef DEBUG
948 if (VarSetOps::IsMember(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex))
949 {
950 JITDUMP("\t\t\t\t\t\t\tRemoving V%02u from gcVarPtrSetCur\n", lcl->gtLclNum);
951 }
952#endif // DEBUG
953 VarSetOps::RemoveElemD(compiler, gcInfo.gcVarPtrSetCur, varDsc->lvVarIndex);
954
955#ifdef DEBUG
956 if (compiler->verbose)
957 {
958 printf("\t\t\t\t\t\t\tV%02u in reg ", lcl->gtLclNum);
959 varDsc->PrintVarReg();
960 printf(" is becoming live ");
961 compiler->printTreeID(unspillTree);
962 printf("\n");
963 }
964#endif // DEBUG
965
966 regSet.AddMaskVars(genGetRegMask(varDsc));
967 }
968
969 gcInfo.gcMarkRegPtrVal(dstReg, unspillTree->TypeGet());
970 }
971 else if (unspillTree->IsMultiRegCall())
972 {
973 GenTreeCall* call = unspillTree->AsCall();
974 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
975 unsigned regCount = retTypeDesc->GetReturnRegCount();
976 GenTreeCopyOrReload* reloadTree = nullptr;
977 if (tree->OperGet() == GT_RELOAD)
978 {
979 reloadTree = tree->AsCopyOrReload();
980 }
981
982 // In case of multi-reg call node, GTF_SPILLED flag on it indicates that
983 // one or more of its result regs are spilled. Call node needs to be
984 // queried to know which specific result regs to be unspilled.
985 for (unsigned i = 0; i < regCount; ++i)
986 {
987 unsigned flags = call->GetRegSpillFlagByIdx(i);
988 if ((flags & GTF_SPILLED) != 0)
989 {
990 var_types dstType = retTypeDesc->GetReturnRegType(i);
991 regNumber unspillTreeReg = call->GetRegNumByIdx(i);
992
993 if (reloadTree != nullptr)
994 {
995 dstReg = reloadTree->GetRegNumByIdx(i);
996 if (dstReg == REG_NA)
997 {
998 dstReg = unspillTreeReg;
999 }
1000 }
1001 else
1002 {
1003 dstReg = unspillTreeReg;
1004 }
1005
1006 TempDsc* t = regSet.rsUnspillInPlace(call, unspillTreeReg, i);
1007 getEmitter()->emitIns_R_S(ins_Load(dstType), emitActualTypeSize(dstType), dstReg, t->tdTempNum(),
1008 0);
1009 regSet.tmpRlsTemp(t);
1010 gcInfo.gcMarkRegPtrVal(dstReg, dstType);
1011 }
1012 }
1013
1014 unspillTree->gtFlags &= ~GTF_SPILLED;
1015 }
1016#if FEATURE_ARG_SPLIT
1017 else if (unspillTree->OperIsPutArgSplit())
1018 {
1019 GenTreePutArgSplit* splitArg = unspillTree->AsPutArgSplit();
1020 unsigned regCount = splitArg->gtNumRegs;
1021
1022 // In case of split struct argument node, GTF_SPILLED flag on it indicates that
1023 // one or more of its result regs are spilled. Call node needs to be
1024 // queried to know which specific result regs to be unspilled.
1025 for (unsigned i = 0; i < regCount; ++i)
1026 {
1027 unsigned flags = splitArg->GetRegSpillFlagByIdx(i);
1028 if ((flags & GTF_SPILLED) != 0)
1029 {
1030 BYTE* gcPtrs = splitArg->gtGcPtrs;
1031 var_types dstType = splitArg->GetRegType(i);
1032 regNumber dstReg = splitArg->GetRegNumByIdx(i);
1033
1034 TempDsc* t = regSet.rsUnspillInPlace(splitArg, dstReg, i);
1035 getEmitter()->emitIns_R_S(ins_Load(dstType), emitActualTypeSize(dstType), dstReg, t->tdTempNum(),
1036 0);
1037 regSet.tmpRlsTemp(t);
1038 gcInfo.gcMarkRegPtrVal(dstReg, dstType);
1039 }
1040 }
1041
1042 unspillTree->gtFlags &= ~GTF_SPILLED;
1043 }
1044#ifdef _TARGET_ARM_
1045 else if (unspillTree->OperIsMultiRegOp())
1046 {
1047 GenTreeMultiRegOp* multiReg = unspillTree->AsMultiRegOp();
1048 unsigned regCount = multiReg->GetRegCount();
1049
1050 // In case of split struct argument node, GTF_SPILLED flag on it indicates that
1051 // one or more of its result regs are spilled. Call node needs to be
1052 // queried to know which specific result regs to be unspilled.
1053 for (unsigned i = 0; i < regCount; ++i)
1054 {
1055 unsigned flags = multiReg->GetRegSpillFlagByIdx(i);
1056 if ((flags & GTF_SPILLED) != 0)
1057 {
1058 var_types dstType = multiReg->GetRegType(i);
1059 regNumber dstReg = multiReg->GetRegNumByIdx(i);
1060
1061 TempDsc* t = regSet.rsUnspillInPlace(multiReg, dstReg, i);
1062 getEmitter()->emitIns_R_S(ins_Load(dstType), emitActualTypeSize(dstType), dstReg, t->tdTempNum(),
1063 0);
1064 regSet.tmpRlsTemp(t);
1065 gcInfo.gcMarkRegPtrVal(dstReg, dstType);
1066 }
1067 }
1068
1069 unspillTree->gtFlags &= ~GTF_SPILLED;
1070 }
1071#endif //_TARGET_ARM_
1072#endif // FEATURE_ARG_SPLIT
1073 else
1074 {
1075 TempDsc* t = regSet.rsUnspillInPlace(unspillTree, unspillTree->gtRegNum);
1076 getEmitter()->emitIns_R_S(ins_Load(unspillTree->gtType), emitActualTypeSize(unspillTree->TypeGet()), dstReg,
1077 t->tdTempNum(), 0);
1078 regSet.tmpRlsTemp(t);
1079
1080 unspillTree->gtFlags &= ~GTF_SPILLED;
1081 gcInfo.gcMarkRegPtrVal(dstReg, unspillTree->TypeGet());
1082 }
1083 }
1084}
1085
1086//------------------------------------------------------------------------
1087// genCopyRegIfNeeded: Copy the given node into the specified register
1088//
1089// Arguments:
1090// node - The node that has been evaluated (consumed).
1091// needReg - The register in which its value is needed.
1092//
1093// Notes:
1094// This must be a node that has a register.
1095//
1096void CodeGen::genCopyRegIfNeeded(GenTree* node, regNumber needReg)
1097{
1098 assert((node->gtRegNum != REG_NA) && (needReg != REG_NA));
1099 assert(!node->isUsedFromSpillTemp());
1100 if (node->gtRegNum != needReg)
1101 {
1102 inst_RV_RV(INS_mov, needReg, node->gtRegNum, node->TypeGet());
1103 }
1104}
1105
1106// Do Liveness update for a subnodes that is being consumed by codegen
1107// including the logic for reload in case is needed and also takes care
1108// of locating the value on the desired register.
1109void CodeGen::genConsumeRegAndCopy(GenTree* node, regNumber needReg)
1110{
1111 if (needReg == REG_NA)
1112 {
1113 return;
1114 }
1115 regNumber treeReg = genConsumeReg(node);
1116 genCopyRegIfNeeded(node, needReg);
1117}
1118
1119// Check that registers are consumed in the right order for the current node being generated.
1120#ifdef DEBUG
1121void CodeGen::genNumberOperandUse(GenTree* const operand, int& useNum) const
1122{
1123 assert(operand != nullptr);
1124
1125 // Ignore argument placeholders.
1126 if (operand->OperGet() == GT_ARGPLACE)
1127 {
1128 return;
1129 }
1130
1131 assert(operand->gtUseNum == -1);
1132
1133 if (!operand->isContained() && !operand->IsCopyOrReload())
1134 {
1135 operand->gtUseNum = useNum;
1136 useNum++;
1137 }
1138 else
1139 {
1140 for (GenTree* operand : operand->Operands())
1141 {
1142 genNumberOperandUse(operand, useNum);
1143 }
1144 }
1145}
1146
1147void CodeGen::genCheckConsumeNode(GenTree* const node)
1148{
1149 assert(node != nullptr);
1150
1151 if (verbose)
1152 {
1153 if (node->gtUseNum == -1)
1154 {
1155 // nothing wrong if the node was not consumed
1156 }
1157 else if ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) != 0)
1158 {
1159 printf("Node was consumed twice:\n");
1160 compiler->gtDispTree(node, nullptr, nullptr, true);
1161 }
1162 else if ((lastConsumedNode != nullptr) && (node->gtUseNum < lastConsumedNode->gtUseNum))
1163 {
1164 printf("Nodes were consumed out-of-order:\n");
1165 compiler->gtDispTree(lastConsumedNode, nullptr, nullptr, true);
1166 compiler->gtDispTree(node, nullptr, nullptr, true);
1167 }
1168 }
1169
1170 assert((node->OperGet() == GT_CATCH_ARG) || ((node->gtDebugFlags & GTF_DEBUG_NODE_CG_CONSUMED) == 0));
1171 assert((lastConsumedNode == nullptr) || (node->gtUseNum == -1) || (node->gtUseNum > lastConsumedNode->gtUseNum));
1172
1173 node->gtDebugFlags |= GTF_DEBUG_NODE_CG_CONSUMED;
1174 lastConsumedNode = node;
1175}
1176#endif // DEBUG
1177
1178//--------------------------------------------------------------------
1179// genConsumeReg: Do liveness update for a subnode that is being
1180// consumed by codegen.
1181//
1182// Arguments:
1183// tree - GenTree node
1184//
1185// Return Value:
1186// Returns the reg number of tree.
1187// In case of multi-reg call node returns the first reg number
1188// of the multi-reg return.
1189regNumber CodeGen::genConsumeReg(GenTree* tree)
1190{
1191 if (tree->OperGet() == GT_COPY)
1192 {
1193 genRegCopy(tree);
1194 }
1195
1196 // Handle the case where we have a lclVar that needs to be copied before use (i.e. because it
1197 // interferes with one of the other sources (or the target, if it's a "delayed use" register)).
1198 // TODO-Cleanup: This is a special copyReg case in LSRA - consider eliminating these and
1199 // always using GT_COPY to make the lclVar location explicit.
1200 // Note that we have to do this before calling genUpdateLife because otherwise if we spill it
1201 // the lvRegNum will be set to REG_STK and we will lose track of what register currently holds
1202 // the lclVar (normally when a lclVar is spilled it is then used from its former register
1203 // location, which matches the gtRegNum on the node).
1204 // (Note that it doesn't matter if we call this before or after genUnspillRegIfNeeded
1205 // because if it's on the stack it will always get reloaded into tree->gtRegNum).
1206 if (genIsRegCandidateLocal(tree))
1207 {
1208 GenTreeLclVarCommon* lcl = tree->AsLclVarCommon();
1209 LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()];
1210 if (varDsc->lvRegNum != REG_STK && varDsc->lvRegNum != tree->gtRegNum)
1211 {
1212 inst_RV_RV(ins_Copy(tree->TypeGet()), tree->gtRegNum, varDsc->lvRegNum);
1213 }
1214 }
1215
1216 genUnspillRegIfNeeded(tree);
1217
1218 // genUpdateLife() will also spill local var if marked as GTF_SPILL by calling CodeGen::genSpillVar
1219 genUpdateLife(tree);
1220
1221 assert(tree->gtHasReg());
1222
1223 // there are three cases where consuming a reg means clearing the bit in the live mask
1224 // 1. it was not produced by a local
1225 // 2. it was produced by a local that is going dead
1226 // 3. it was produced by a local that does not live in that reg (like one allocated on the stack)
1227
1228 if (genIsRegCandidateLocal(tree))
1229 {
1230 GenTreeLclVarCommon* lcl = tree->AsLclVarCommon();
1231 LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()];
1232 assert(varDsc->lvLRACandidate);
1233
1234 if ((tree->gtFlags & GTF_VAR_DEATH) != 0)
1235 {
1236 gcInfo.gcMarkRegSetNpt(genRegMask(varDsc->lvRegNum));
1237 }
1238 else if (varDsc->lvRegNum == REG_STK)
1239 {
1240 // We have loaded this into a register only temporarily
1241 gcInfo.gcMarkRegSetNpt(genRegMask(tree->gtRegNum));
1242 }
1243 }
1244 else
1245 {
1246 gcInfo.gcMarkRegSetNpt(tree->gtGetRegMask());
1247 }
1248
1249 genCheckConsumeNode(tree);
1250 return tree->gtRegNum;
1251}
1252
1253// Do liveness update for an address tree: one of GT_LEA, GT_LCL_VAR, or GT_CNS_INT (for call indirect).
1254void CodeGen::genConsumeAddress(GenTree* addr)
1255{
1256 if (!addr->isContained())
1257 {
1258 genConsumeReg(addr);
1259 }
1260 else if (addr->OperGet() == GT_LEA)
1261 {
1262 genConsumeAddrMode(addr->AsAddrMode());
1263 }
1264}
1265
1266// do liveness update for a subnode that is being consumed by codegen
1267void CodeGen::genConsumeAddrMode(GenTreeAddrMode* addr)
1268{
1269 genConsumeOperands(addr);
1270}
1271
1272void CodeGen::genConsumeRegs(GenTree* tree)
1273{
1274#if !defined(_TARGET_64BIT_)
1275 if (tree->OperGet() == GT_LONG)
1276 {
1277 genConsumeRegs(tree->gtGetOp1());
1278 genConsumeRegs(tree->gtGetOp2());
1279 return;
1280 }
1281#endif // !defined(_TARGET_64BIT_)
1282
1283 if (tree->isUsedFromSpillTemp())
1284 {
1285 // spill temps are un-tracked and hence no need to update life
1286 }
1287 else if (tree->isContained())
1288 {
1289 if (tree->isIndir())
1290 {
1291 genConsumeAddress(tree->AsIndir()->Addr());
1292 }
1293#ifdef _TARGET_XARCH_
1294 else if (tree->OperIsLocalRead())
1295 {
1296 // A contained lcl var must be living on stack and marked as reg optional, or not be a
1297 // register candidate.
1298 unsigned varNum = tree->AsLclVarCommon()->GetLclNum();
1299 LclVarDsc* varDsc = compiler->lvaTable + varNum;
1300
1301 noway_assert(varDsc->lvRegNum == REG_STK);
1302 noway_assert(tree->IsRegOptional() || !varDsc->lvLRACandidate);
1303
1304 // Update the life of the lcl var.
1305 genUpdateLife(tree);
1306 }
1307#endif // _TARGET_XARCH_
1308 else if (tree->OperIsInitVal())
1309 {
1310 genConsumeReg(tree->gtGetOp1());
1311 }
1312 else if (tree->OperIsHWIntrinsic())
1313 {
1314 genConsumeReg(tree->gtGetOp1());
1315 }
1316 else
1317 {
1318#ifdef FEATURE_SIMD
1319 // (In)Equality operation that produces bool result, when compared
1320 // against Vector zero, marks its Vector Zero operand as contained.
1321 assert(tree->OperIsLeaf() || tree->IsIntegralConstVector(0));
1322#else
1323 assert(tree->OperIsLeaf());
1324#endif
1325 }
1326 }
1327 else
1328 {
1329 genConsumeReg(tree);
1330 }
1331}
1332
1333//------------------------------------------------------------------------
1334// genConsumeOperands: Do liveness update for the operands of a unary or binary tree
1335//
1336// Arguments:
1337// tree - the GenTreeOp whose operands will have their liveness updated.
1338//
1339// Return Value:
1340// None.
1341//
1342// Notes:
1343// Note that this logic is localized here because we must do the liveness update in
1344// the correct execution order. This is important because we may have two operands
1345// that involve the same lclVar, and if one is marked "lastUse" we must handle it
1346// after the first.
1347
1348void CodeGen::genConsumeOperands(GenTreeOp* tree)
1349{
1350 GenTree* firstOp = tree->gtOp1;
1351 GenTree* secondOp = tree->gtOp2;
1352
1353 if (firstOp != nullptr)
1354 {
1355 genConsumeRegs(firstOp);
1356 }
1357 if (secondOp != nullptr)
1358 {
1359 genConsumeRegs(secondOp);
1360 }
1361}
1362
1363#if FEATURE_PUT_STRUCT_ARG_STK
1364//------------------------------------------------------------------------
1365// genConsumePutStructArgStk: Do liveness update for the operands of a PutArgStk node.
1366// Also loads in the right register the addresses of the
1367// src/dst for rep mov operation.
1368//
1369// Arguments:
1370// putArgNode - the PUTARG_STK tree.
1371// dstReg - the dstReg for the rep move operation.
1372// srcReg - the srcReg for the rep move operation.
1373// sizeReg - the sizeReg for the rep move operation.
1374//
1375// Return Value:
1376// None.
1377//
1378// Notes:
1379// sizeReg can be REG_NA when this function is used to consume the dstReg and srcReg
1380// for copying on the stack a struct with references.
1381// The source address/offset is determined from the address on the GT_OBJ node, while
1382// the destination address is the address contained in 'm_stkArgVarNum' plus the offset
1383// provided in the 'putArgNode'.
1384// m_stkArgVarNum must be set to the varnum for the local used for placing the "by-value" args on the stack.
1385
1386void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode,
1387 regNumber dstReg,
1388 regNumber srcReg,
1389 regNumber sizeReg)
1390{
1391 // The putArgNode children are always contained. We should not consume any registers.
1392 assert(putArgNode->gtGetOp1()->isContained());
1393
1394 // Get the source address.
1395 GenTree* src = putArgNode->gtGetOp1();
1396 assert(varTypeIsStruct(src));
1397 assert((src->gtOper == GT_OBJ) || ((src->gtOper == GT_IND && varTypeIsSIMD(src))));
1398 GenTree* srcAddr = src->gtGetOp1();
1399
1400 unsigned int size = putArgNode->getArgSize();
1401
1402 assert(dstReg != REG_NA);
1403 assert(srcReg != REG_NA);
1404
1405 // Consume the registers only if they are not contained or set to REG_NA.
1406 if (srcAddr->gtRegNum != REG_NA)
1407 {
1408 genConsumeReg(srcAddr);
1409 }
1410
1411 // If the op1 is already in the dstReg - nothing to do.
1412 // Otherwise load the op1 (GT_ADDR) into the dstReg to copy the struct on the stack by value.
1413 CLANG_FORMAT_COMMENT_ANCHOR;
1414
1415#ifdef _TARGET_X86_
1416 assert(dstReg != REG_SPBASE);
1417 inst_RV_RV(INS_mov, dstReg, REG_SPBASE);
1418#else // !_TARGET_X86_
1419 GenTree* dstAddr = putArgNode;
1420 if (dstAddr->gtRegNum != dstReg)
1421 {
1422 // Generate LEA instruction to load the stack of the outgoing var + SlotNum offset (or the incoming arg area
1423 // for tail calls) in RDI.
1424 // Destination is always local (on the stack) - use EA_PTRSIZE.
1425 assert(m_stkArgVarNum != BAD_VAR_NUM);
1426 getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, dstReg, m_stkArgVarNum, putArgNode->getArgOffset());
1427 }
1428#endif // !_TARGET_X86_
1429
1430 if (srcAddr->gtRegNum != srcReg)
1431 {
1432 if (srcAddr->OperIsLocalAddr())
1433 {
1434 // The OperLocalAddr is always contained.
1435 assert(srcAddr->isContained());
1436 GenTreeLclVarCommon* lclNode = srcAddr->AsLclVarCommon();
1437
1438 // Generate LEA instruction to load the LclVar address in RSI.
1439 // Source is known to be on the stack. Use EA_PTRSIZE.
1440 unsigned int offset = 0;
1441 if (srcAddr->OperGet() == GT_LCL_FLD_ADDR)
1442 {
1443 offset = srcAddr->AsLclFld()->gtLclOffs;
1444 }
1445 getEmitter()->emitIns_R_S(INS_lea, EA_PTRSIZE, srcReg, lclNode->gtLclNum, offset);
1446 }
1447 else
1448 {
1449 assert(srcAddr->gtRegNum != REG_NA);
1450 // Source is not known to be on the stack. Use EA_BYREF.
1451 getEmitter()->emitIns_R_R(INS_mov, EA_BYREF, srcReg, srcAddr->gtRegNum);
1452 }
1453 }
1454
1455 if (sizeReg != REG_NA)
1456 {
1457 inst_RV_IV(INS_mov, sizeReg, size, EA_PTRSIZE);
1458 }
1459}
1460#endif // FEATURE_PUT_STRUCT_ARG_STK
1461
1462#if FEATURE_ARG_SPLIT
1463//------------------------------------------------------------------------
1464// genConsumeArgRegSplit: Consume register(s) in Call node to set split struct argument.
1465// Liveness update for the PutArgSplit node is not needed
1466//
1467// Arguments:
1468// putArgNode - the PUTARG_STK tree.
1469//
1470// Return Value:
1471// None.
1472//
1473void CodeGen::genConsumeArgSplitStruct(GenTreePutArgSplit* putArgNode)
1474{
1475 assert(putArgNode->OperGet() == GT_PUTARG_SPLIT);
1476 assert(putArgNode->gtHasReg());
1477
1478 genUnspillRegIfNeeded(putArgNode);
1479
1480 // Skip updating GC info
1481 // GC info for all argument registers will be cleared in caller
1482
1483 genCheckConsumeNode(putArgNode);
1484}
1485#endif // FEATURE_ARG_SPLIT
1486
1487//------------------------------------------------------------------------
1488// genPutArgStkFieldList: Generate code for a putArgStk whose source is a GT_FIELD_LIST
1489//
1490// Arguments:
1491// putArgStk - The putArgStk node
1492// outArgVarNum - The lclVar num for the argument
1493//
1494// Notes:
1495// The x86 version of this is in codegenxarch.cpp, and doesn't take an
1496// outArgVarNum, as it pushes its args onto the stack.
1497//
1498#ifndef _TARGET_X86_
1499void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk, unsigned outArgVarNum)
1500{
1501 assert(putArgStk->gtOp1->OperIs(GT_FIELD_LIST));
1502
1503 // Evaluate each of the GT_FIELD_LIST items into their register
1504 // and store their register into the outgoing argument area.
1505 unsigned argOffset = putArgStk->getArgOffset();
1506 for (GenTreeFieldList* fieldListPtr = putArgStk->gtOp1->AsFieldList(); fieldListPtr != nullptr;
1507 fieldListPtr = fieldListPtr->Rest())
1508 {
1509 GenTree* nextArgNode = fieldListPtr->gtOp.gtOp1;
1510 genConsumeReg(nextArgNode);
1511
1512 regNumber reg = nextArgNode->gtRegNum;
1513 var_types type = nextArgNode->TypeGet();
1514 emitAttr attr = emitTypeSize(type);
1515
1516 // Emit store instructions to store the registers produced by the GT_FIELD_LIST into the outgoing
1517 // argument area.
1518 unsigned thisFieldOffset = argOffset + fieldListPtr->gtFieldOffset;
1519 getEmitter()->emitIns_S_R(ins_Store(type), attr, reg, outArgVarNum, thisFieldOffset);
1520
1521 // We can't write beyound the arg area
1522 assert((thisFieldOffset + EA_SIZE_IN_BYTES(attr)) <= compiler->lvaLclSize(outArgVarNum));
1523 }
1524}
1525#endif // !_TARGET_X86_
1526
1527//------------------------------------------------------------------------
1528// genSetBlockSize: Ensure that the block size is in the given register
1529//
1530// Arguments:
1531// blkNode - The block node
1532// sizeReg - The register into which the block's size should go
1533//
1534
1535void CodeGen::genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg)
1536{
1537 if (sizeReg != REG_NA)
1538 {
1539 unsigned blockSize = blkNode->Size();
1540 if (blockSize != 0)
1541 {
1542 assert((blkNode->gtRsvdRegs & genRegMask(sizeReg)) != 0);
1543 genSetRegToIcon(sizeReg, blockSize);
1544 }
1545 else
1546 {
1547 noway_assert(blkNode->gtOper == GT_STORE_DYN_BLK);
1548 GenTree* sizeNode = blkNode->AsDynBlk()->gtDynamicSize;
1549 if (sizeNode->gtRegNum != sizeReg)
1550 {
1551 inst_RV_RV(INS_mov, sizeReg, sizeNode->gtRegNum, sizeNode->TypeGet());
1552 }
1553 }
1554 }
1555}
1556
1557//------------------------------------------------------------------------
1558// genConsumeBlockSrc: Consume the source address register of a block node, if any.
1559//
1560// Arguments:
1561// blkNode - The block node
1562
1563void CodeGen::genConsumeBlockSrc(GenTreeBlk* blkNode)
1564{
1565 GenTree* src = blkNode->Data();
1566 if (blkNode->OperIsCopyBlkOp())
1567 {
1568 // For a CopyBlk we need the address of the source.
1569 if (src->OperGet() == GT_IND)
1570 {
1571 src = src->gtOp.gtOp1;
1572 }
1573 else
1574 {
1575 // This must be a local.
1576 // For this case, there is no source address register, as it is a
1577 // stack-based address.
1578 assert(src->OperIsLocal());
1579 return;
1580 }
1581 }
1582 else
1583 {
1584 if (src->OperIsInitVal())
1585 {
1586 src = src->gtGetOp1();
1587 }
1588 }
1589 genConsumeReg(src);
1590}
1591
1592//------------------------------------------------------------------------
1593// genSetBlockSrc: Ensure that the block source is in its allocated register.
1594//
1595// Arguments:
1596// blkNode - The block node
1597// srcReg - The register in which to set the source (address or init val).
1598//
1599void CodeGen::genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg)
1600{
1601 GenTree* src = blkNode->Data();
1602 if (blkNode->OperIsCopyBlkOp())
1603 {
1604 // For a CopyBlk we need the address of the source.
1605 if (src->OperGet() == GT_IND)
1606 {
1607 src = src->gtOp.gtOp1;
1608 }
1609 else
1610 {
1611 // This must be a local struct.
1612 // Load its address into srcReg.
1613 inst_RV_TT(INS_lea, srcReg, src, 0, EA_BYREF);
1614 return;
1615 }
1616 }
1617 else
1618 {
1619 if (src->OperIsInitVal())
1620 {
1621 src = src->gtGetOp1();
1622 }
1623 }
1624 genCopyRegIfNeeded(src, srcReg);
1625}
1626
1627//------------------------------------------------------------------------
1628// genConsumeBlockOp: Ensure that the block's operands are enregistered
1629// as needed.
1630// Arguments:
1631// blkNode - The block node
1632//
1633// Notes:
1634// This ensures that the operands are consumed in the proper order to
1635// obey liveness modeling.
1636
1637void CodeGen::genConsumeBlockOp(GenTreeBlk* blkNode, regNumber dstReg, regNumber srcReg, regNumber sizeReg)
1638{
1639 // We have to consume the registers, and perform any copies, in the actual execution order: dst, src, size.
1640 //
1641 // Note that the register allocator ensures that the registers ON THE NODES will not interfere
1642 // with one another if consumed (i.e. reloaded or moved to their ASSIGNED reg) in execution order.
1643 // Further, it ensures that they will not interfere with one another if they are then copied
1644 // to the REQUIRED register (if a fixed register requirement) in execution order. This requires,
1645 // then, that we first consume all the operands, then do any necessary moves.
1646
1647 GenTree* const dstAddr = blkNode->Addr();
1648
1649 // First, consume all the sources in order.
1650 genConsumeReg(dstAddr);
1651 genConsumeBlockSrc(blkNode);
1652 if (blkNode->OperGet() == GT_STORE_DYN_BLK)
1653 {
1654 genConsumeReg(blkNode->AsDynBlk()->gtDynamicSize);
1655 }
1656
1657 // Next, perform any necessary moves.
1658 genCopyRegIfNeeded(dstAddr, dstReg);
1659 genSetBlockSrc(blkNode, srcReg);
1660 genSetBlockSize(blkNode, sizeReg);
1661}
1662
1663//-------------------------------------------------------------------------
1664// genProduceReg: do liveness update for register produced by the current
1665// node in codegen.
1666//
1667// Arguments:
1668// tree - Gentree node
1669//
1670// Return Value:
1671// None.
1672void CodeGen::genProduceReg(GenTree* tree)
1673{
1674#ifdef DEBUG
1675 assert((tree->gtDebugFlags & GTF_DEBUG_NODE_CG_PRODUCED) == 0);
1676 tree->gtDebugFlags |= GTF_DEBUG_NODE_CG_PRODUCED;
1677#endif
1678
1679 if (tree->gtFlags & GTF_SPILL)
1680 {
1681 // Code for GT_COPY node gets generated as part of consuming regs by its parent.
1682 // A GT_COPY node in turn produces reg result and it should never be marked to
1683 // spill.
1684 //
1685 // Similarly GT_RELOAD node gets generated as part of consuming regs by its
1686 // parent and should never be marked for spilling.
1687 noway_assert(!tree->IsCopyOrReload());
1688
1689 if (genIsRegCandidateLocal(tree))
1690 {
1691 // Store local variable to its home location.
1692 // Ensure that lclVar stores are typed correctly.
1693 unsigned varNum = tree->gtLclVarCommon.gtLclNum;
1694 assert(!compiler->lvaTable[varNum].lvNormalizeOnStore() ||
1695 (tree->TypeGet() == genActualType(compiler->lvaTable[varNum].TypeGet())));
1696 inst_TT_RV(ins_Store(tree->gtType, compiler->isSIMDTypeLocalAligned(varNum)), tree, tree->gtRegNum);
1697 }
1698 else
1699 {
1700 // In case of multi-reg call node, spill flag on call node
1701 // indicates that one or more of its allocated regs need to
1702 // be spilled. Call node needs to be further queried to
1703 // know which of its result regs needs to be spilled.
1704 if (tree->IsMultiRegCall())
1705 {
1706 GenTreeCall* call = tree->AsCall();
1707 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
1708 unsigned regCount = retTypeDesc->GetReturnRegCount();
1709
1710 for (unsigned i = 0; i < regCount; ++i)
1711 {
1712 unsigned flags = call->GetRegSpillFlagByIdx(i);
1713 if ((flags & GTF_SPILL) != 0)
1714 {
1715 regNumber reg = call->GetRegNumByIdx(i);
1716 regSet.rsSpillTree(reg, call, i);
1717 gcInfo.gcMarkRegSetNpt(genRegMask(reg));
1718 }
1719 }
1720 }
1721#if FEATURE_ARG_SPLIT
1722 else if (tree->OperIsPutArgSplit())
1723 {
1724 GenTreePutArgSplit* argSplit = tree->AsPutArgSplit();
1725 unsigned regCount = argSplit->gtNumRegs;
1726
1727 for (unsigned i = 0; i < regCount; ++i)
1728 {
1729 unsigned flags = argSplit->GetRegSpillFlagByIdx(i);
1730 if ((flags & GTF_SPILL) != 0)
1731 {
1732 regNumber reg = argSplit->GetRegNumByIdx(i);
1733 regSet.rsSpillTree(reg, argSplit, i);
1734 gcInfo.gcMarkRegSetNpt(genRegMask(reg));
1735 }
1736 }
1737 }
1738#ifdef _TARGET_ARM_
1739 else if (tree->OperIsMultiRegOp())
1740 {
1741 GenTreeMultiRegOp* multiReg = tree->AsMultiRegOp();
1742 unsigned regCount = multiReg->GetRegCount();
1743
1744 for (unsigned i = 0; i < regCount; ++i)
1745 {
1746 unsigned flags = multiReg->GetRegSpillFlagByIdx(i);
1747 if ((flags & GTF_SPILL) != 0)
1748 {
1749 regNumber reg = multiReg->GetRegNumByIdx(i);
1750 regSet.rsSpillTree(reg, multiReg, i);
1751 gcInfo.gcMarkRegSetNpt(genRegMask(reg));
1752 }
1753 }
1754 }
1755#endif // _TARGET_ARM_
1756#endif // FEATURE_ARG_SPLIT
1757 else
1758 {
1759 regSet.rsSpillTree(tree->gtRegNum, tree);
1760 gcInfo.gcMarkRegSetNpt(genRegMask(tree->gtRegNum));
1761 }
1762
1763 tree->gtFlags |= GTF_SPILLED;
1764 tree->gtFlags &= ~GTF_SPILL;
1765
1766 return;
1767 }
1768 }
1769
1770 genUpdateLife(tree);
1771
1772 // If we've produced a register, mark it as a pointer, as needed.
1773 if (tree->gtHasReg())
1774 {
1775 // We only mark the register in the following cases:
1776 // 1. It is not a register candidate local. In this case, we're producing a
1777 // register from a local, but the local is not a register candidate. Thus,
1778 // we must be loading it as a temp register, and any "last use" flag on
1779 // the register wouldn't be relevant.
1780 // 2. The register candidate local is going dead. There's no point to mark
1781 // the register as live, with a GC pointer, if the variable is dead.
1782 if (!genIsRegCandidateLocal(tree) || ((tree->gtFlags & GTF_VAR_DEATH) == 0))
1783 {
1784 // Multi-reg call node will produce more than one register result.
1785 // Mark all the regs produced by call node.
1786 if (tree->IsMultiRegCall())
1787 {
1788 GenTreeCall* call = tree->AsCall();
1789 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
1790 unsigned regCount = retTypeDesc->GetReturnRegCount();
1791
1792 for (unsigned i = 0; i < regCount; ++i)
1793 {
1794 regNumber reg = call->GetRegNumByIdx(i);
1795 var_types type = retTypeDesc->GetReturnRegType(i);
1796 gcInfo.gcMarkRegPtrVal(reg, type);
1797 }
1798 }
1799 else if (tree->IsCopyOrReloadOfMultiRegCall())
1800 {
1801 // we should never see reload of multi-reg call here
1802 // because GT_RELOAD gets generated in reg consuming path.
1803 noway_assert(tree->OperGet() == GT_COPY);
1804
1805 // A multi-reg GT_COPY node produces those regs to which
1806 // copy has taken place.
1807 GenTreeCopyOrReload* copy = tree->AsCopyOrReload();
1808 GenTreeCall* call = copy->gtGetOp1()->AsCall();
1809 ReturnTypeDesc* retTypeDesc = call->GetReturnTypeDesc();
1810 unsigned regCount = retTypeDesc->GetReturnRegCount();
1811
1812 for (unsigned i = 0; i < regCount; ++i)
1813 {
1814 var_types type = retTypeDesc->GetReturnRegType(i);
1815 regNumber fromReg = call->GetRegNumByIdx(i);
1816 regNumber toReg = copy->GetRegNumByIdx(i);
1817
1818 if (toReg != REG_NA)
1819 {
1820 gcInfo.gcMarkRegPtrVal(toReg, type);
1821 }
1822 }
1823 }
1824 else
1825 {
1826 gcInfo.gcMarkRegPtrVal(tree->gtRegNum, tree->TypeGet());
1827 }
1828 }
1829 }
1830}
1831
1832// transfer gc/byref status of src reg to dst reg
1833void CodeGen::genTransferRegGCState(regNumber dst, regNumber src)
1834{
1835 regMaskTP srcMask = genRegMask(src);
1836 regMaskTP dstMask = genRegMask(dst);
1837
1838 if (gcInfo.gcRegGCrefSetCur & srcMask)
1839 {
1840 gcInfo.gcMarkRegSetGCref(dstMask);
1841 }
1842 else if (gcInfo.gcRegByrefSetCur & srcMask)
1843 {
1844 gcInfo.gcMarkRegSetByref(dstMask);
1845 }
1846 else
1847 {
1848 gcInfo.gcMarkRegSetNpt(dstMask);
1849 }
1850}
1851
1852// generates an ip-relative call or indirect call via reg ('call reg')
1853// pass in 'addr' for a relative call or 'base' for a indirect register call
1854// methHnd - optional, only used for pretty printing
1855// retSize - emitter type of return for GC purposes, should be EA_BYREF, EA_GCREF, or EA_PTRSIZE(not GC)
1856//
1857// clang-format off
1858void CodeGen::genEmitCall(int callType,
1859 CORINFO_METHOD_HANDLE methHnd,
1860 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
1861 void* addr
1862 X86_ARG(int argSize),
1863 emitAttr retSize
1864 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
1865 IL_OFFSETX ilOffset,
1866 regNumber base,
1867 bool isJump)
1868{
1869#if !defined(_TARGET_X86_)
1870 int argSize = 0;
1871#endif // !defined(_TARGET_X86_)
1872 getEmitter()->emitIns_Call(emitter::EmitCallType(callType),
1873 methHnd,
1874 INDEBUG_LDISASM_COMMA(sigInfo)
1875 addr,
1876 argSize,
1877 retSize
1878 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1879 gcInfo.gcVarPtrSetCur,
1880 gcInfo.gcRegGCrefSetCur,
1881 gcInfo.gcRegByrefSetCur,
1882 ilOffset, base, REG_NA, 0, 0, isJump);
1883}
1884// clang-format on
1885
1886// generates an indirect call via addressing mode (call []) given an indir node
1887// methHnd - optional, only used for pretty printing
1888// retSize - emitter type of return for GC purposes, should be EA_BYREF, EA_GCREF, or EA_PTRSIZE(not GC)
1889//
1890// clang-format off
1891void CodeGen::genEmitCall(int callType,
1892 CORINFO_METHOD_HANDLE methHnd,
1893 INDEBUG_LDISASM_COMMA(CORINFO_SIG_INFO* sigInfo)
1894 GenTreeIndir* indir
1895 X86_ARG(int argSize),
1896 emitAttr retSize
1897 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(emitAttr secondRetSize),
1898 IL_OFFSETX ilOffset)
1899{
1900#if !defined(_TARGET_X86_)
1901 int argSize = 0;
1902#endif // !defined(_TARGET_X86_)
1903 genConsumeAddress(indir->Addr());
1904
1905 getEmitter()->emitIns_Call(emitter::EmitCallType(callType),
1906 methHnd,
1907 INDEBUG_LDISASM_COMMA(sigInfo)
1908 nullptr,
1909 argSize,
1910 retSize
1911 MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize),
1912 gcInfo.gcVarPtrSetCur,
1913 gcInfo.gcRegGCrefSetCur,
1914 gcInfo.gcRegByrefSetCur,
1915 ilOffset,
1916 (indir->Base() != nullptr) ? indir->Base()->gtRegNum : REG_NA,
1917 (indir->Index() != nullptr) ? indir->Index()->gtRegNum : REG_NA,
1918 indir->Scale(),
1919 indir->Offset());
1920}
1921// clang-format on
1922
1923//------------------------------------------------------------------------
1924// genCodeForCast: Generates the code for GT_CAST.
1925//
1926// Arguments:
1927// tree - the GT_CAST node.
1928//
1929void CodeGen::genCodeForCast(GenTreeOp* tree)
1930{
1931 assert(tree->OperIs(GT_CAST));
1932
1933 var_types targetType = tree->TypeGet();
1934
1935 if (varTypeIsFloating(targetType) && varTypeIsFloating(tree->gtOp1))
1936 {
1937 // Casts float/double <--> double/float
1938 genFloatToFloatCast(tree);
1939 }
1940 else if (varTypeIsFloating(tree->gtOp1))
1941 {
1942 // Casts float/double --> int32/int64
1943 genFloatToIntCast(tree);
1944 }
1945 else if (varTypeIsFloating(targetType))
1946 {
1947 // Casts int32/uint32/int64/uint64 --> float/double
1948 genIntToFloatCast(tree);
1949 }
1950#ifndef _TARGET_64BIT_
1951 else if (varTypeIsLong(tree->gtOp1))
1952 {
1953 genLongToIntCast(tree);
1954 }
1955#endif // !_TARGET_64BIT_
1956 else
1957 {
1958 // Casts int <--> int
1959 genIntToIntCast(tree->AsCast());
1960 }
1961 // The per-case functions call genProduceReg()
1962}
1963
1964CodeGen::GenIntCastDesc::GenIntCastDesc(GenTreeCast* cast)
1965{
1966 const var_types srcType = genActualType(cast->gtGetOp1()->TypeGet());
1967 const bool srcUnsigned = cast->IsUnsigned();
1968 const unsigned srcSize = genTypeSize(srcType);
1969 const var_types castType = cast->gtCastType;
1970 const bool castUnsigned = varTypeIsUnsigned(castType);
1971 const unsigned castSize = genTypeSize(castType);
1972 const var_types dstType = genActualType(cast->TypeGet());
1973 const unsigned dstSize = genTypeSize(dstType);
1974 const bool overflow = cast->gtOverflow();
1975
1976 assert((srcSize == 4) || (srcSize == genTypeSize(TYP_I_IMPL)));
1977 assert((dstSize == 4) || (dstSize == genTypeSize(TYP_I_IMPL)));
1978
1979 assert(dstSize == genTypeSize(genActualType(castType)));
1980
1981 if (castSize < 4) // Cast to small int type
1982 {
1983 if (overflow)
1984 {
1985 m_checkKind = CHECK_SMALL_INT_RANGE;
1986 m_checkSrcSize = srcSize;
1987 // Since these are small int types we can compute the min and max
1988 // values of the castType without risk of integer overflow.
1989 const int castNumBits = (castSize * 8) - (castUnsigned ? 0 : 1);
1990 m_checkSmallIntMax = (1 << castNumBits) - 1;
1991 m_checkSmallIntMin = (castUnsigned | srcUnsigned) ? 0 : (-m_checkSmallIntMax - 1);
1992
1993 m_extendKind = COPY;
1994 m_extendSrcSize = dstSize;
1995 }
1996 else
1997 {
1998 m_checkKind = CHECK_NONE;
1999
2000 // Casting to a small type really means widening from that small type to INT/LONG.
2001 m_extendKind = castUnsigned ? ZERO_EXTEND_SMALL_INT : SIGN_EXTEND_SMALL_INT;
2002 m_extendSrcSize = castSize;
2003 }
2004 }
2005#ifdef _TARGET_64BIT_
2006 // castType cannot be (U)LONG on 32 bit targets, such casts should have been decomposed.
2007 // srcType cannot be a small int type since it's the "actual type" of the cast operand.
2008 // This means that widening casts do not occur on 32 bit targets.
2009 else if (castSize > srcSize) // (U)INT to (U)LONG widening cast
2010 {
2011 assert((srcSize == 4) && (castSize == 8));
2012
2013 if (overflow && !srcUnsigned && castUnsigned)
2014 {
2015 // Widening from INT to ULONG, check if the value is positive
2016 m_checkKind = CHECK_POSITIVE;
2017 m_checkSrcSize = 4;
2018
2019 // This is the only overflow checking cast that requires changing the
2020 // source value (by zero extending), all others copy the value as is.
2021 assert((srcType == TYP_INT) && (castType == TYP_ULONG));
2022 m_extendKind = ZERO_EXTEND_INT;
2023 m_extendSrcSize = 4;
2024 }
2025 else
2026 {
2027 m_checkKind = CHECK_NONE;
2028
2029 m_extendKind = srcUnsigned ? ZERO_EXTEND_INT : SIGN_EXTEND_INT;
2030 m_extendSrcSize = 4;
2031 }
2032 }
2033 else if (castSize < srcSize) // (U)LONG to (U)INT narrowing cast
2034 {
2035 assert((srcSize == 8) && (castSize == 4));
2036
2037 if (overflow)
2038 {
2039 if (castUnsigned) // (U)LONG to UINT cast
2040 {
2041 m_checkKind = CHECK_UINT_RANGE;
2042 }
2043 else if (srcUnsigned) // ULONG to INT cast
2044 {
2045 m_checkKind = CHECK_POSITIVE_INT_RANGE;
2046 }
2047 else // LONG to INT cast
2048 {
2049 m_checkKind = CHECK_INT_RANGE;
2050 }
2051
2052 m_checkSrcSize = 8;
2053 }
2054 else
2055 {
2056 m_checkKind = CHECK_NONE;
2057 }
2058
2059 m_extendKind = COPY;
2060 m_extendSrcSize = 4;
2061 }
2062#endif
2063 else // if (castSize == srcSize) // Sign changing or same type cast
2064 {
2065 assert(castSize == srcSize);
2066
2067 if (overflow && (srcUnsigned != castUnsigned))
2068 {
2069 m_checkKind = CHECK_POSITIVE;
2070 m_checkSrcSize = srcSize;
2071 }
2072 else
2073 {
2074 m_checkKind = CHECK_NONE;
2075 }
2076
2077 m_extendKind = COPY;
2078 m_extendSrcSize = srcSize;
2079 }
2080}
2081
2082#if !defined(_TARGET_64BIT_)
2083//------------------------------------------------------------------------
2084// genStoreLongLclVar: Generate code to store a non-enregistered long lclVar
2085//
2086// Arguments:
2087// treeNode - A TYP_LONG lclVar node.
2088//
2089// Return Value:
2090// None.
2091//
2092// Assumptions:
2093// 'treeNode' must be a TYP_LONG lclVar node for a lclVar that has NOT been promoted.
2094// Its operand must be a GT_LONG node.
2095//
2096void CodeGen::genStoreLongLclVar(GenTree* treeNode)
2097{
2098 emitter* emit = getEmitter();
2099
2100 GenTreeLclVarCommon* lclNode = treeNode->AsLclVarCommon();
2101 unsigned lclNum = lclNode->gtLclNum;
2102 LclVarDsc* varDsc = &(compiler->lvaTable[lclNum]);
2103 assert(varDsc->TypeGet() == TYP_LONG);
2104 assert(!varDsc->lvPromoted);
2105 GenTree* op1 = treeNode->gtOp.gtOp1;
2106
2107 // A GT_LONG is always contained, so it cannot have RELOAD or COPY inserted between it and its consumer,
2108 // but a MUL_LONG may.
2109 noway_assert(op1->OperIs(GT_LONG) || op1->gtSkipReloadOrCopy()->OperIs(GT_MUL_LONG));
2110 genConsumeRegs(op1);
2111
2112 if (op1->OperGet() == GT_LONG)
2113 {
2114 GenTree* loVal = op1->gtGetOp1();
2115 GenTree* hiVal = op1->gtGetOp2();
2116
2117 noway_assert((loVal->gtRegNum != REG_NA) && (hiVal->gtRegNum != REG_NA));
2118
2119 emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, loVal->gtRegNum, lclNum, 0);
2120 emit->emitIns_S_R(ins_Store(TYP_INT), EA_4BYTE, hiVal->gtRegNum, lclNum, genTypeSize(TYP_INT));
2121 }
2122 else
2123 {
2124 assert((op1->gtSkipReloadOrCopy()->gtFlags & GTF_MUL_64RSLT) != 0);
2125 // This is either a multi-reg MUL_LONG, or a multi-reg reload or copy.
2126 assert(op1->IsMultiRegNode() && (op1->GetMultiRegCount() == 2));
2127
2128 // Stack store
2129 emit->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), op1->GetRegByIndex(0), lclNum, 0);
2130 emit->emitIns_S_R(ins_Store(TYP_INT), emitTypeSize(TYP_INT), op1->GetRegByIndex(1), lclNum,
2131 genTypeSize(TYP_INT));
2132 }
2133}
2134#endif // !defined(_TARGET_64BIT_)
2135