summaryrefslogtreecommitdiff
path: root/src/jit/register_arg_convention.h
blob: ad20b4a0f543c4ce0b692ebdb7281511d3441086 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef __register_arg_convention__
#define __register_arg_convention__

class LclVarDsc;

struct InitVarDscInfo
{
    LclVarDsc* varDsc;
    unsigned   varNum;

    unsigned intRegArgNum;
    unsigned floatRegArgNum;
    unsigned maxIntRegArgNum;
    unsigned maxFloatRegArgNum;

    bool hasRetBufArg;

#ifdef _TARGET_ARM_
    // Support back-filling of FP parameters. This is similar to code in gtMorphArgs() that
    // handles arguments.
    regMaskTP fltArgSkippedRegMask;
    bool      anyFloatStackArgs;
#endif // _TARGET_ARM_

#if FEATURE_FASTTAILCALL
    // It is used to calculate argument stack size information in byte
    unsigned stackArgSize;
    bool     hasMultiSlotStruct;
#endif // FEATURE_FASTTAILCALL

public:
    // set to initial values
    void Init(LclVarDsc* lvaTable, bool _hasRetBufArg)
    {
        hasRetBufArg      = _hasRetBufArg;
        varDsc            = &lvaTable[0]; // the first argument LclVar 0
        varNum            = 0;            // the first argument varNum 0
        intRegArgNum      = 0;
        floatRegArgNum    = 0;
        maxIntRegArgNum   = MAX_REG_ARG;
        maxFloatRegArgNum = MAX_FLOAT_REG_ARG;

#ifdef _TARGET_ARM_
        fltArgSkippedRegMask = RBM_NONE;
        anyFloatStackArgs    = false;
#endif // _TARGET_ARM_

#if FEATURE_FASTTAILCALL
        stackArgSize       = 0;
        hasMultiSlotStruct = false;
#endif // FEATURE_FASTTAILCALL
    }

    // return ref to current register arg for this type
    unsigned& regArgNum(var_types type)
    {
        return varTypeUsesFloatArgReg(type) ? floatRegArgNum : intRegArgNum;
    }

    // Allocate a set of contiguous argument registers. "type" is either an integer
    // type, indicating to use the integer registers, or a floating-point type, indicating
    // to use the floating-point registers. The actual type (TYP_FLOAT vs. TYP_DOUBLE) is
    // ignored. "numRegs" is the number of registers to allocate. Thus, on ARM, to allocate
    // a double-precision floating-point register, you need to pass numRegs=2. For an HFA,
    // pass the number of slots/registers needed.
    // This routine handles floating-point register back-filling on ARM.
    // Returns the first argument register of the allocated set.
    unsigned allocRegArg(var_types type, unsigned numRegs = 1);

#ifdef _TARGET_ARM_
    // We are aligning the register to an ABI-required boundary, such as putting
    // double-precision floats in even-numbered registers, by skipping one register.
    // "requiredRegAlignment" is the amount to align to: 1 for no alignment (everything
    // is 1-aligned), 2 for "double" alignment.
    // Returns the number of registers skipped.
    unsigned alignReg(var_types type, unsigned requiredRegAlignment);
#endif // _TARGET_ARM_

    // Return true if it is an enregisterable type and there is room.
    // Note that for "type", we only care if it is float or not. In particular,
    // "numRegs" must be "2" to allocate an ARM double-precision floating-point register.
    bool canEnreg(var_types type, unsigned numRegs = 1);

    // Set the fact that we have used up all remaining registers of 'type'
    //
    void setAllRegArgUsed(var_types type)
    {
        regArgNum(type) = maxRegArgNum(type);
    }

#ifdef _TARGET_ARM_

    void setAnyFloatStackArgs()
    {
        anyFloatStackArgs = true;
    }

    bool existAnyFloatStackArgs()
    {
        return anyFloatStackArgs;
    }

#endif // _TARGET_ARM_

private:
    // return max register arg for this type
    unsigned maxRegArgNum(var_types type)
    {
        return varTypeUsesFloatArgReg(type) ? maxFloatRegArgNum : maxIntRegArgNum;
    }

    bool enoughAvailRegs(var_types type, unsigned numRegs = 1);

    void nextReg(var_types type, unsigned numRegs = 1)
    {
        regArgNum(type) = min(regArgNum(type) + numRegs, maxRegArgNum(type));
    }
};

#endif // __register_arg_convention__