Skip to content

Commit b3f302b

Browse files
authored
[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
1 parent 2a03207 commit b3f302b

File tree

11 files changed

+199
-54
lines changed

11 files changed

+199
-54
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/SIL/SILModule.h"
2626
#include "swift/SIL/SILType.h"
2727
#include "clang/AST/ASTContext.h"
28+
#include "clang/AST/GlobalDecl.h"
2829
#include "clang/AST/RecordLayout.h"
2930
#include "clang/Basic/TargetInfo.h"
3031
#include "clang/CodeGen/CodeGenABITypes.h"
@@ -428,6 +429,10 @@ namespace {
428429
IRGenModule &IGM;
429430
CanSILFunctionType FnType;
430431
bool forStaticCall = false; // Used for objc_method (direct call or not).
432+
433+
// Indicates this is a c++ constructor call.
434+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr;
435+
431436
public:
432437
SmallVector<llvm::Type*, 8> ParamIRTypes;
433438
llvm::Type *ResultIRType = nullptr;
@@ -442,8 +447,10 @@ namespace {
442447
FunctionPointerKind FnKind;
443448

444449
SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
445-
FunctionPointerKind fnKind, bool forStaticCall = false)
446-
: IGM(IGM), FnType(fnType), forStaticCall(forStaticCall), FnKind(fnKind) {}
450+
FunctionPointerKind fnKind, bool forStaticCall = false,
451+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr)
452+
: IGM(IGM), FnType(fnType), forStaticCall(forStaticCall),
453+
cxxCtorDecl(cxxCtorDecl), FnKind(fnKind) {}
447454

448455
/// Expand the components of the primary entrypoint of the function type.
449456
void expandFunctionType(
@@ -468,7 +475,7 @@ namespace {
468475

469476
private:
470477
const TypeInfo &expand(SILParameterInfo param);
471-
llvm::Type *addIndirectResult();
478+
llvm::Type *addIndirectResult(SILType resultType);
472479

473480
SILFunctionConventions getSILFuncConventions() const {
474481
return SILFunctionConventions(FnType, IGM.getSILModule());
@@ -526,9 +533,7 @@ namespace {
526533
} // end namespace irgen
527534
} // end namespace swift
528535

529-
llvm::Type *SignatureExpansion::addIndirectResult() {
530-
auto resultType = getSILFuncConventions().getSILResultType(
531-
IGM.getMaximalTypeExpansionContext());
536+
llvm::Type *SignatureExpansion::addIndirectResult(SILType resultType) {
532537
const TypeInfo &resultTI = IGM.getTypeInfo(resultType);
533538
auto storageTy = resultTI.getStorageType();
534539
addIndirectResultAttributes(IGM, Attrs, ParamIRTypes.size(), claimSRet(),
@@ -925,7 +930,7 @@ SignatureExpansion::expandDirectResult() {
925930
auto &ti = IGM.getTypeInfo(resultType);
926931
auto &native = ti.nativeReturnValueSchema(IGM);
927932
if (native.requiresIndirect())
928-
return std::make_pair(addIndirectResult(), nullptr);
933+
return std::make_pair(addIndirectResult(resultType), nullptr);
929934

930935
// Disable the use of sret if we have a non-trivial direct result.
931936
if (!native.empty()) CanUseSRet = false;
@@ -1361,26 +1366,28 @@ static bool doesClangExpansionMatchSchema(IRGenModule &IGM,
13611366
void SignatureExpansion::expandExternalSignatureTypes() {
13621367
assert(FnType->getLanguage() == SILFunctionLanguage::C);
13631368

1364-
// Convert the SIL result type to a Clang type.
1365-
auto clangResultTy =
1366-
IGM.getClangType(FnType->getFormalCSemanticResult(IGM.getSILModule()));
1369+
auto SILResultTy = [&]() {
1370+
if (FnType->getNumResults() == 0)
1371+
return SILType::getPrimitiveObjectType(IGM.Context.TheEmptyTupleType);
1372+
1373+
return SILType::getPrimitiveObjectType(
1374+
FnType->getSingleResult().getReturnValueType(
1375+
IGM.getSILModule(), FnType, TypeExpansionContext::minimal()));
1376+
}();
1377+
1378+
// Convert the SIL result type to a Clang type. If this is for a c++
1379+
// constructor, use 'void' as the return type to arrange the function type.
1380+
auto clangResultTy = IGM.getClangType(
1381+
cxxCtorDecl
1382+
? SILType::getPrimitiveObjectType(IGM.Context.TheEmptyTupleType)
1383+
: SILResultTy);
13671384

13681385
// Now convert the parameters to Clang types.
13691386
auto params = FnType->getParameters();
13701387

13711388
SmallVector<clang::CanQualType,4> paramTys;
13721389
auto const &clangCtx = IGM.getClangASTContext();
13731390

1374-
bool formalIndirectResult = FnType->getNumResults() > 0 &&
1375-
FnType->getSingleResult().isFormalIndirect();
1376-
if (formalIndirectResult) {
1377-
auto resultType = getSILFuncConventions().getSingleSILResultType(
1378-
IGM.getMaximalTypeExpansionContext());
1379-
auto clangTy =
1380-
IGM.getClangASTContext().getPointerType(IGM.getClangType(resultType));
1381-
paramTys.push_back(clangTy);
1382-
}
1383-
13841391
switch (FnType->getRepresentation()) {
13851392
case SILFunctionTypeRepresentation::ObjCMethod: {
13861393
// ObjC methods take their 'self' argument first, followed by an
@@ -1409,7 +1416,11 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14091416
}
14101417

14111418
case SILFunctionTypeRepresentation::CFunctionPointer:
1412-
// No implicit arguments.
1419+
if (cxxCtorDecl) {
1420+
auto clangTy = IGM.getClangASTContext().getPointerType(
1421+
IGM.getClangType(SILResultTy));
1422+
paramTys.push_back(clangTy);
1423+
}
14131424
break;
14141425

14151426
case SILFunctionTypeRepresentation::Thin:
@@ -1437,6 +1448,7 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14371448

14381449
// Generate function info for this signature.
14391450
auto extInfo = clang::FunctionType::ExtInfo();
1451+
14401452
auto &FI = clang::CodeGen::arrangeFreeFunctionCall(IGM.ClangCodeGen->CGM(),
14411453
clangResultTy, paramTys, extInfo,
14421454
clang::CodeGen::RequiredArgs::All);
@@ -1447,6 +1459,14 @@ void SignatureExpansion::expandExternalSignatureTypes() {
14471459

14481460
auto &returnInfo = FI.getReturnInfo();
14491461

1462+
#ifndef NDEBUG
1463+
bool formalIndirectResult = FnType->getNumResults() > 0 &&
1464+
FnType->getSingleResult().isFormalIndirect();
1465+
assert(
1466+
(cxxCtorDecl || !formalIndirectResult || returnInfo.isIndirect()) &&
1467+
"swift and clang disagree on whether the result is returned indirectly");
1468+
#endif
1469+
14501470
// Does the result need an extension attribute?
14511471
if (returnInfo.isExtend()) {
14521472
bool signExt = clangResultTy->hasSignedIntegerRepresentation();
@@ -1551,16 +1571,18 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15511571

15521572
// If we return indirectly, that is the first parameter type.
15531573
if (returnInfo.isIndirect()) {
1574+
auto resultType = getSILFuncConventions().getSingleSILResultType(
1575+
IGM.getMaximalTypeExpansionContext());
15541576
if (IGM.Triple.isWindowsMSVCEnvironment() &&
15551577
FnType->getRepresentation() ==
15561578
SILFunctionTypeRepresentation::CXXMethod) {
15571579
// Windows ABI places `this` before the
15581580
// returned indirect values.
15591581
emitArg(0);
15601582
firstParamToLowerNormally = 1;
1561-
addIndirectResult();
1583+
addIndirectResult(resultType);
15621584
} else
1563-
addIndirectResult();
1585+
addIndirectResult(resultType);
15641586
}
15651587

15661588
// Use a special IR type for passing block pointers.
@@ -1574,7 +1596,12 @@ void SignatureExpansion::expandExternalSignatureTypes() {
15741596
for (auto i : indices(paramTys).slice(firstParamToLowerNormally))
15751597
emitArg(i);
15761598

1577-
if (returnInfo.isIndirect() || returnInfo.isIgnore()) {
1599+
if (cxxCtorDecl) {
1600+
ResultIRType = cast<llvm::Function>(IGM.getAddrOfClangGlobalDecl(
1601+
{cxxCtorDecl, clang::Ctor_Complete},
1602+
(ForDefinition_t) false))
1603+
->getReturnType();
1604+
} else if (returnInfo.isIndirect() || returnInfo.isIgnore()) {
15781605
ResultIRType = IGM.VoidTy;
15791606
} else {
15801607
ResultIRType = returnInfo.getCoerceToType();
@@ -1986,7 +2013,7 @@ void SignatureExpansion::expandAsyncEntryType() {
19862013
auto &ti = IGM.getTypeInfo(resultType);
19872014
auto &native = ti.nativeReturnValueSchema(IGM);
19882015
if (native.requiresIndirect())
1989-
addIndirectResult();
2016+
addIndirectResult(resultType);
19902017

19912018
// Add the indirect result types.
19922019
expandIndirectResults();
@@ -2153,10 +2180,11 @@ Signature SignatureExpansion::getSignature() {
21532180

21542181
Signature Signature::getUncached(IRGenModule &IGM,
21552182
CanSILFunctionType formalType,
2156-
FunctionPointerKind fpKind,
2157-
bool forStaticCall) {
2183+
FunctionPointerKind fpKind, bool forStaticCall,
2184+
const clang::CXXConstructorDecl *cxxCtorDecl) {
21582185
GenericContextScope scope(IGM, formalType->getInvocationGenericSignature());
2159-
SignatureExpansion expansion(IGM, formalType, fpKind, forStaticCall);
2186+
SignatureExpansion expansion(IGM, formalType, fpKind, forStaticCall,
2187+
cxxCtorDecl);
21602188
expansion.expandFunctionType();
21612189
return expansion.getSignature();
21622190
}
@@ -3235,7 +3263,13 @@ llvm::CallBase *IRBuilder::CreateCallOrInvoke(
32353263
for (unsigned argIndex = 0; argIndex < func->arg_size(); ++argIndex) {
32363264
if (func->hasParamAttribute(argIndex, llvm::Attribute::StructRet)) {
32373265
llvm::AttrBuilder builder(func->getContext());
3238-
builder.addStructRetAttr(func->getParamStructRetType(argIndex));
3266+
// See if there is a sret parameter in the signature. There are cases
3267+
// where the called function has a sret parameter, but the signature
3268+
// doesn't (e.g., noreturn functions).
3269+
llvm::Type *ty = attrs.getParamStructRetType(argIndex);
3270+
if (!ty)
3271+
ty = func->getParamStructRetType(argIndex);
3272+
builder.addStructRetAttr(ty);
32393273
attrs = attrs.addParamAttributes(func->getContext(), argIndex, builder);
32403274
}
32413275
if (func->hasParamAttribute(argIndex, llvm::Attribute::ByVal)) {
@@ -3950,11 +3984,13 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
39503984
params = params.drop_back();
39513985
}
39523986

3953-
if (fnType->getNumResults() > 0 &&
3954-
fnType->getSingleResult().isFormalIndirect()) {
3955-
// Ignore the indirect result parameter.
3987+
bool formalIndirectResult = fnType->getNumResults() > 0 &&
3988+
fnType->getSingleResult().isFormalIndirect();
3989+
3990+
// If clang returns directly and swift returns indirectly, this must be a c++
3991+
// constructor call. In that case, skip the "self" param.
3992+
if (!FI.getReturnInfo().isIndirect() && formalIndirectResult)
39563993
firstParam += 1;
3957-
}
39583994

39593995
for (unsigned i = firstParam; i != paramEnd; ++i) {
39603996
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
@@ -3511,7 +3511,10 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded(
35113511
emitCXXConstructorCall(subIGF, ctor, ctorFnType, ctorAddress, Args);
35123512
if (isa<llvm::InvokeInst>(call))
35133513
IGM.emittedForeignFunctionThunksWithExceptionTraps.insert(thunk);
3514-
subIGF.Builder.CreateRetVoid();
3514+
if (ctorFnType->getReturnType()->isVoidTy())
3515+
subIGF.Builder.CreateRetVoid();
3516+
else
3517+
subIGF.Builder.CreateRet(call);
35153518

35163519
return thunk;
35173520
}
@@ -3583,7 +3586,7 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(
35833586
}
35843587

35853588
if (cxxCtor) {
3586-
Signature signature = getSignature(f->getLoweredFunctionType());
3589+
Signature signature = getSignature(f->getLoweredFunctionType(), cxxCtor);
35873590

35883591
// The thunk has private linkage, so it doesn't need to have a predictable
35893592
// 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

@@ -674,6 +678,20 @@ Signature FuncSignatureInfo::getSignature(IRGenModule &IGM) const {
674678
return TheSignature;
675679
}
676680

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

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

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

lib/IRGen/GenStruct.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ namespace {
620620
auto clangFnAddr =
621621
IGF.IGM.getAddrOfClangGlobalDecl(globalDecl, NotForDefinition);
622622
auto callee = cast<llvm::Function>(clangFnAddr->stripPointerCasts());
623-
Signature signature = IGF.IGM.getSignature(fnType);
623+
Signature signature = IGF.IGM.getSignature(fnType, copyConstructor);
624624
std::string name = "__swift_cxx_copy_ctor" + callee->getName().str();
625625
auto *origClangFnAddr = clangFnAddr;
626626
clangFnAddr = emitCXXConstructorThunkIfNeeded(

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,10 +1574,13 @@ private: \
15741574
void finalizeClangCodeGen();
15751575
void finishEmitAfterTopLevel();
15761576

1577-
Signature getSignature(CanSILFunctionType fnType);
1578-
Signature getSignature(CanSILFunctionType fnType,
1579-
FunctionPointerKind kind,
1580-
bool forStaticCall = false);
1577+
Signature
1578+
getSignature(CanSILFunctionType fnType,
1579+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr);
1580+
Signature
1581+
getSignature(CanSILFunctionType fnType, FunctionPointerKind kind,
1582+
bool forStaticCall = false,
1583+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr);
15811584
llvm::FunctionType *getFunctionType(CanSILFunctionType type,
15821585
llvm::AttributeList &attrs,
15831586
ForeignFunctionInfo *foreignInfo=nullptr);

lib/IRGen/IRGenSIL.cpp

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

29712971
auto fpKind = irgen::classifyFunctionPointerKind(fn);
2972+
const clang::CXXConstructorDecl *cxxCtorDecl = nullptr;
29722973

2973-
auto sig = IGM.getSignature(fnType, fpKind, true /*forStaticCall*/);
2974+
if (auto *clangFnDecl = fn->getClangDecl())
2975+
cxxCtorDecl = dyn_cast<clang::CXXConstructorDecl>(clangFnDecl);
2976+
2977+
auto sig =
2978+
IGM.getSignature(fnType, fpKind, true /*forStaticCall*/, cxxCtorDecl);
29742979

29752980
// Note that the pointer value returned by getAddrOfSILFunction doesn't
29762981
// 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,

0 commit comments

Comments
 (0)