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#ifndef __register_arg_convention__
6#define __register_arg_convention__
7
8class LclVarDsc;
9
10struct InitVarDscInfo
11{
12 LclVarDsc* varDsc;
13 unsigned varNum;
14
15 unsigned intRegArgNum;
16 unsigned floatRegArgNum;
17 unsigned maxIntRegArgNum;
18 unsigned maxFloatRegArgNum;
19
20 bool hasRetBufArg;
21
22#ifdef _TARGET_ARM_
23 // Support back-filling of FP parameters. This is similar to code in gtMorphArgs() that
24 // handles arguments.
25 regMaskTP fltArgSkippedRegMask;
26 bool anyFloatStackArgs;
27#endif // _TARGET_ARM_
28
29#if FEATURE_FASTTAILCALL
30 // It is used to calculate argument stack size information in byte
31 unsigned stackArgSize;
32#endif // FEATURE_FASTTAILCALL
33
34public:
35 // set to initial values
36 void Init(LclVarDsc* lvaTable, bool _hasRetBufArg)
37 {
38 hasRetBufArg = _hasRetBufArg;
39 varDsc = &lvaTable[0]; // the first argument LclVar 0
40 varNum = 0; // the first argument varNum 0
41 intRegArgNum = 0;
42 floatRegArgNum = 0;
43 maxIntRegArgNum = MAX_REG_ARG;
44 maxFloatRegArgNum = MAX_FLOAT_REG_ARG;
45
46#ifdef _TARGET_ARM_
47 fltArgSkippedRegMask = RBM_NONE;
48 anyFloatStackArgs = false;
49#endif // _TARGET_ARM_
50
51#if FEATURE_FASTTAILCALL
52 stackArgSize = 0;
53#endif // FEATURE_FASTTAILCALL
54 }
55
56 // return ref to current register arg for this type
57 unsigned& regArgNum(var_types type)
58 {
59 return varTypeIsFloating(type) ? floatRegArgNum : intRegArgNum;
60 }
61
62 // Allocate a set of contiguous argument registers. "type" is either an integer
63 // type, indicating to use the integer registers, or a floating-point type, indicating
64 // to use the floating-point registers. The actual type (TYP_FLOAT vs. TYP_DOUBLE) is
65 // ignored. "numRegs" is the number of registers to allocate. Thus, on ARM, to allocate
66 // a double-precision floating-point register, you need to pass numRegs=2. For an HFA,
67 // pass the number of slots/registers needed.
68 // This routine handles floating-point register back-filling on ARM.
69 // Returns the first argument register of the allocated set.
70 unsigned allocRegArg(var_types type, unsigned numRegs = 1);
71
72 // We are aligning the register to an ABI-required boundary, such as putting
73 // double-precision floats in even-numbered registers, by skipping one register.
74 // "requiredRegAlignment" is the amount to align to: 1 for no alignment (everything
75 // is 1-aligned), 2 for "double" alignment.
76 // Returns the number of registers skipped.
77 unsigned alignReg(var_types type, unsigned requiredRegAlignment);
78
79 // Return true if it is an enregisterable type and there is room.
80 // Note that for "type", we only care if it is float or not. In particular,
81 // "numRegs" must be "2" to allocate an ARM double-precision floating-point register.
82 bool canEnreg(var_types type, unsigned numRegs = 1);
83
84 // Set the fact that we have used up all remaining registers of 'type'
85 //
86 void setAllRegArgUsed(var_types type)
87 {
88 regArgNum(type) = maxRegArgNum(type);
89 }
90
91#ifdef _TARGET_ARM_
92
93 void setAnyFloatStackArgs()
94 {
95 anyFloatStackArgs = true;
96 }
97
98 bool existAnyFloatStackArgs()
99 {
100 return anyFloatStackArgs;
101 }
102
103#endif // _TARGET_ARM_
104
105private:
106 // return max register arg for this type
107 unsigned maxRegArgNum(var_types type)
108 {
109 return varTypeIsFloating(type) ? maxFloatRegArgNum : maxIntRegArgNum;
110 }
111
112 bool enoughAvailRegs(var_types type, unsigned numRegs = 1);
113
114 void nextReg(var_types type, unsigned numRegs = 1)
115 {
116 regArgNum(type) = min(regArgNum(type) + numRegs, maxRegArgNum(type));
117 }
118};
119
120#endif // __register_arg_convention__
121