| 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 | #include "jitpch.h" |
| 6 | #ifdef _MSC_VER |
| 7 | #pragma hdrstop |
| 8 | #endif |
| 9 | |
| 10 | #include "register_arg_convention.h" |
| 11 | |
| 12 | unsigned InitVarDscInfo::allocRegArg(var_types type, unsigned numRegs /* = 1 */) |
| 13 | { |
| 14 | assert(numRegs > 0); |
| 15 | |
| 16 | unsigned resultArgNum = regArgNum(type); |
| 17 | bool isBackFilled = false; |
| 18 | |
| 19 | #ifdef _TARGET_ARM_ |
| 20 | // Check for back-filling |
| 21 | if (varTypeIsFloating(type) && // We only back-fill the float registers |
| 22 | !anyFloatStackArgs && // Is it legal to back-fill? (We haven't put any FP args on the stack yet) |
| 23 | (numRegs == 1) && // Is there a possibility we could back-fill? |
| 24 | (fltArgSkippedRegMask != RBM_NONE)) // Is there an available back-fill slot? |
| 25 | { |
| 26 | // We will never back-fill something greater than a single register |
| 27 | // (TYP_FLOAT, or TYP_STRUCT HFA with a single float). This is because |
| 28 | // we don't have any types that require > 2 register alignment, so we |
| 29 | // can't create a > 1 register alignment hole to back-fill. |
| 30 | |
| 31 | // Back-fill the register |
| 32 | regMaskTP backFillBitMask = genFindLowestBit(fltArgSkippedRegMask); |
| 33 | fltArgSkippedRegMask &= ~backFillBitMask; // Remove the back-filled register(s) from the skipped mask |
| 34 | resultArgNum = genMapFloatRegNumToRegArgNum(genRegNumFromMask(backFillBitMask)); |
| 35 | assert(resultArgNum < MAX_FLOAT_REG_ARG); |
| 36 | isBackFilled = true; |
| 37 | } |
| 38 | #endif // _TARGET_ARM_ |
| 39 | |
| 40 | if (!isBackFilled) |
| 41 | { |
| 42 | #if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI) |
| 43 | // For System V the reg type counters should be independent. |
| 44 | nextReg(TYP_INT, numRegs); |
| 45 | nextReg(TYP_FLOAT, numRegs); |
| 46 | #else |
| 47 | // We didn't back-fill a register (on ARM), so skip the number of registers that we allocated. |
| 48 | nextReg(type, numRegs); |
| 49 | #endif |
| 50 | } |
| 51 | |
| 52 | return resultArgNum; |
| 53 | } |
| 54 | |
| 55 | bool InitVarDscInfo::enoughAvailRegs(var_types type, unsigned numRegs /* = 1 */) |
| 56 | { |
| 57 | assert(numRegs > 0); |
| 58 | |
| 59 | unsigned backFillCount = 0; |
| 60 | |
| 61 | #ifdef _TARGET_ARM_ |
| 62 | // Check for back-filling |
| 63 | if (varTypeIsFloating(type) && // We only back-fill the float registers |
| 64 | !anyFloatStackArgs && // Is it legal to back-fill? (We haven't put any FP args on the stack yet) |
| 65 | (numRegs == 1) && // Is there a possibility we could back-fill? |
| 66 | (fltArgSkippedRegMask != RBM_NONE)) // Is there an available back-fill slot? |
| 67 | { |
| 68 | backFillCount = 1; |
| 69 | } |
| 70 | #endif // _TARGET_ARM_ |
| 71 | |
| 72 | return regArgNum(type) + numRegs - backFillCount <= maxRegArgNum(type); |
| 73 | } |
| 74 | |
| 75 | unsigned InitVarDscInfo::alignReg(var_types type, unsigned requiredRegAlignment) |
| 76 | { |
| 77 | NYI_ARM64("alignReg" ); |
| 78 | |
| 79 | assert(requiredRegAlignment > 0); |
| 80 | if (requiredRegAlignment == 1) |
| 81 | { |
| 82 | return 0; // Everything is always "1" aligned |
| 83 | } |
| 84 | |
| 85 | assert(requiredRegAlignment == 2); // we don't expect anything else right now |
| 86 | |
| 87 | int alignMask = regArgNum(type) & (requiredRegAlignment - 1); |
| 88 | if (alignMask == 0) |
| 89 | { |
| 90 | return 0; // We're already aligned |
| 91 | } |
| 92 | |
| 93 | unsigned cAlignSkipped = requiredRegAlignment - alignMask; |
| 94 | assert(cAlignSkipped == 1); // Alignment is currently only 1 or 2, so misalignment can only be 1. |
| 95 | |
| 96 | #ifdef _TARGET_ARM_ |
| 97 | if (varTypeIsFloating(type)) |
| 98 | { |
| 99 | fltArgSkippedRegMask |= genMapFloatRegArgNumToRegMask(floatRegArgNum); |
| 100 | } |
| 101 | #endif // _TARGET_ARM_ |
| 102 | |
| 103 | assert(regArgNum(type) + cAlignSkipped <= maxRegArgNum(type)); // if equal, then we aligned the last slot, and the |
| 104 | // arg can't be enregistered |
| 105 | regArgNum(type) += cAlignSkipped; |
| 106 | |
| 107 | return cAlignSkipped; |
| 108 | } |
| 109 | |
| 110 | bool InitVarDscInfo::canEnreg(var_types type, unsigned numRegs /* = 1 */) |
| 111 | { |
| 112 | if (!isRegParamType(type)) |
| 113 | { |
| 114 | return false; |
| 115 | } |
| 116 | |
| 117 | if (!enoughAvailRegs(type, numRegs)) |
| 118 | { |
| 119 | return false; |
| 120 | } |
| 121 | |
| 122 | return true; |
| 123 | } |
| 124 | |