Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2334,6 +2334,16 @@ RetAttrs.addAttribute(llvm::Attribute::NoUndef); } + auto AddArm64ECArgSize = [this](QualType Ty, llvm::AttrBuilder &Attrs) { + if (Ty->isRecordType()) { + CharUnits SizeInBytes = getContext().getTypeSizeInChars(Ty.getTypePtr()); + Attrs.addArm64ECArgSizeAttr(SizeInBytes.getQuantity()); + } + }; + + if (getTriple().isWindowsArm64EC()) + AddArm64ECArgSize(RetTy, RetAttrs); + switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetAI.isSignExt()) @@ -2467,6 +2477,9 @@ Attrs.addAttribute(llvm::Attribute::NoUndef); } + if (getTriple().isWindowsArm64EC()) + AddArm64ECArgSize(ParamType, Attrs); + // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make // sense to do it here because parameters are so messed up. Index: clang/test/CodeGenCXX/arm64ec-mangle-align.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/arm64ec-mangle-align.cpp @@ -0,0 +1,180 @@ +// RUN: %clang_cc1 %s -triple=arm64ec-pc-windows-msvc -emit-llvm -fms-compatibility -o - | FileCheck %s + +#pragma pack(push, 1) + +struct __declspec(align(1)) s1 { + char a[1]; +}; +s1 (*pfnstruct1)(s1 x); +s1 callstruct1(s1 x) { return pfnstruct1(x); }; +struct __declspec(align(8)) s2 { + char a[2]; +}; +s2 (*pfnstruct2)(s2 x); +s2 callstruct2(s2 x) { return pfnstruct2(x); }; +struct __declspec(align(64)) s3 { + char a[3]; +}; +s3 (*pfnstruct3)(s3 x); +s3 callstruct3(s3 x) { return pfnstruct3(x); }; +struct __declspec(align(32)) s4 { + char a[4]; +}; +s4 (*pfnstruct4)(s4 x); +s4 callstruct4(s4 x) { return pfnstruct4(x); }; +struct __declspec(align(2)) s5 { + char a[5]; +}; +s5 (*pfnstruct5)(s5 x); +s5 callstruct5(s5 x) { return pfnstruct5(x); }; +struct __declspec(align(4)) s6 { + char a[6]; +}; +s6 (*pfnstruct6)(s6 x); +s6 callstruct6(s6 x) { return pfnstruct6(x); }; +struct __declspec(align(8)) s7 { + char a[7]; +}; +s7 (*pfnstruct7)(s7 x); +s7 callstruct7(s7 x) { return pfnstruct7(x); }; +struct __declspec(align(16)) s8 { + char a[8]; +}; +s8 (*pfnstruct8)(s8 x); +s8 callstruct8(s8 x) { return pfnstruct8(x); }; +struct __declspec(align(4)) s9 { + char a[9]; +}; +s9 (*pfnstruct9)(s9 x); +s9 callstruct9(s9 x) { return pfnstruct9(x); }; +struct __declspec(align(2)) s10 { + char a[10]; +}; +s10 (*pfnstruct10)(s10 x); +s10 callstruct10(s10 x) { return pfnstruct10(x); }; +struct __declspec(align(1)) s11 { + char a[11]; +}; +s11 (*pfnstruct11)(s11 x); +s11 callstruct11(s11 x) { return pfnstruct11(x); }; +struct __declspec(align(64)) s12 { + char a[12]; +}; +s12 (*pfnstruct12)(s12 x); +s12 callstruct12(s12 x) { return pfnstruct12(x); }; +struct __declspec(align(8)) s13 { + char a[13]; +}; +s13 (*pfnstruct13)(s13 x); +s13 callstruct13(s13 x) { return pfnstruct13(x); }; +struct __declspec(align(4)) s14 { + char a[14]; +}; +s14 (*pfnstruct14)(s14 x); +s14 callstruct14(s14 x) { return pfnstruct14(x); }; +struct __declspec(align(16)) s15 { + char a[15]; +}; +s15 (*pfnstruct15)(s15 x); +s15 callstruct15(s15 x) { return pfnstruct15(x); }; +struct __declspec(align(32)) s16 { + char a[16]; +}; +s16 (*pfnstruct16)(s16 x); +s16 callstruct16(s16 x) { return pfnstruct16(x); }; +struct __declspec(align(64)) s17 { + char a[17]; +}; +s17 (*pfnstruct17)(s17 x); +s17 callstruct17(s17 x) { return pfnstruct17(x); }; +struct __declspec(align(4)) s33 { + char a[33]; +}; +s33 (*pfnstruct33)(s33 x); +s33 callstruct33(s33 x) { return pfnstruct33(x); }; +struct __declspec(align(2)) s65 { + char a[65]; +}; +s65 (*pfnstruct65)(s65 x); +s65 callstruct65(s65 x) { return pfnstruct65(x); }; +struct __declspec(align(16)) s129 { + char a[129]; +}; +s129 (*pfnstruct129)(s129 x); +s129 callstruct129(s129 x) { return pfnstruct129(x); }; +struct __declspec(align(32)) s257 { + char a[257]; +}; +s257 (*pfnstruct257)(s257 x); +s257 callstruct257(s257 x) { return pfnstruct257(x); }; +struct __declspec(align(8)) f2 { + float a[2]; +}; +f2 (*pfnstructf2)(f2 x); +f2 callstructf2(f2 x) { return pfnstructf2(x); }; +struct __declspec(align(64)) f3 { + float a[3]; +}; +f3 (*pfnstructf3)(f3 x); +f3 callstructf3(f3 x) { return pfnstructf3(x); }; +struct __declspec(align(32)) f4 { + float a[4]; +}; +f4 (*pfnstructf4)(f4 x); +f4 callstructf4(f4 x) { return pfnstructf4(x); }; +struct __declspec(align(32)) f5 { + float a[5]; +}; +f5 (*pfnstructf5)(f5 x); +f5 callstructf5(f5 x) { return pfnstructf5(x); }; +struct __declspec(align(64)) d2 { + double a[2]; +}; +d2 (*pfnstructd2)(d2 x); +d2 callstructd2(d2 x) { return pfnstructd2(x); }; +struct __declspec(align(64)) d3 { + double a[3]; +}; +d3 (*pfnstructd3)(d3 x); +d3 callstructd3(d3 x) { return pfnstructd3(x); }; +struct __declspec(align(16)) d4 { + double a[4]; +}; +d4 (*pfnstructd4)(d4 x); +d4 callstructd4(d4 x) { return pfnstructd4(x); }; +struct __declspec(align(16)) d5 { + double a[5]; +}; +d5 (*pfnstructd5)(d5 x); +d5 callstructd5(d5 x) { return pfnstructd5(x); }; +#pragma pack(pop) + +// CHECK: define dso_local arm64ec_argsize(1) i8 @"?callstruct1@@$$hYA?AUs1@@U1@@Z"(i64 arm64ec_argsize(1) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(8) i64 @"?callstruct2@@$$hYA?AUs2@@U1@@Z"(i64 arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstruct3@@$$hYA?AUs3@@U1@@Z"(ptr noalias sret(%struct.s3) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(32) void @"?callstruct4@@$$hYA?AUs4@@U1@@Z"(ptr noalias sret(%struct.s4) align 32 %agg.result, ptr noundef arm64ec_argsize(32) %x) +// CHECK: define dso_local arm64ec_argsize(6) i48 @"?callstruct5@@$$hYA?AUs5@@U1@@Z"(i64 arm64ec_argsize(6) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(8) i64 @"?callstruct6@@$$hYA?AUs6@@U1@@Z"(i64 arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(8) i64 @"?callstruct7@@$$hYA?AUs7@@U1@@Z"(i64 arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(16) i128 @"?callstruct8@@$$hYA?AUs8@@U1@@Z"(i128 arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(12) [2 x i64] @"?callstruct9@@$$hYA?AUs9@@U1@@Z"([2 x i64] arm64ec_argsize(12) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(10) [2 x i64] @"?callstruct10@@$$hYA?AUs10@@U1@@Z"([2 x i64] arm64ec_argsize(10) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(11) [2 x i64] @"?callstruct11@@$$hYA?AUs11@@U1@@Z"([2 x i64] arm64ec_argsize(11) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstruct12@@$$hYA?AUs12@@U1@@Z"(ptr noalias sret(%struct.s12) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(16) [2 x i64] @"?callstruct13@@$$hYA?AUs13@@U1@@Z"([2 x i64] arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(16) [2 x i64] @"?callstruct14@@$$hYA?AUs14@@U1@@Z"([2 x i64] arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(16) i128 @"?callstruct15@@$$hYA?AUs15@@U1@@Z"(i128 arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(32) void @"?callstruct16@@$$hYA?AUs16@@U1@@Z"(ptr noalias sret(%struct.s16) align 32 %agg.result, ptr noundef arm64ec_argsize(32) %x) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstruct17@@$$hYA?AUs17@@U1@@Z"(ptr noalias sret(%struct.s17) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(36) void @"?callstruct33@@$$hYA?AUs33@@U1@@Z"(ptr noalias sret(%struct.s33) align 4 %agg.result, ptr noundef arm64ec_argsize(36) %x) +// CHECK: define dso_local arm64ec_argsize(66) void @"?callstruct65@@$$hYA?AUs65@@U1@@Z"(ptr noalias sret(%struct.s65) align 2 %agg.result, ptr noundef arm64ec_argsize(66) %x) +// CHECK: define dso_local arm64ec_argsize(144) void @"?callstruct129@@$$hYA?AUs129@@U1@@Z"(ptr noalias sret(%struct.s129) align 16 %agg.result, ptr noundef arm64ec_argsize(144) %x) +// CHECK: define dso_local arm64ec_argsize(288) void @"?callstruct257@@$$hYA?AUs257@@U1@@Z"(ptr noalias sret(%struct.s257) align 32 %agg.result, ptr noundef arm64ec_argsize(288) %x) +// CHECK: define dso_local arm64ec_argsize(8) %struct.f2 @"?callstructf2@@$$hYA?AUf2@@U1@@Z"([2 x float] arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstructf3@@$$hYA?AUf3@@U1@@Z"(ptr noalias sret(%struct.f3) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(32) void @"?callstructf4@@$$hYA?AUf4@@U1@@Z"(ptr noalias sret(%struct.f4) align 32 %agg.result, ptr noundef arm64ec_argsize(32) %x) +// CHECK: define dso_local arm64ec_argsize(32) void @"?callstructf5@@$$hYA?AUf5@@U1@@Z"(ptr noalias sret(%struct.f5) align 32 %agg.result, ptr noundef arm64ec_argsize(32) %x) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstructd2@@$$hYA?AUd2@@U1@@Z"(ptr noalias sret(%struct.d2) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstructd3@@$$hYA?AUd3@@U1@@Z"(ptr noalias sret(%struct.d3) align 64 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(32) %struct.d4 @"?callstructd4@@$$hYA?AUd4@@U1@@Z"([4 x double] arm64ec_argsize(32) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(48) void @"?callstructd5@@$$hYA?AUd5@@U1@@Z"(ptr noalias sret(%struct.d5) align 16 %agg.result, ptr noundef arm64ec_argsize(48) %x) Index: clang/test/CodeGenCXX/arm64ec-mangle-basic.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/arm64ec-mangle-basic.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -triple=arm64ec-pc-windows-msvc -emit-llvm -fms-compatibility -o - | FileCheck %s + +#pragma pack(push, 1) +typedef long long i64; +typedef long double longdouble; +typedef void *VOIDP; +bool (*pfnbool)(bool x); +bool callbool(bool x) { return pfnbool(x); }; +char (*pfnchar)(char x); +char callchar(char x) { return pfnchar(x); }; +short (*pfnshort)(short x); +short callshort(short x) { return pfnshort(x); }; +wchar_t (*pfnwchar_t)(wchar_t x); +wchar_t callwchar_t(wchar_t x) { return pfnwchar_t(x); }; +int (*pfnint)(int x); +int callint(int x) { return pfnint(x); }; +i64 (*pfni64)(i64 x); +i64 calli64(i64 x) { return pfni64(x); }; +float (*pfnfloat)(float x); +float callfloat(float x) { return pfnfloat(x); }; +double (*pfndouble)(double x); +double calldouble(double x) { return pfndouble(x); }; +longdouble (*pfnlongdouble)(longdouble x); +longdouble calllongdouble(longdouble x) { return pfnlongdouble(x); }; +VOIDP (*pfnVOIDP)(VOIDP x); +VOIDP callVOIDP(VOIDP x) { return pfnVOIDP(x); }; +#pragma pack(pop) + +// CHECK: define dso_local noundef i1 @"?callbool@@$$hYA_N_N@Z"(i1 noundef %x) +// CHECK: define dso_local noundef i8 @"?callchar@@$$hYADD@Z"(i8 noundef %x) +// CHECK: define dso_local noundef i16 @"?callshort@@$$hYAFF@Z"(i16 noundef %x) +// CHECK: define dso_local noundef i16 @"?callwchar_t@@$$hYA_W_W@Z"(i16 noundef %x) +// CHECK: define dso_local noundef i32 @"?callint@@$$hYAHH@Z"(i32 noundef %x) +// CHECK: define dso_local noundef i64 @"?calli64@@$$hYA_J_J@Z"(i64 noundef %x) +// CHECK: define dso_local noundef float @"?callfloat@@$$hYAMM@Z"(float noundef %x) +// CHECK: define dso_local noundef double @"?calldouble@@$$hYANN@Z"(double noundef %x) +// CHECK: define dso_local noundef double @"?calllongdouble@@$$hYAOO@Z"(double noundef %x) +// CHECK: define dso_local noundef ptr @"?callVOIDP@@$$hYAPEAXPEAX@Z"(ptr noundef %x) Index: clang/test/CodeGenCXX/arm64ec-mangle-struct.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/arm64ec-mangle-struct.cpp @@ -0,0 +1,215 @@ +// RUN: %clang_cc1 %s -triple=arm64ec-pc-windows-msvc -emit-llvm -fms-compatibility -o - | FileCheck %s + +#pragma pack(push, 1) +struct s1 { + char a[1]; +}; +s1 (*pfnstruct1)(s1 x); +s1 callstruct1(s1 x) { return pfnstruct1(x); }; +struct s2 { + char a[2]; +}; +s2 (*pfnstruct2)(s2 x); +s2 callstruct2(s2 x) { return pfnstruct2(x); }; +struct s3 { + char a[3]; +}; +s3 (*pfnstruct3)(s3 x); +s3 callstruct3(s3 x) { return pfnstruct3(x); }; +struct s4 { + char a[4]; +}; +s4 (*pfnstruct4)(s4 x); +s4 callstruct4(s4 x) { return pfnstruct4(x); }; +struct s5 { + char a[5]; +}; +s5 (*pfnstruct5)(s5 x); +s5 callstruct5(s5 x) { return pfnstruct5(x); }; +struct s6 { + char a[6]; +}; +s6 (*pfnstruct6)(s6 x); +s6 callstruct6(s6 x) { return pfnstruct6(x); }; +struct s7 { + char a[7]; +}; +s7 (*pfnstruct7)(s7 x); +s7 callstruct7(s7 x) { return pfnstruct7(x); }; +struct s8 { + char a[8]; +}; +s8 (*pfnstruct8)(s8 x); +s8 callstruct8(s8 x) { return pfnstruct8(x); }; +struct s9 { + char a[9]; +}; +s9 (*pfnstruct9)(s9 x); +s9 callstruct9(s9 x) { return pfnstruct9(x); }; +struct s10 { + char a[10]; +}; +s10 (*pfnstruct10)(s10 x); +s10 callstruct10(s10 x) { return pfnstruct10(x); }; +struct s11 { + char a[11]; +}; +s11 (*pfnstruct11)(s11 x); +s11 callstruct11(s11 x) { return pfnstruct11(x); }; +struct s12 { + char a[12]; +}; +s12 (*pfnstruct12)(s12 x); +s12 callstruct12(s12 x) { return pfnstruct12(x); }; +struct s13 { + char a[13]; +}; +s13 (*pfnstruct13)(s13 x); +s13 callstruct13(s13 x) { return pfnstruct13(x); }; +struct s14 { + char a[14]; +}; +s14 (*pfnstruct14)(s14 x); +s14 callstruct14(s14 x) { return pfnstruct14(x); }; +struct s15 { + char a[15]; +}; +s15 (*pfnstruct15)(s15 x); +s15 callstruct15(s15 x) { return pfnstruct15(x); }; +struct s16 { + char a[16]; +}; +s16 (*pfnstruct16)(s16 x); +s16 callstruct16(s16 x) { return pfnstruct16(x); }; +struct s17 { + char a[17]; +}; +s17 (*pfnstruct17)(s17 x); +s17 callstruct17(s17 x) { return pfnstruct17(x); }; +struct s32 { + char a[32]; +}; +s32 (*pfnstruct32)(s32 x); +s32 callstruct32(s32 x) { return pfnstruct32(x); }; +struct s33 { + char a[33]; +}; +s33 (*pfnstruct33)(s33 x); +s33 callstruct33(s33 x) { return pfnstruct33(x); }; +struct s64 { + char a[64]; +}; +s64 (*pfnstruct64)(s64 x); +s64 callstruct64(s64 x) { return pfnstruct64(x); }; +struct s65 { + char a[65]; +}; +s65 (*pfnstruct65)(s65 x); +s65 callstruct65(s65 x) { return pfnstruct65(x); }; +struct s128 { + char a[128]; +}; +s128 (*pfnstruct128)(s128 x); +s128 callstruct128(s128 x) { return pfnstruct128(x); }; +struct s133 { + char a[133]; +}; +s133 (*pfnstruct133)(s133 x); +s133 callstruct133(s133 x) { return pfnstruct133(x); }; +struct s192 { + char a[192]; +}; +s192 (*pfnstruct192)(s192 x); +s192 callstruct192(s192 x) { return pfnstruct192(x); }; +struct s223 { + char a[223]; +}; +s223 (*pfnstruct223)(s223 x); +s223 callstruct223(s223 x) { return pfnstruct223(x); }; +struct s256 { + char a[256]; +}; +s256 (*pfnstruct256)(s256 x); +s256 callstruct256(s256 x) { return pfnstruct256(x); }; +struct s257 { + char a[257]; +}; +s257 (*pfnstruct257)(s257 x); +s257 callstruct257(s257 x) { return pfnstruct257(x); }; +struct f2 { + float a[2]; +}; +f2 (*pfnstructf2)(f2 x); +f2 callstructf2(f2 x) { return pfnstructf2(x); }; +struct f3 { + float a[3]; +}; +f3 (*pfnstructf3)(f3 x); +f3 callstructf3(f3 x) { return pfnstructf3(x); }; +struct f4 { + float a[4]; +}; +f4 (*pfnstructf4)(f4 x); +f4 callstructf4(f4 x) { return pfnstructf4(x); }; +struct f5 { + float a[5]; +}; +f5 (*pfnstructf5)(f5 x); +f5 callstructf5(f5 x) { return pfnstructf5(x); }; +struct d2 { + double a[2]; +}; +d2 (*pfnstructd2)(d2 x); +d2 callstructd2(d2 x) { return pfnstructd2(x); }; +struct d3 { + double a[3]; +}; +d3 (*pfnstructd3)(d3 x); +d3 callstructd3(d3 x) { return pfnstructd3(x); }; +struct d4 { + double a[4]; +}; +d4 (*pfnstructd4)(d4 x); +d4 callstructd4(d4 x) { return pfnstructd4(x); }; +struct d5 { + double a[5]; +}; +d5 (*pfnstructd5)(d5 x); +d5 callstructd5(d5 x) { return pfnstructd5(x); }; +#pragma pack(pop) + +// CHECK: define dso_local arm64ec_argsize(1) i8 @"?callstruct1@@$$hYA?AUs1@@U1@@Z"(i64 arm64ec_argsize(1) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(2) i16 @"?callstruct2@@$$hYA?AUs2@@U1@@Z"(i64 arm64ec_argsize(2) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(3) i24 @"?callstruct3@@$$hYA?AUs3@@U1@@Z"(i64 arm64ec_argsize(3) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(4) i32 @"?callstruct4@@$$hYA?AUs4@@U1@@Z"(i64 arm64ec_argsize(4) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(5) i40 @"?callstruct5@@$$hYA?AUs5@@U1@@Z"(i64 arm64ec_argsize(5) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(6) i48 @"?callstruct6@@$$hYA?AUs6@@U1@@Z"(i64 arm64ec_argsize(6) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(7) i56 @"?callstruct7@@$$hYA?AUs7@@U1@@Z"(i64 arm64ec_argsize(7) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(8) i64 @"?callstruct8@@$$hYA?AUs8@@U1@@Z"(i64 arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(9) [2 x i64] @"?callstruct9@@$$hYA?AUs9@@U1@@Z"([2 x i64] arm64ec_argsize(9) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(10) [2 x i64] @"?callstruct10@@$$hYA?AUs10@@U1@@Z"([2 x i64] arm64ec_argsize(10) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(11) [2 x i64] @"?callstruct11@@$$hYA?AUs11@@U1@@Z"([2 x i64] arm64ec_argsize(11) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(12) [2 x i64] @"?callstruct12@@$$hYA?AUs12@@U1@@Z"([2 x i64] arm64ec_argsize(12) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(13) [2 x i64] @"?callstruct13@@$$hYA?AUs13@@U1@@Z"([2 x i64] arm64ec_argsize(13) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(14) [2 x i64] @"?callstruct14@@$$hYA?AUs14@@U1@@Z"([2 x i64] arm64ec_argsize(14) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(15) [2 x i64] @"?callstruct15@@$$hYA?AUs15@@U1@@Z"([2 x i64] arm64ec_argsize(15) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(16) [2 x i64] @"?callstruct16@@$$hYA?AUs16@@U1@@Z"([2 x i64] arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(17) void @"?callstruct17@@$$hYA?AUs17@@U1@@Z"(ptr noalias sret(%struct.s17) align 1 %agg.result, ptr noundef arm64ec_argsize(17) %x) +// CHECK: define dso_local arm64ec_argsize(32) void @"?callstruct32@@$$hYA?AUs32@@U1@@Z"(ptr noalias sret(%struct.s32) align 1 %agg.result, ptr noundef arm64ec_argsize(32) %x) +// CHECK: define dso_local arm64ec_argsize(33) void @"?callstruct33@@$$hYA?AUs33@@U1@@Z"(ptr noalias sret(%struct.s33) align 1 %agg.result, ptr noundef arm64ec_argsize(33) %x) +// CHECK: define dso_local arm64ec_argsize(64) void @"?callstruct64@@$$hYA?AUs64@@U1@@Z"(ptr noalias sret(%struct.s64) align 1 %agg.result, ptr noundef arm64ec_argsize(64) %x) +// CHECK: define dso_local arm64ec_argsize(65) void @"?callstruct65@@$$hYA?AUs65@@U1@@Z"(ptr noalias sret(%struct.s65) align 1 %agg.result, ptr noundef arm64ec_argsize(65) %x) +// CHECK: define dso_local arm64ec_argsize(128) void @"?callstruct128@@$$hYA?AUs128@@U1@@Z"(ptr noalias sret(%struct.s128) align 1 %agg.result, ptr noundef arm64ec_argsize(128) %x) +// CHECK: define dso_local arm64ec_argsize(133) void @"?callstruct133@@$$hYA?AUs133@@U1@@Z"(ptr noalias sret(%struct.s133) align 1 %agg.result, ptr noundef arm64ec_argsize(133) %x) +// CHECK: define dso_local arm64ec_argsize(192) void @"?callstruct192@@$$hYA?AUs192@@U1@@Z"(ptr noalias sret(%struct.s192) align 1 %agg.result, ptr noundef arm64ec_argsize(192) %x) +// CHECK: define dso_local arm64ec_argsize(223) void @"?callstruct223@@$$hYA?AUs223@@U1@@Z"(ptr noalias sret(%struct.s223) align 1 %agg.result, ptr noundef arm64ec_argsize(223) %x) +// CHECK: define dso_local arm64ec_argsize(256) void @"?callstruct256@@$$hYA?AUs256@@U1@@Z"(ptr noalias sret(%struct.s256) align 1 %agg.result, ptr noundef arm64ec_argsize(256) %x) +// CHECK: define dso_local arm64ec_argsize(257) void @"?callstruct257@@$$hYA?AUs257@@U1@@Z"(ptr noalias sret(%struct.s257) align 1 %agg.result, ptr noundef arm64ec_argsize(257) %x) +// CHECK: define dso_local arm64ec_argsize(8) %struct.f2 @"?callstructf2@@$$hYA?AUf2@@U1@@Z"([2 x float] arm64ec_argsize(8) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(12) %struct.f3 @"?callstructf3@@$$hYA?AUf3@@U1@@Z"([3 x float] arm64ec_argsize(12) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(16) %struct.f4 @"?callstructf4@@$$hYA?AUf4@@U1@@Z"([4 x float] arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(20) void @"?callstructf5@@$$hYA?AUf5@@U1@@Z"(ptr noalias sret(%struct.f5) align 1 %agg.result, ptr noundef arm64ec_argsize(20) %x) +// CHECK: define dso_local arm64ec_argsize(16) %struct.d2 @"?callstructd2@@$$hYA?AUd2@@U1@@Z"([2 x double] arm64ec_argsize(16) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(24) %struct.d3 @"?callstructd3@@$$hYA?AUd3@@U1@@Z"([3 x double] arm64ec_argsize(24) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(32) %struct.d4 @"?callstructd4@@$$hYA?AUd4@@U1@@Z"([4 x double] arm64ec_argsize(32) %x.coerce) +// CHECK: define dso_local arm64ec_argsize(40) void @"?callstructd5@@$$hYA?AUd5@@U1@@Z"(ptr noalias sret(%struct.d5) align 1 %agg.result, ptr noundef arm64ec_argsize(40) %x) Index: clang/test/CodeGenCXX/arm64ec.cpp =================================================================== --- clang/test/CodeGenCXX/arm64ec.cpp +++ clang/test/CodeGenCXX/arm64ec.cpp @@ -2,7 +2,7 @@ // CHECK: @"?g@@YAXUA@@UB@@@Z" = alias void ([2 x float], [4 x float]), void ([2 x float], [4 x float])* @"?g@@$$hYAXUA@@UB@@@Z" // CHECK: define dso_local void @"?g@@$$hYAXUA@@UB@@@Z" -// CHECK: call void (i64, ...) @"?f@@YAXUA@@ZZ"(i64 %{{.*}}, %struct.B* noundef %{{.*}}) +// CHECK: call void (i64, ...) @"?f@@YAXUA@@ZZ"(i64 arm64ec_argsize(8) %{{.*}}, %struct.B* noundef arm64ec_argsize(16) %{{.*}}) typedef struct { float x[2]; } A; typedef struct { float x[4]; } B; void f(A a, ...); Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -690,6 +690,7 @@ ATTR_KIND_PRESPLIT_COROUTINE = 83, ATTR_KIND_FNRETTHUNK_EXTERN = 84, ATTR_KIND_SKIP_PROFILE = 85, + ATTR_KIND_ARM64EC_ARG_SIZE = 86, }; enum ComdatSelectionKindCodes { Index: llvm/include/llvm/IR/Attributes.h =================================================================== --- llvm/include/llvm/IR/Attributes.h +++ llvm/include/llvm/IR/Attributes.h @@ -145,6 +145,8 @@ static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty); static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty); static Attribute getWithUWTableKind(LLVMContext &Context, UWTableKind Kind); + static Attribute getWithArm64ECArgSizeBytes(LLVMContext &Context, + uint64_t Bytes); /// For a typed attribute, return the equivalent attribute with the type /// changed to \p ReplacementTy. @@ -244,6 +246,9 @@ // Returns the allocator function kind. AllocFnKind getAllocKind() const; + /// Returns arm64ec x86 signature arg size in bytes + uint64_t getArm64ECArgSizeBytes() const; + /// The Attribute is converted to a string of equivalent mnemonic. This /// is, presumably, for writing out the mnemonics for the assembly writer. std::string getAsString(bool InAttrGrp = false) const; @@ -376,6 +381,7 @@ Optional getVScaleRangeMax() const; UWTableKind getUWTableKind() const; AllocFnKind getAllocKind() const; + uint64_t getArm64ECArgSizeBytes() const; std::string getAsString(bool InAttrGrp = false) const; /// Return true if this attribute set belongs to the LLVMContext. @@ -875,6 +881,13 @@ AllocFnKind getAllocKind() const; + /// Get the number of Arm64ECArgSize bytes (or zero if unknown) of the + /// return value. + uint64_t getRetArm64ECArgSizeBytes() const; + + /// Get the number of Arm64ECArgSize bytes (or zero if unknown) of an arg. + uint64_t getParamArm64ECArgSizeBytes(unsigned Index) const; + /// Return the attributes at the index as a string. std::string getAsString(unsigned Index, bool InAttrGrp = false) const; @@ -1155,6 +1168,11 @@ /// Retrieve the maximum value of 'vscale_range' or None when unknown. Optional getVScaleRangeMax() const; + /// Retrieve the arm64ec x86 signature size attribute, if it exists. + uint64_t getArm64ECArgSizeBytes() const { + return getRawIntAttr(Attribute::Arm64ECArgSize); + } + /// Add integer attribute with raw value (packed/encoded if necessary). AttrBuilder &addRawIntAttr(Attribute::AttrKind Kind, uint64_t Value); @@ -1224,6 +1242,10 @@ /// Attribute.getIntValue(). AttrBuilder &addVScaleRangeAttrFromRawRepr(uint64_t RawVScaleRangeRepr); + /// This turns the number of arm64ec args with x86 signature bytes into the + /// form used internally in Attribute. + AttrBuilder &addArm64ECArgSizeAttr(uint64_t Bytes); + /// This turns the unwind table kind into the form used internally in /// Attribute. AttrBuilder &addUWTableAttr(UWTableKind Kind); Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -314,6 +314,9 @@ /// Function is a presplit coroutine. def PresplitCoroutine : EnumAttr<"presplitcoroutine", [FnAttr]>; +/// Struct Arg size for x86 signature to generate correct thunk +def Arm64ECArgSize : IntAttr<"arm64ec_argsize", [ParamAttr, RetAttr]>; + /// Target-independent string attributes. def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; Index: llvm/include/llvm/IR/Function.h =================================================================== --- llvm/include/llvm/IR/Function.h +++ llvm/include/llvm/IR/Function.h @@ -484,6 +484,12 @@ return AttributeSets.getParamDereferenceableOrNullBytes(ArgNo); } + /// Extract the number of Arm64ECArgSize bytes for a parameter. + /// @param ArgNo Index of an argument, with 0 being the first function arg. + uint64_t getParamArm64ECArgSizeBytes(unsigned ArgNo) const { + return AttributeSets.getParamArm64ECArgSizeBytes(ArgNo); + } + /// Determine if the function is presplit coroutine. bool isPresplitCoroutine() const { return hasFnAttribute(Attribute::PresplitCoroutine); Index: llvm/include/llvm/IR/InstrTypes.h =================================================================== --- llvm/include/llvm/IR/InstrTypes.h +++ llvm/include/llvm/IR/InstrTypes.h @@ -1814,6 +1814,18 @@ return Attrs.getParamDereferenceableOrNullBytes(i); } + /// Extract the number of Arm64ECArgSize bytes for a call or + /// parameter. + uint64_t getRetArm64ECArgSizeBytes() const { + return Attrs.getRetArm64ECArgSizeBytes(); + } + + /// Extract the number of Arm64ECArgSize bytes for a call or + /// parameter. + uint64_t getParamArm64ECArgSizeBytes(unsigned i) const { + return Attrs.getParamArm64ECArgSizeBytes(i); + } + /// Return true if the return value is known to be not null. /// This may be because it has the nonnull attribute, or because at least /// one byte is dereferenceable and the pointer is in addrspace(0). Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1416,6 +1416,21 @@ B.addAllocKindAttr(Kind); return false; } + case Attribute::Arm64ECArgSize: { + if (!EatIfPresent(lltok::kw_arm64ec_argsize)) + return false; + LocTy ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::lparen)) + return error(ParenLoc, "expected '('"); + uint64_t Bytes = 0; + if (parseUInt64(Bytes)) + return true; + ParenLoc = Lex.getLoc(); + if (!EatIfPresent(lltok::rparen)) + return error(ParenLoc, "expected ')'"); + B.addArm64ECArgSizeAttr(Bytes); + return false; + } default: B.addAttribute(Attr); Lex.Lex(); Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2015,6 +2015,8 @@ return Attribute::Hot; case bitc::ATTR_KIND_PRESPLIT_COROUTINE: return Attribute::PresplitCoroutine; + case bitc::ATTR_KIND_ARM64EC_ARG_SIZE: + return Attribute::Arm64ECArgSize; } } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -782,6 +782,8 @@ return bitc::ATTR_KIND_MUSTPROGRESS; case Attribute::PresplitCoroutine: return bitc::ATTR_KIND_PRESPLIT_COROUTINE; + case Attribute::Arm64ECArgSize: + return bitc::ATTR_KIND_ARM64EC_ARG_SIZE; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: Index: llvm/lib/IR/AttributeImpl.h =================================================================== --- llvm/lib/IR/AttributeImpl.h +++ llvm/lib/IR/AttributeImpl.h @@ -257,6 +257,7 @@ Optional getVScaleRangeMax() const; UWTableKind getUWTableKind() const; AllocFnKind getAllocKind() const; + uint64_t getArm64ECArgSizeBytes() const; std::string getAsString(bool InAttrGrp) const; Type *getAttributeType(Attribute::AttrKind Kind) const; Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -222,6 +222,11 @@ return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue)); } +Attribute Attribute::getWithArm64ECArgSizeBytes(LLVMContext &Context, + uint64_t Bytes) { + return get(Context, Arm64ECArgSize, Bytes); +} + Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) { return StringSwitch(AttrName) #define GET_ATTR_NAMES @@ -369,6 +374,13 @@ return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second; } +uint64_t Attribute::getArm64ECArgSizeBytes() const { + assert(hasAttribute(Attribute::Arm64ECArgSize) && + "Trying to get Arm64ECArgSize bytes from " + "non-Arm64ECArgSize attribute!"); + return pImpl->getValueAsInt(); +} + UWTableKind Attribute::getUWTableKind() const { assert(hasAttribute(Attribute::UWTable) && "Trying to get unwind table kind from non-uwtable attribute"); @@ -472,6 +484,9 @@ .str(); } + if (hasAttribute(Attribute::Arm64ECArgSize)) + return AttrWithBytesToString("arm64ec_argsize"); + // Convert target-dependent attributes to strings of the form: // // "kind" @@ -764,6 +779,10 @@ return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown; } +uint64_t AttributeSet::getArm64ECArgSizeBytes() const { + return SetNode ? SetNode->getArm64ECArgSizeBytes() : 0; +} + std::string AttributeSet::getAsString(bool InAttrGrp) const { return SetNode ? SetNode->getAsString(InAttrGrp) : ""; } @@ -942,6 +961,12 @@ return AllocFnKind::Unknown; } +uint64_t AttributeSetNode::getArm64ECArgSizeBytes() const { + if (auto A = findEnumAttribute(Attribute::Arm64ECArgSize)) + return A->getArm64ECArgSizeBytes(); + return 0; +} + std::string AttributeSetNode::getAsString(bool InAttrGrp) const { std::string Str; for (iterator I = begin(), E = end(); I != E; ++I) { @@ -1494,6 +1519,14 @@ return getFnAttrs().getAllocKind(); } +uint64_t AttributeList::getRetArm64ECArgSizeBytes() const { + return getRetAttrs().getArm64ECArgSizeBytes(); +} + +uint64_t AttributeList::getParamArm64ECArgSizeBytes(unsigned Index) const { + return getParamAttrs(Index).getArm64ECArgSizeBytes(); +} + std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const { return getAttributes(Index).getAsString(InAttrGrp); } @@ -1715,6 +1748,10 @@ return addRawIntAttr(Attribute::VScaleRange, RawArgs); } +AttrBuilder &AttrBuilder::addArm64ECArgSizeAttr(uint64_t Bytes) { + return addRawIntAttr(Attribute::Arm64ECArgSize, Bytes); +} + AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) { if (Kind == UWTableKind::None) return *this; Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -990,6 +990,7 @@ case Attribute::ZExt: case Attribute::ImmArg: case Attribute::ByRef: + case Attribute::Arm64ECArgSize: // These are not really attributes. case Attribute::None: case Attribute::EndAttrKinds: