@@ -2765,6 +2765,115 @@ class AppleArm64SystemCallConvention : public CallingConvention
27652765 virtual bool IsEligibleForHeuristics () override { return false ; }
27662766};
27672767
2768+
2769+ // Swift calling convention for ARM64.
2770+ //
2771+ // The Swift ABI repurposes three callee-saved registers for implicit parameters:
2772+ // x20 - self (swiftself): context/self parameter, passed as the last integer argument
2773+ // x21 - error (swifterror): caller initializes to zero, callee sets to error pointer on throw
2774+ // x22 - async context (swiftasync): implicit async context for async functions
2775+ //
2776+ // Each combination of these three properties requires a distinct calling convention,
2777+ // since it changes which registers are arguments, callee-saved, or implicitly defined.
2778+ // The naming scheme is "swift" with optional suffixes: "-self", "-throws", "-async".
2779+ class SwiftArm64CallingConvention : public CallingConvention
2780+ {
2781+ bool m_hasSelf;
2782+ bool m_throws;
2783+ bool m_isAsync;
2784+
2785+ public:
2786+ SwiftArm64CallingConvention (Architecture* arch, const string& name, bool hasSelf, bool throws, bool isAsync)
2787+ : CallingConvention(arch, name), m_hasSelf(hasSelf), m_throws(throws), m_isAsync(isAsync)
2788+ {
2789+ }
2790+
2791+ virtual vector<uint32_t > GetIntegerArgumentRegisters () override
2792+ {
2793+ // Self goes first because our function types list self as the first
2794+ // parameter. Parameters are assigned to registers sequentially, so
2795+ // this ensures self -> x20 and remaining args -> x0-x7.
2796+ // Async context and error go last as implicit trailing registers.
2797+ vector<uint32_t > regs;
2798+ if (m_hasSelf)
2799+ regs.push_back (REG_X20);
2800+ regs.insert (regs.end (), {REG_X0, REG_X1, REG_X2, REG_X3, REG_X4, REG_X5, REG_X6, REG_X7});
2801+ if (m_isAsync)
2802+ regs.push_back (REG_X22);
2803+ if (m_throws)
2804+ regs.push_back (REG_X21);
2805+ return regs;
2806+ }
2807+
2808+ virtual vector<uint32_t > GetFloatArgumentRegisters () override
2809+ {
2810+ return vector<uint32_t > {REG_V0, REG_V1, REG_V2, REG_V3, REG_V4, REG_V5, REG_V6, REG_V7};
2811+ }
2812+
2813+ virtual vector<uint32_t > GetCallerSavedRegisters () override
2814+ {
2815+ vector<uint32_t > regs {REG_X0, REG_X1, REG_X2, REG_X3, REG_X4, REG_X5, REG_X6, REG_X7, REG_X8,
2816+ REG_X9, REG_X10, REG_X11, REG_X12, REG_X13, REG_X14, REG_X15, REG_X16, REG_X17, REG_X18,
2817+ REG_X30, REG_V0, REG_V1, REG_V2, REG_V3, REG_V4, REG_V5, REG_V6, REG_V7, REG_V16, REG_V17,
2818+ REG_V18, REG_V19, REG_V20, REG_V21, REG_V22, REG_V23, REG_V24, REG_V25, REG_V26, REG_V27,
2819+ REG_V28, REG_V29, REG_V30, REG_V31};
2820+ // When used as special registers, they are no longer callee-saved.
2821+ if (m_hasSelf)
2822+ regs.push_back (REG_X20);
2823+ if (m_throws)
2824+ regs.push_back (REG_X21);
2825+ if (m_isAsync)
2826+ regs.push_back (REG_X22);
2827+ return regs;
2828+ }
2829+
2830+ virtual vector<uint32_t > GetCalleeSavedRegisters () override
2831+ {
2832+ vector<uint32_t > regs {REG_X19, REG_X23, REG_X24, REG_X25, REG_X26, REG_X27, REG_X28, REG_X29};
2833+ // Only include x20/x21/x22 as callee-saved when they are NOT repurposed.
2834+ if (!m_hasSelf)
2835+ regs.push_back (REG_X20);
2836+ if (!m_throws)
2837+ regs.push_back (REG_X21);
2838+ if (!m_isAsync)
2839+ regs.push_back (REG_X22);
2840+ return regs;
2841+ }
2842+
2843+ virtual vector<uint32_t > GetImplicitlyDefinedRegisters () override
2844+ {
2845+ vector<uint32_t > regs;
2846+ // Throwing functions implicitly define x21 (the error register) on return.
2847+ if (m_throws)
2848+ regs.push_back (REG_X21);
2849+ return regs;
2850+ }
2851+
2852+ virtual uint32_t GetIntegerReturnValueRegister () override { return REG_X0; }
2853+
2854+ virtual uint32_t GetFloatReturnValueRegister () override { return REG_V0; }
2855+
2856+ virtual vector<uint32_t > GetRequiredArgumentRegisters () override
2857+ {
2858+ vector<uint32_t > regs;
2859+ if (m_hasSelf)
2860+ regs.push_back (REG_X20);
2861+ if (m_throws)
2862+ regs.push_back (REG_X21);
2863+ if (m_isAsync)
2864+ regs.push_back (REG_X22);
2865+ return regs;
2866+ }
2867+
2868+ virtual bool AreArgumentRegistersUsedForVarArgs () override { return false ; }
2869+
2870+ virtual bool IsEligibleForHeuristics () override
2871+ {
2872+ return m_hasSelf || m_throws || m_isAsync;
2873+ }
2874+ };
2875+
2876+
27682877#define PAGE (x ) (uint32_t )((x) >> 12 )
27692878#define PAGE_OFF (x ) (uint32_t )((x)&0xfff )
27702879#define PAGE_NO_OFF (x ) (uint32_t )((x)&0xFFFFF000 )
@@ -3550,6 +3659,20 @@ extern "C"
35503659 conv = new AppleArm64CallingConvention (arm64);
35513660 arm64->RegisterCallingConvention (conv);
35523661
3662+ // Register Swift calling conventions (all combinations of self/throws/async).
3663+ for (int swiftFlags = 0 ; swiftFlags < 8 ; swiftFlags++)
3664+ {
3665+ bool hasSelf = (swiftFlags & 1 ) != 0 ;
3666+ bool throws = (swiftFlags & 2 ) != 0 ;
3667+ bool isAsync = (swiftFlags & 4 ) != 0 ;
3668+ string name = " swift" ;
3669+ if (hasSelf) name += " -self" ;
3670+ if (throws) name += " -throws" ;
3671+ if (isAsync) name += " -async" ;
3672+ conv = new SwiftArm64CallingConvention (arm64, name, hasSelf, throws, isAsync);
3673+ arm64->RegisterCallingConvention (conv);
3674+ }
3675+
35533676 for (uint32_t i = REG_X0; i <= REG_X28; i++)
35543677 {
35553678 if (i == REG_X16 || i == REG_X17 || i == REG_X18) // reserved by os.
0 commit comments