@@ -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