Skip to content

Commit fd3ad8d

Browse files
committed
[IRGen] Fix a bug where an argument wasn't annotated with sret (#71459)
Fix a bug in expandExternalSignatureTypes where it wasn't annotating a function call parameter type with sret when the result was being returned indirectly. The bug was causing calls to ObjC methods that return their results indirectly to crash. Additionally, fix the return type for C++ constructors computed in expandExternalSignatureTypes. Previously, the return type was always void even on targets that require constructors to return this (e.g., Apple arm64), which was causing C++ constructor thunks to be emitted needlessly. Resolves rdar://121618707 Cherrypick commit b3f302b Cherrypick PR #71459
1 parent 528e66d commit fd3ad8d

File tree

10 files changed

+196
-51
lines changed

10 files changed

+196
-51
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/SIL/SILModule.h"
2525
#include "swift/SIL/SILType.h"
2626
#include "clang/AST/ASTContext.h"
27+
#include "clang/AST/GlobalDecl.h"
2728
#include "clang/AST/RecordLayout.h"
2829
#include "clang/Basic/TargetInfo.h"
2930
#include "clang/CodeGen/CodeGenABITypes.h"
@@ -420,6 +421,10 @@ namespace {
420421
IRGenModule &IGM;
421422
CanSILFunctionType FnType;
422423
bool forStaticCall = false; // Used for objc_method (direct call or not).
424+
425+
// Indicates this is a c++ constructor call.
426+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr;
427+
423428
public:
424429
SmallVector<llvm::Type*, 8> ParamIRTypes;
425430
llvm::Type *ResultIRType = nullptr;
@@ -434,8 +439,10 @@ namespace {
434439
FunctionPointerKind FnKind;
435440

436441
SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
437-
FunctionPointerKind fnKind, bool forStaticCall = false)
438-
: IGM(IGM), FnType(fnType), forStaticCall(forStaticCall), FnKind(fnKind) {}
442+
FunctionPointerKind fnKind, bool forStaticCall = false,
443+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr)
444+
: IGM(IGM), FnType(fnType), forStaticCall(forStaticCall),
445+
cxxCtorDecl(cxxCtorDecl), FnKind(fnKind) {}
439446

440447
/// Expand the components of the primary entrypoint of the function type.
441448
void expandFunctionType(
@@ -460,7 +467,7 @@ namespace {
460467

461468
private:
462469
const TypeInfo &expand(SILParameterInfo param);
463-
llvm::Type *addIndirectResult();
470+
llvm::Type *addIndirectResult(SILType resultType);
464471

465472
SILFunctionConventions getSILFuncConventions() const {
466473
return SILFunctionConventions(FnType, IGM.getSILModule());
@@ -514,9 +521,7 @@ namespace {
514521
} // end namespace irgen
515522
} // end namespace swift
516523

517-
llvm::Type *SignatureExpansion::addIndirectResult() {
518-
auto resultType = getSILFuncConventions().getSILResultType(
519-
IGM.getMaximalTypeExpansionContext());
524+
llvm::Type *SignatureExpansion::addIndirectResult(SILType resultType) {
520525
const TypeInfo &resultTI = IGM.getTypeInfo(resultType);
521526
auto storageTy = resultTI.getStorageType();
522527
addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet(),
@@ -913,7 +918,7 @@ SignatureExpansion::expandDirectResult() {
913918
auto &ti = IGM.getTypeInfo(resultType);
914919
auto &native = ti.nativeReturnValueSchema(IGM);
915920
if (native.requiresIndirect())
916-
return std::make_pair(addIndirectResult(), nullptr);
921+
return std::make_pair(addIndirectResult(resultType), nullptr);
917922

918923
// Disable the use of sret if we have a non-trivial direct result.
919924
if (!native.empty()) CanUseSRet = false;
@@ -1345,26 +1350,28 @@ static bool doesClangExpansionMatchSchema(IRGenModule &IGM,
13451350
void SignatureExpansion::expandExternalSignatureTypes() {
13461351
assert(FnType->getLanguage() == SILFunctionLanguage::C);
13471352

1348-
// Convert the SIL result type to a Clang type.
1349-
auto clangResultTy =
1350-
IGM.getClangType(FnType->getFormalCSemanticResult(IGM.getSILModule()));
1353+
auto SILResultTy = [&]() {
1354+
if (FnType->getNumResults() == 0)
1355+
return SILType::getPrimitiveObjectType(IGM.Context.TheEmptyTupleType);
1356+
1357+
return SILType::getPrimitiveObjectType(
1358+
FnType->getSingleResult().getReturnValueType(
1359+
IGM.getSILModule(), FnType, TypeExpansionContext::minimal()));
1360+
}();
1361+
1362+
// Convert the SIL result type to a Clang type. If this is for a c++
1363+
// constructor, use 'void' as the return type to arrange the function type.
1364+
auto clangResultTy = IGM.getClangType(
1365+
cxxCtorDecl
1366+
? SILType::getPrimitiveObjectType(IGM.Context.TheEmptyTupleType)
1367+
: SILResultTy);
13511368

13521369
// Now convert the parameters to Clang types.
13531370
auto params = FnType->getParameters();
13541371

13551372
SmallVector<clang::CanQualType,4> paramTys;
13561373
auto const &clangCtx = IGM.getClangASTContext();
13571374

1358-
bool formalIndirectResult = FnType->getNumResults() > 0 &&
1359-
FnType->getSingleResult().isFormalIndirect();
1360-
if (formalIndirectResult) {
1361-
auto resultType = getSILFuncConventions().getSingleSILResultType(
1362-
IGM.getMaximalTypeExpansionContext());
1363-
auto clangTy =
1364-
IGM.getClangASTContext().getPointerType(IGM.getClangType(resultType));
1365-
paramTys.push_back(clangTy);
1366-
}
1367-
13681375
switch (FnType->getRepresentation()) {
13691376
case SILFunctionTypeRepresentation::ObjCMethod: {
13701377
// ObjC methods take their 'self' argument first, followed by an
@@ -1393,7 +1400,11 @@ void SignatureExpansion::expandExternalSignatureTypes() {
13931400
}
13941401

13951402
case SILFunctionTypeRepresentation::CFunctionPointer:
1396-
// No implicit arguments.
1403+
if (cxxCtorDecl) {
1404+
auto clangTy = IGM.getClangASTContext().getPointerType(
1405+
IGM.getClangType(SILResultTy));
1406+
paramTys.push_back(clangTy);
1407+
}
13971408
break;
13981409

13991410
case SILFunctionTypeRepresentation::Thin:
@@ -1417,6 +1428,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14171428

14181429
// Generate function info for this signature.
14191430
auto extInfo = clang::FunctionType::ExtInfo();
1431+
14201432
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
14211433
clangResultTy, paramTys, extInfo,
14221434
clang::CodeGen::RequiredArgs::All);
@@ -1427,6 +1439,14 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14271439

14281440
auto &returnInfo = FI.getReturnInfo();
14291441

1442+
#ifndef NDEBUG
1443+
bool formalIndirectResult = FnType->getNumResults() > 0 &&
1444+
FnType->getSingleResult().isFormalIndirect();
1445+
assert(
1446+
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect()) &&
1447+
"swift and clang disagree on whether the result is returned indirectly");
1448+
#endif
1449+
14301450
// Does the result need an extension attribute?
14311451
if (returnInfo.isExtend()) {
14321452
bool signExt = clangResultTy->hasSignedIntegerRepresentation();
@@ -1531,16 +1551,18 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15311551

15321552
// If we return indirectly, that is the first parameter type.
15331553
if (returnInfo.isIndirect()) {
1554+
auto resultType = getSILFuncConventions().getSingleSILResultType(
1555+
IGM.getMaximalTypeExpansionContext());
15341556
if (IGM.Triple.isWindowsMSVCEnvironment() &&
15351557
FnType->getRepresentation() ==
15361558
SILFunctionTypeRepresentation::CXXMethod) {
15371559
// Windows ABI places `this` before the
15381560
// returned indirect values.
15391561
emitArg(0);
15401562
firstParamToLowerNormally = 1;
1541-
addIndirectResult();
1563+
addIndirectResult(resultType);
15421564
} else
1543-
addIndirectResult();
1565+
addIndirectResult(resultType);
15441566
}
15451567

15461568
// Use a special IR type for passing block pointers.
@@ -1554,7 +1576,12 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15541576
for (auto i : indices(paramTys).slice(firstParamToLowerNormally))
15551577
emitArg(i);
15561578

1557-
if (returnInfo.isIndirect() || returnInfo.isIgnore()) {
1579+
if (cxxCtorDecl) {
1580+
ResultIRType = cast<llvm::Function>(IGM.getAddrOfClangGlobalDecl(
1581+
{cxxCtorDecl, clang::Ctor_Complete},
1582+
(ForDefinition_t) false))
1583+
->getReturnType();
1584+
} else if (returnInfo.isIndirect() || returnInfo.isIgnore()) {
15581585
ResultIRType = IGM.VoidTy;
15591586
} else {
15601587
ResultIRType = returnInfo.getCoerceToType();
@@ -1874,7 +1901,7 @@ void SignatureExpansion::expandAsyncEntryType() {
18741901
auto &ti = IGM.getTypeInfo(resultType);
18751902
auto &native = ti.nativeReturnValueSchema(IGM);
18761903
if (native.requiresIndirect())
1877-
addIndirectResult();
1904+
addIndirectResult(resultType);
18781905

18791906
// Add the indirect result types.
18801907
expandIndirectResults();
@@ -2035,10 +2062,11 @@ Signature SignatureExpansion::getSignature() {
20352062

20362063
Signature Signature::getUncached(IRGenModule &IGM,
20372064
CanSILFunctionType formalType,
2038-
FunctionPointerKind fpKind,
2039-
bool forStaticCall) {
2065+
FunctionPointerKind fpKind, bool forStaticCall,
2066+
const clang::CXXConstructorDecl *cxxCtorDecl) {
20402067
GenericContextScope scope(IGM, formalType->getInvocationGenericSignature());
2041-
SignatureExpansion expansion(IGM, formalType, fpKind, forStaticCall);
2068+
SignatureExpansion expansion(IGM, formalType, fpKind, forStaticCall,
2069+
cxxCtorDecl);
20422070
expansion.expandFunctionType();
20432071
return expansion.getSignature();
20442072
}
@@ -3083,7 +3111,13 @@ llvm::CallBase *IRBuilder::CreateCallOrInvoke(
30833111
for (unsigned argIndex = 0; argIndex < func->arg_size(); ++argIndex) {
30843112
if (func->hasParamAttribute(argIndex, llvm::Attribute::StructRet)) {
30853113
llvm::AttrBuilder builder(func->getContext());
3086-
builder.addStructRetAttr(func->getParamStructRetType(argIndex));
3114+
// See if there is a sret parameter in the signature. There are cases
3115+
// where the called function has a sret parameter, but the signature
3116+
// doesn't (e.g., noreturn functions).
3117+
llvm::Type *ty = attrs.getParamStructRetType(argIndex);
3118+
if (!ty)
3119+
ty = func->getParamStructRetType(argIndex);
3120+
builder.addStructRetAttr(ty);
30873121
attrs = attrs.addParamAttributes(func->getContext(), argIndex, builder);
30883122
}
30893123
if (func->hasParamAttribute(argIndex, llvm::Attribute::ByVal)) {
@@ -3797,11 +3831,13 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
37973831
params = params.drop_back();
37983832
}
37993833

3800-
if (fnType->getNumResults() > 0 &&
3801-
fnType->getSingleResult().isFormalIndirect()) {
3802-
// Ignore the indirect result parameter.
3834+
bool formalIndirectResult = fnType->getNumResults() > 0 &&
3835+
fnType->getSingleResult().isFormalIndirect();
3836+
3837+
// If clang returns directly and swift returns indirectly, this must be a c++
3838+
// constructor call. In that case, skip the "self" param.
3839+
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult)
38033840
firstParam += 1;
3804-
}
38053841

38063842
for (unsigned i = firstParam; i != paramEnd; ++i) {
38073843
auto clangParamTy = FI.arg_begin()[i].type;

lib/IRGen/GenDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3376,7 +3376,10 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded(
33763376
emitCXXConstructorCall(subIGF, ctor, ctorFnType, ctorAddress, Args);
33773377
if (isa<llvm::InvokeInst>(call))
33783378
IGM.emittedForeignFunctionThunksWithExceptionTraps.insert(thunk);
3379-
subIGF.Builder.CreateRetVoid();
3379+
if (ctorFnType->getReturnType()->isVoidTy())
3380+
subIGF.Builder.CreateRetVoid();
3381+
else
3382+
subIGF.Builder.CreateRet(call);
33803383

33813384
return thunk;
33823385
}
@@ -3448,7 +3451,7 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
34483451
}
34493452

34503453
if (cxxCtor) {
3451-
Signature signature = getSignature(f->getLoweredFunctionType());
3454+
Signature signature = getSignature(f->getLoweredFunctionType(), cxxCtor);
34523455

34533456
// The thunk has private linkage, so it doesn't need to have a predictable
34543457
// mangled name -- we just need to make sure the name is unique.

lib/IRGen/GenFunc.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,15 @@ namespace {
125125
const CanSILFunctionType FormalType;
126126

127127
mutable Signature TheSignature;
128+
mutable Signature TheCXXConstructorSignature;
128129

129130
public:
130131
FuncSignatureInfo(CanSILFunctionType formalType)
131132
: FormalType(formalType) {}
132133

134+
Signature
135+
getCXXConstructorSignature(const clang::CXXConstructorDecl *cxxCtorDecl,
136+
IRGenModule &IGM) const;
133137
Signature getSignature(IRGenModule &IGM) const;
134138
};
135139

@@ -677,6 +681,20 @@ Signature FuncSignatureInfo::getSignature(IRGenModule &IGM) const {
677681
return TheSignature;
678682
}
679683

684+
Signature FuncSignatureInfo::getCXXConstructorSignature(
685+
const clang::CXXConstructorDecl *cxxCtorDecl, IRGenModule &IGM) const {
686+
// If it's already been filled in, we're done.
687+
if (TheCXXConstructorSignature.isValid())
688+
return TheCXXConstructorSignature;
689+
690+
// Update the cache and return.
691+
TheCXXConstructorSignature =
692+
Signature::getUncached(IGM, FormalType, FunctionPointerKind(FormalType),
693+
/*forStaticCall*/ false, cxxCtorDecl);
694+
assert(TheCXXConstructorSignature.isValid());
695+
return TheCXXConstructorSignature;
696+
}
697+
680698
Signature ObjCFuncSignatureInfo::getDirectSignature(IRGenModule &IGM) const {
681699
// If it's already been filled in, we're done.
682700
if (TheDirectSignature.isValid())
@@ -711,13 +729,17 @@ getFuncSignatureInfoForLowered(IRGenModule &IGM, CanSILFunctionType type) {
711729
llvm_unreachable("bad function type representation");
712730
}
713731

714-
Signature IRGenModule::getSignature(CanSILFunctionType type) {
715-
return getSignature(type, FunctionPointerKind(type));
732+
Signature
733+
IRGenModule::getSignature(CanSILFunctionType type,
734+
const clang::CXXConstructorDecl *cxxCtorDecl) {
735+
return getSignature(type, FunctionPointerKind(type), /*forStaticCall*/ false,
736+
cxxCtorDecl);
716737
}
717738

718-
Signature IRGenModule::getSignature(CanSILFunctionType type,
719-
FunctionPointerKind kind,
720-
bool forStaticCall) {
739+
Signature
740+
IRGenModule::getSignature(CanSILFunctionType type, FunctionPointerKind kind,
741+
bool forStaticCall,
742+
const clang::CXXConstructorDecl *cxxCtorDecl) {
721743
// Don't bother caching if we're working with a special kind.
722744
if (kind.isSpecial())
723745
return Signature::getUncached(*this, type, kind);
@@ -729,6 +751,10 @@ Signature IRGenModule::getSignature(CanSILFunctionType type,
729751
auto &objcSigInfo = static_cast<const ObjCFuncSignatureInfo &>(sigInfo);
730752
return objcSigInfo.getDirectSignature(*this);
731753
}
754+
755+
if (cxxCtorDecl)
756+
return sigInfo.getCXXConstructorSignature(cxxCtorDecl, *this);
757+
732758
return sigInfo.getSignature(*this);
733759
}
734760

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ namespace {
628628
auto clangFnAddr =
629629
IGF.IGM.getAddrOfClangGlobalDecl(globalDecl, NotForDefinition);
630630
auto callee = cast<llvm::Function>(clangFnAddr->stripPointerCasts());
631-
Signature signature = IGF.IGM.getSignature(fnType);
631+
Signature signature = IGF.IGM.getSignature(fnType, copyConstructor);
632632
std::string name = "__swift_cxx_copy_ctor" + callee->getName().str();
633633
auto *origClangFnAddr = clangFnAddr;
634634
clangFnAddr = emitCXXConstructorThunkIfNeeded(

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,10 +1513,13 @@ private: \
15131513
void finalizeClangCodeGen();
15141514
void finishEmitAfterTopLevel();
15151515

1516-
Signature getSignature(CanSILFunctionType fnType);
1517-
Signature getSignature(CanSILFunctionType fnType,
1518-
FunctionPointerKind kind,
1519-
bool forStaticCall = false);
1516+
Signature
1517+
getSignature(CanSILFunctionType fnType,
1518+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr);
1519+
Signature
1520+
getSignature(CanSILFunctionType fnType, FunctionPointerKind kind,
1521+
bool forStaticCall = false,
1522+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr);
15201523
llvm::FunctionType *getFunctionType(CanSILFunctionType type,
15211524
llvm::AttributeList &attrs,
15221525
ForeignFunctionInfo *foreignInfo=nullptr);

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2892,8 +2892,13 @@ void IRGenSILFunction::visitFunctionRefBaseInst(FunctionRefBaseInst *i) {
28922892
auto fnType = fn->getLoweredFunctionType();
28932893

28942894
auto fpKind = irgen::classifyFunctionPointerKind(fn);
2895+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr;
28952896

2896-
auto sig = IGM.getSignature(fnType, fpKind, true /*forStaticCall*/);
2897+
if (auto *clangFnDecl = fn->getClangDecl())
2898+
cxxCtorDecl = dyn_cast<clang::CXXConstructorDecl>(clangFnDecl);
2899+
2900+
auto sig =
2901+
IGM.getSignature(fnType, fpKind, true /*forStaticCall*/, cxxCtorDecl);
28972902

28982903
// Note that the pointer value returned by getAddrOfSILFunction doesn't
28992904
// necessarily have element type sig.getType(), e.g. if it's imported.

lib/IRGen/Signature.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace llvm {
3131
}
3232

3333
namespace clang {
34+
class CXXConstructorDecl;
3435
namespace CodeGen {
3536
class CGFunctionInfo;
3637
}
@@ -202,9 +203,10 @@ class Signature {
202203
/// This is a private detail of the implementation of
203204
/// IRGenModule::getSignature(CanSILFunctionType), which is what
204205
/// clients should generally be using.
205-
static Signature getUncached(IRGenModule &IGM, CanSILFunctionType formalType,
206-
FunctionPointerKind kind,
207-
bool forStaticCall = false);
206+
static Signature
207+
getUncached(IRGenModule &IGM, CanSILFunctionType formalType,
208+
FunctionPointerKind kind, bool forStaticCall = false,
209+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr);
208210

209211
static SignatureExpansionABIDetails
210212
getUncachedABIDetails(IRGenModule &IGM, CanSILFunctionType formalType,

test/Interop/Cxx/class/method/methods-this-and-indirect-return-irgen-itanium.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ public func use() -> CInt {
1212

1313
// CHECK: %[[instance:.*]] = alloca %TSo10HasMethodsV
1414
// CHECK: %[[result:.*]] = alloca %TSo19NonTrivialInWrapperV
15-
// CHECK: call void @_ZN10HasMethods28nonConstPassThroughAsWrapperEi(ptr sret(%struct.NonTrivialInWrapper) %[[result]], ptr %[[instance]], i32 42)
15+
// CHECK: call void @_ZN10HasMethods28nonConstPassThroughAsWrapperEi(ptr noalias sret(%TSo19NonTrivialInWrapperV) %[[result]], ptr %[[instance]], i32 42)
1616

1717
// CHECK: define {{.*}} void @_ZN10HasMethods28nonConstPassThroughAsWrapperEi(ptr noalias sret(%struct.NonTrivialInWrapper) {{.*}} %{{.*}}, ptr {{.*}} %{{.*}}, i32 noundef %{{.*}})

0 commit comments

Comments
 (0)