From 3f0de5787ec906d68e8ad0b29ca5f13455541ca6 Mon Sep 17 00:00:00 2001 From: Hiroshi Yamauchi Date: Wed, 4 Sep 2024 17:58:31 -0700 Subject: [PATCH] Add the inreg attribute to sreg when present. On Windows/AArch64, a different register is used between when an arugment is both inreg and sret (X0 or X1) and when it is just sret (X8) as the following comment indicates: https://github.com/llvm/llvm-project/blob/46fe36a4295f05d5d3731762e31fc4e6e99863e9/llvm/lib/Target/AArch64/AArch64CallingConvention.td#L42 ``` // In AAPCS, an SRet is passed in X8, not X0 like a normal pointer parameter. // However, on windows, in some circumstances, the SRet is passed in X0 or X1 // instead. The presence of the inreg attribute indicates that SRet is // passed in the alternative register (X0 or X1), not X8: // - X0 for non-instance methods. // - X1 for instance methods. // The "sret" attribute identifies indirect returns. // The "inreg" attribute identifies non-aggregate types. // The position of the "sret" attribute identifies instance/non-instance // methods. // "sret" on argument 0 means non-instance methods. // "sret" on argument 1 means instance methods. CCIfInReg>>>>, CCIfSRet>>, ``` So missing/dropping inreg can cause a codegen bug. This is a partial fix for #74866 --- lib/IRGen/GenCall.cpp | 16 ++++++++++------ ...ods-this-and-indirect-return-irgen-msvc.swift | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index fc053208df9d3..cb7b4f51705ec 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -360,7 +360,8 @@ static void addIndirectResultAttributes(IRGenModule &IGM, llvm::AttributeList &attrs, unsigned paramIndex, bool allowSRet, llvm::Type *storageType, - const TypeInfo &typeInfo) { + const TypeInfo &typeInfo, + bool useInReg = false) { llvm::AttrBuilder b(IGM.getLLVMContext()); b.addAttribute(llvm::Attribute::NoAlias); // Bitwise takable value types are guaranteed not to capture @@ -370,6 +371,8 @@ static void addIndirectResultAttributes(IRGenModule &IGM, if (allowSRet) { assert(storageType); b.addStructRetAttr(storageType); + if (useInReg) + b.addAttribute(llvm::Attribute::InReg); } attrs = attrs.addParamAttributes(IGM.getLLVMContext(), paramIndex, b); } @@ -552,7 +555,7 @@ namespace { private: const TypeInfo &expand(SILParameterInfo param); - llvm::Type *addIndirectResult(SILType resultType); + llvm::Type *addIndirectResult(SILType resultType, bool useInReg = false); SILFunctionConventions getSILFuncConventions() const { return SILFunctionConventions(FnType, IGM.getSILModule()); @@ -611,11 +614,12 @@ namespace { } // end namespace irgen } // end namespace swift -llvm::Type *SignatureExpansion::addIndirectResult(SILType resultType) { +llvm::Type *SignatureExpansion::addIndirectResult(SILType resultType, + bool useInReg) { const TypeInfo &resultTI = IGM.getTypeInfo(resultType); auto storageTy = resultTI.getStorageType(); addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet(), - storageTy, resultTI); + storageTy, resultTI, useInReg); addPointerParameter(storageTy); return IGM.VoidTy; } @@ -1707,9 +1711,9 @@ void SignatureExpansion::expandExternalSignatureTypes() { // returned indirect values. emitArg(0); firstParamToLowerNormally = 1; - addIndirectResult(resultType); + addIndirectResult(resultType, returnInfo.getInReg()); } else - addIndirectResult(resultType); + addIndirectResult(resultType, returnInfo.getInReg()); } // Use a special IR type for passing block pointers. diff --git a/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift index 333f94e30ded1..29c8bf3528c75 100644 --- a/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift +++ b/test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-msvc.swift @@ -12,7 +12,8 @@ public func use() -> CInt { // CHECK: %[[instance:.*]] = alloca %TSo10HasMethodsV // CHECK: %[[result:.*]] = alloca %TSo19NonTrivialInWrapperV -// CHECK: call void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(ptr %[[instance]], ptr noalias sret(%TSo19NonTrivialInWrapperV) %[[result]], i32 42) +// CHECK-x86_64: call void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(ptr %[[instance]], ptr noalias sret(%TSo19NonTrivialInWrapperV) %[[result]], i32 42) +// CHECK-aarch64: call void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(ptr %[[instance]], ptr inreg noalias sret(%TSo19NonTrivialInWrapperV) %[[result]], i32 42) // CHECK-x86_64: define {{.*}} void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(ptr {{.*}} %{{.*}}, ptr noalias sret(%struct.NonTrivialInWrapper) {{.*}} %{{.*}}, i32 noundef %{{.*}}) // CHECK-aarch64: define {{.*}} void @"?nonConstPassThroughAsWrapper@HasMethods@@QEAA?AUNonTrivialInWrapper@@H@Z"(ptr {{.*}} %{{.*}}, ptr inreg noalias sret(%struct.NonTrivialInWrapper) {{.*}} %{{.*}}, i32 noundef %{{.*}})