Index: clang/lib/CodeGen/CGCall.cpp =================================================================== --- clang/lib/CodeGen/CGCall.cpp +++ clang/lib/CodeGen/CGCall.cpp @@ -2334,6 +2334,17 @@ RetAttrs.addAttribute(llvm::Attribute::NoUndef); } + auto AddArm64ECX86Sign = [this](QualType Ty, llvm::AttrBuilder& Attrs) { + if (Ty->isRecordType() || Ty->isArrayType()) { + unsigned SizeInBits = getContext().getTypeSize(Ty.getTypePtr()); + unsigned SizeInBytes = (SizeInBits + 7) / 8; + Attrs.addArmECArgX86SignAttr(SizeInBytes); + } + }; + + if (getTriple().isWindowsArm64EC()) + AddArm64ECX86Sign(RetTy, RetAttrs); + switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetAI.isSignExt()) @@ -2467,6 +2478,9 @@ Attrs.addAttribute(llvm::Attribute::NoUndef); } + if (getTriple().isWindowsArm64EC()) + AddArm64ECX86Sign(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,63 @@ +// RUN: %clang_cc1 %s -triple=arm64-pc-windows-msvc_arm64ec -emit-llvm -fms-compatibility -o - | FileCheck %s + +extern "C" +{ +#pragma pack(push, 1) + +#define structf(Size, Align) \ + struct __declspec(align(Align)) s##Size \ + { \ + char a[Size]; \ + }; \ + s##Size (*pfnstruct##Size)(s##Size x); \ + s##Size callstruct##Size(s##Size x) \ + { \ + return pfnstruct##Size(x); \ + } + + structf(1, 1); + structf(2, 8); + structf(3, 64); + structf(4, 32); + structf(5, 2); + structf(6, 4); + structf(7, 8); + structf(8, 16); + structf(9, 4); + structf(10, 2); + structf(11, 1); + structf(12, 64); + structf(13, 8); + structf(14, 4); + structf(15, 16); + structf(16, 32); + structf(17, 64); + structf(33, 4); + structf(65, 2); + structf(129, 16); + structf(257, 32); + +#pragma pack(pop) +} + +// CHECK: define dso_local arm64ec_x86sign(1) i8 @"#callstruct1"(i64 arm64ec_x86sign(1) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(8) i64 @"#callstruct2"(i64 arm64ec_x86sign(8) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(64) void @"#callstruct3"(ptr noalias sret(%struct.s3) align 64 %agg.result, ptr {{.*}} arm64ec_x86sign(64) %x) +// CHECK: define dso_local arm64ec_x86sign(32) void @"#callstruct4"(ptr noalias sret(%struct.s4) align 32 %agg.result, ptr {{.*}} arm64ec_x86sign(32) %x) +// CHECK: define dso_local arm64ec_x86sign(6) i48 @"#callstruct5"(i64 arm64ec_x86sign(6) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(8) i64 @"#callstruct6"(i64 arm64ec_x86sign(8) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(8) i64 @"#callstruct7"(i64 arm64ec_x86sign(8) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(16) i128 @"#callstruct8"(i128 arm64ec_x86sign(16) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(12) [2 x i64] @"#callstruct9"([2 x i64] arm64ec_x86sign(12) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(10) [2 x i64] @"#callstruct10"([2 x i64] arm64ec_x86sign(10) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(11) [2 x i64] @"#callstruct11"([2 x i64] arm64ec_x86sign(11) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(64) void @"#callstruct12"(ptr noalias sret(%struct.s12) align 64 %agg.result, ptr {{.*}} arm64ec_x86sign(64) %x) +// CHECK: define dso_local arm64ec_x86sign(16) [2 x i64] @"#callstruct13"([2 x i64] arm64ec_x86sign(16) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(16) [2 x i64] @"#callstruct14"([2 x i64] arm64ec_x86sign(16) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(16) i128 @"#callstruct15"(i128 arm64ec_x86sign(16) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(32) void @"#callstruct16"(ptr noalias sret(%struct.s16) align 32 %agg.result, ptr {{.*}} arm64ec_x86sign(32) %x) +// CHECK: define dso_local arm64ec_x86sign(64) void @"#callstruct17"(ptr noalias sret(%struct.s17) align 64 %agg.result, ptr {{.*}} arm64ec_x86sign(64) %x) +// CHECK: define dso_local arm64ec_x86sign(36) void @"#callstruct33"(ptr noalias sret(%struct.s33) align 4 %agg.result, ptr {{.*}} arm64ec_x86sign(36) %x) +// CHECK: define dso_local arm64ec_x86sign(66) void @"#callstruct65"(ptr noalias sret(%struct.s65) align 2 %agg.result, ptr {{.*}} arm64ec_x86sign(66) %x) +// CHECK: define dso_local arm64ec_x86sign(144) void @"#callstruct129"(ptr noalias sret(%struct.s129) align 16 %agg.result, ptr {{.*}} arm64ec_x86sign(144) %x) +// CHECK: define dso_local arm64ec_x86sign(288) void @"#callstruct257"(ptr noalias sret(%struct.s257) align 32 %agg.result, ptr {{.*}} arm64ec_x86sign(288) %x) \ No newline at end of file Index: clang/test/CodeGenCXX/arm64ec-mangle-basic.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/arm64ec-mangle-basic.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 %s -triple=arm64-pc-windows-msvc_arm64ec -emit-llvm -fms-compatibility -o - | FileCheck %s +extern "C" +{ +#pragma pack(push, 1) + +#define basicf(type) \ + type (*pfn##type)(type x); \ + type call##type(type x) \ + { \ + return pfn##type(x); \ + } + + typedef long long i64; + typedef long double longdouble; + typedef void *VOIDP; + + basicf(bool); + basicf(char); + basicf(short); + basicf(wchar_t); + basicf(int); + basicf(i64); + basicf(float); + basicf(double); + basicf(longdouble); + basicf(VOIDP); + +#pragma pack(pop) +} + +// CHECK: define dso_local i1 @"#callbool"(i1 noundef %x) +// CHECK: define dso_local i8 @"#callchar"(i8 noundef %x) +// CHECK: define dso_local i16 @"#callshort"(i16 noundef %x) +// CHECK: define dso_local i16 @"#callwchar_t"(i16 noundef %x) +// CHECK: define dso_local i32 @"#callint"(i32 noundef %x) +// CHECK: define dso_local i64 @"#calli64"(i64 noundef %x) +// CHECK: define dso_local float @"#callfloat"(float noundef %x) +// CHECK: define dso_local double @"#calldouble"(double noundef %x) +// CHECK: define dso_local double @"#calllongdouble"(double noundef %x) +// CHECK: define dso_local ptr @"#callVOIDP"(ptr noundef %x) Index: clang/test/CodeGenCXX/arm64ec-mangle-struct.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/arm64ec-mangle-struct.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 %s -triple=arm64-pc-windows-msvc_arm64ec -emit-llvm -fms-compatibility -o - | FileCheck %s + +extern "C" +{ +#pragma pack(push, 1) + +#define structf(Size) \ + struct s##Size \ + { \ + char a[Size]; \ + }; \ + s##Size (*pfnstruct##Size)(s##Size x); \ + s##Size callstruct##Size(s##Size x) \ + { \ + return pfnstruct##Size(x); \ + } + + structf(1); + structf(2); + structf(3); + structf(4); + structf(5); + structf(6); + structf(7); + structf(8); + structf(9); + structf(10); + structf(11); + structf(12); + structf(13); + structf(14); + structf(15); + structf(16); + structf(17); + structf(32); + structf(33); + structf(64); + structf(65); + structf(128); + structf(133); + structf(192); + structf(223); + structf(256); + structf(257); + +#pragma pack(pop) +} + +// CHECK: define dso_local arm64ec_x86sign(1) i8 @"#callstruct1"(i64 arm64ec_x86sign(1) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(2) i16 @"#callstruct2"(i64 arm64ec_x86sign(2) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(3) i24 @"#callstruct3"(i64 arm64ec_x86sign(3) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(4) i32 @"#callstruct4"(i64 arm64ec_x86sign(4) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(5) i40 @"#callstruct5"(i64 arm64ec_x86sign(5) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(6) i48 @"#callstruct6"(i64 arm64ec_x86sign(6) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(7) i56 @"#callstruct7"(i64 arm64ec_x86sign(7) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(8) i64 @"#callstruct8"(i64 arm64ec_x86sign(8) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(9) [2 x i64] @"#callstruct9"([2 x i64] arm64ec_x86sign(9) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(10) [2 x i64] @"#callstruct10"([2 x i64] arm64ec_x86sign(10) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(11) [2 x i64] @"#callstruct11"([2 x i64] arm64ec_x86sign(11) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(12) [2 x i64] @"#callstruct12"([2 x i64] arm64ec_x86sign(12) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(13) [2 x i64] @"#callstruct13"([2 x i64] arm64ec_x86sign(13) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(14) [2 x i64] @"#callstruct14"([2 x i64] arm64ec_x86sign(14) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(15) [2 x i64] @"#callstruct15"([2 x i64] arm64ec_x86sign(15) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(16) [2 x i64] @"#callstruct16"([2 x i64] arm64ec_x86sign(16) %x.coerce) +// CHECK: define dso_local arm64ec_x86sign(17) void @"#callstruct17"(ptr noalias sret(%struct.s17) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(17) %x) +// CHECK: define dso_local arm64ec_x86sign(32) void @"#callstruct32"(ptr noalias sret(%struct.s32) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(32) %x) +// CHECK: define dso_local arm64ec_x86sign(33) void @"#callstruct33"(ptr noalias sret(%struct.s33) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(33) %x) +// CHECK: define dso_local arm64ec_x86sign(64) void @"#callstruct64"(ptr noalias sret(%struct.s64) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(64) %x) +// CHECK: define dso_local arm64ec_x86sign(65) void @"#callstruct65"(ptr noalias sret(%struct.s65) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(65) %x) +// CHECK: define dso_local arm64ec_x86sign(128) void @"#callstruct128"(ptr noalias sret(%struct.s128) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(128) %x) +// CHECK: define dso_local arm64ec_x86sign(133) void @"#callstruct133"(ptr noalias sret(%struct.s133) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(133) %x) +// CHECK: define dso_local arm64ec_x86sign(192) void @"#callstruct192"(ptr noalias sret(%struct.s192) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(192) %x) +// CHECK: define dso_local arm64ec_x86sign(223) void @"#callstruct223"(ptr noalias sret(%struct.s223) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(223) %x) +// CHECK: define dso_local arm64ec_x86sign(256) void @"#callstruct256"(ptr noalias sret(%struct.s256) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(256) %x) +// CHECK: define dso_local arm64ec_x86sign(257) void @"#callstruct257"(ptr noalias sret(%struct.s257) align 1 %agg.result, ptr {{.*}} arm64ec_x86sign(257) %x) 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_X86SIGN = 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 getWithArm64ECArgX86SignBytes(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 getArm64ECArgX86SignBytes() 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 getArm64ECArgX86SignBytes() 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 Arm64ECArgX86Sign bytes (or zero if unknown) of the + /// return value. + uint64_t getRetArm64ECArgX86SignBytes() const; + + /// Get the number of Arm64ECArgX86Sign bytes (or zero if unknown) of an arg. + uint64_t getParamArm64ECArgX86SignBytes(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 getArm64ECArgX86SignBytes() const { + return getRawIntAttr(Attribute::Arm64ECArgX86Sign); + } + /// 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 &addArmECArgX86SignAttr(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 Arm64ECArgX86Sign : IntAttr<"arm64ec_x86sign", [ParamAttr, RetAttr]>; + /// Target-independent string attributes. def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; 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 Arm64ECArgX86Sign bytes for a call or + /// parameter. + uint64_t getRetArm64ECArgX86SignBytes() const { + return Attrs.getRetArm64ECArgX86SignBytes(); + } + + /// Extract the number of Arm64ECArgX86Sign bytes for a call or + /// parameter. + uint64_t getParamArm64ECArgX86SignBytes(unsigned i) const { + return Attrs.getParamArm64ECArgX86SignBytes(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::Arm64ECArgX86Sign: { + if (!EatIfPresent(lltok::kw_arm64ec_x86sign)) + 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.addArmECArgX86SignAttr(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 @@ -2005,6 +2005,8 @@ return Attribute::Hot; case bitc::ATTR_KIND_PRESPLIT_COROUTINE: return Attribute::PresplitCoroutine; + case bitc::ATTR_KIND_ARM64EC_ARG_X86SIGN: + return Attribute::Arm64ECArgX86Sign; } } 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::Arm64ECArgX86Sign: + return bitc::ATTR_KIND_ARM64EC_ARG_X86SIGN; 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 getArm64ECArgX86SignBytes() 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::getWithArm64ECArgX86SignBytes(LLVMContext &Context, + uint64_t Bytes) { + return get(Context, Arm64ECArgX86Sign, 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::getArm64ECArgX86SignBytes() const { + assert(hasAttribute(Attribute::Arm64ECArgX86Sign) && + "Trying to get Arm64ECArgX86Sign bytes from " + "non-Arm64ECArgX86Sign 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::Arm64ECArgX86Sign)) + return AttrWithBytesToString("arm64ec_x86sign"); + // Convert target-dependent attributes to strings of the form: // // "kind" @@ -764,6 +779,10 @@ return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown; } +uint64_t AttributeSet::getArm64ECArgX86SignBytes() const { + return SetNode ? SetNode->getArm64ECArgX86SignBytes() : 0; +} + std::string AttributeSet::getAsString(bool InAttrGrp) const { return SetNode ? SetNode->getAsString(InAttrGrp) : ""; } @@ -942,6 +961,12 @@ return AllocFnKind::Unknown; } +uint64_t AttributeSetNode::getArm64ECArgX86SignBytes() const { + if (auto A = findEnumAttribute(Attribute::Arm64ECArgX86Sign)) + return A->getArm64ECArgX86SignBytes(); + 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::getRetArm64ECArgX86SignBytes() const { + return getRetAttrs().getArm64ECArgX86SignBytes(); +} + +uint64_t AttributeList::getParamArm64ECArgX86SignBytes(unsigned Index) const { + return getParamAttrs(Index).getArm64ECArgX86SignBytes(); +} + 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::addArmECArgX86SignAttr(uint64_t Bytes) { + return addRawIntAttr(Attribute::Arm64ECArgX86Sign, 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::Arm64ECArgX86Sign: // These are not really attributes. case Attribute::None: case Attribute::EndAttrKinds: