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 | |
8 | class LclVarDsc; |
9 | |
10 | struct 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 | |
34 | public: |
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 | |
105 | private: |
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 | |