Skip to content

Commit cf177cc

Browse files
committed
Merge remote-tracking branch 'origin/master' into master-next
2 parents 62bb7ff + f6aaf8a commit cf177cc

File tree

4 files changed

+189
-29
lines changed

4 files changed

+189
-29
lines changed

lib/IRGen/GenCall.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,17 @@ void CallEmission::emitToUnmappedExplosion(Explosion &out) {
15141514
result = emitObjCRetainAutoreleasedReturnValue(IGF, result);
15151515
}
15161516

1517+
auto origFnType = getCallee().getOrigFunctionType();
1518+
1519+
// Specially handle noreturn c function which would return a 'Never' SIL result
1520+
// type.
1521+
if (origFnType->getLanguage() == SILFunctionLanguage::C &&
1522+
origFnType->isNoReturnFunction()) {
1523+
auto clangResultTy = result->getType();
1524+
extractScalarResults(IGF, clangResultTy, result, out);
1525+
return;
1526+
}
1527+
15171528
// Get the natural IR type in the body of the function that makes
15181529
// the call. This may be different than the IR type returned by the
15191530
// call itself due to ABI type coercion.
@@ -1527,7 +1538,6 @@ void CallEmission::emitToUnmappedExplosion(Explosion &out) {
15271538
// for methods that have covariant ABI-compatible overrides.
15281539
auto expectedNativeResultType = nativeSchema.getExpandedType(IGF.IGM);
15291540
if (result->getType() != expectedNativeResultType) {
1530-
auto origFnType = getCallee().getOrigFunctionType();
15311541
assert(origFnType->getLanguage() == SILFunctionLanguage::C ||
15321542
origFnType->getRepresentation() == SILFunctionTypeRepresentation::Method);
15331543
result =
@@ -1783,9 +1793,23 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
17831793
auto &substResultTI =
17841794
cast<LoadableTypeInfo>(IGF.getTypeInfo(substResultType));
17851795

1796+
auto origFnType = getCallee().getOrigFunctionType();
1797+
auto isNoReturnCFunction =
1798+
origFnType->getLanguage() == SILFunctionLanguage::C &&
1799+
origFnType->isNoReturnFunction();
1800+
17861801
// If the call is naturally to memory, emit it that way and then
17871802
// explode that temporary.
17881803
if (LastArgWritten == 1) {
1804+
if (isNoReturnCFunction) {
1805+
auto fnType = getCallee().getFunctionPointer().getFunctionType();
1806+
assert(fnType->getNumParams() > 0);
1807+
auto resultTy = fnType->getParamType(0)->getPointerElementType();
1808+
auto temp = IGF.createAlloca(resultTy, Alignment(0), "indirect.result");
1809+
emitToMemory(temp, substResultTI, isOutlined);
1810+
return;
1811+
}
1812+
17891813
StackAddress ctemp = substResultTI.allocateStack(IGF, substResultType,
17901814
"call.aggresult");
17911815
Address temp = ctemp.getAddress();
@@ -1802,6 +1826,13 @@ void CallEmission::emitToExplosion(Explosion &out, bool isOutlined) {
18021826
Explosion temp;
18031827
emitToUnmappedExplosion(temp);
18041828

1829+
// Specially handle noreturn c function which would return a 'Never' SIL result
1830+
// type: there is no need to cast the result.
1831+
if (isNoReturnCFunction) {
1832+
temp.transferInto(out, temp.size());
1833+
return;
1834+
}
1835+
18051836
// We might need to bitcast the results.
18061837
emitCastToSubstSchema(IGF, temp, substResultTI.getSchema(), out);
18071838
}

lib/IRGen/IRGen.cpp

Lines changed: 107 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -873,26 +873,109 @@ performIRGeneration(IRGenOptions &Opts, ModuleDecl *M,
873873
return std::unique_ptr<llvm::Module>(IGM.releaseModule());
874874
}
875875

876-
static void ThreadEntryPoint(IRGenerator *irgen,
877-
llvm::sys::Mutex *DiagMutex, int ThreadIdx) {
878-
while (IRGenModule *IGM = irgen->fetchFromQueue()) {
879-
LLVM_DEBUG(DiagMutex->lock(); dbgs() << "thread " << ThreadIdx
880-
<< ": fetched "
881-
<< IGM->OutputFilename << "\n";
882-
DiagMutex->unlock(););
883-
embedBitcode(IGM->getModule(), irgen->Opts);
884-
performLLVM(irgen->Opts, &IGM->Context.Diags, DiagMutex, IGM->ModuleHash,
885-
IGM->getModule(), IGM->TargetMachine.get(),
886-
IGM->Context.LangOpts.EffectiveLanguageVersion,
887-
IGM->OutputFilename, IGM->Context.Stats);
888-
if (IGM->Context.Diags.hadAnyError())
876+
namespace {
877+
struct LLVMCodeGenThreads {
878+
879+
struct Thread {
880+
LLVMCodeGenThreads &parent;
881+
unsigned threadIndex;
882+
#ifdef __APPLE__
883+
pthread_t threadId;
884+
#else
885+
std::thread *thread;
886+
#endif
887+
888+
Thread(LLVMCodeGenThreads &parent, unsigned threadIndex)
889+
: parent(parent), threadIndex(threadIndex)
890+
#ifndef __APPLE__
891+
, thread(nullptr)
892+
#endif
893+
{}
894+
895+
/// Run llvm codegen.
896+
void run() {
897+
auto *diagMutex = parent.diagMutex;
898+
while (IRGenModule *IGM = parent.irgen->fetchFromQueue()) {
899+
LLVM_DEBUG(diagMutex->lock();
900+
dbgs() << "thread " << threadIndex << ": fetched "
901+
<< IGM->OutputFilename << "\n";
902+
diagMutex->unlock(););
903+
embedBitcode(IGM->getModule(), parent.irgen->Opts);
904+
performLLVM(parent.irgen->Opts, &IGM->Context.Diags, diagMutex,
905+
IGM->ModuleHash, IGM->getModule(), IGM->TargetMachine.get(),
906+
IGM->Context.LangOpts.EffectiveLanguageVersion,
907+
IGM->OutputFilename, IGM->Context.Stats);
908+
if (IGM->Context.Diags.hadAnyError())
909+
return;
910+
}
911+
LLVM_DEBUG(diagMutex->lock();
912+
dbgs() << "thread " << threadIndex << ": done\n";
913+
diagMutex->unlock(););
889914
return;
915+
}
916+
};
917+
918+
IRGenerator *irgen;
919+
llvm::sys::Mutex *diagMutex;
920+
std::vector<Thread> threads;
921+
922+
LLVMCodeGenThreads(IRGenerator *irgen, llvm::sys::Mutex *diagMutex,
923+
unsigned numThreads)
924+
: irgen(irgen), diagMutex(diagMutex) {
925+
threads.reserve(numThreads);
926+
for (unsigned idx = 0; idx < numThreads; ++idx) {
927+
// the 0-th thread is executed by the main thread.
928+
threads.push_back(Thread(*this, idx + 1));
929+
}
930+
}
931+
932+
static void *runThread(void *arg) {
933+
auto *thread = reinterpret_cast<Thread *>(arg);
934+
thread->run();
935+
return nullptr;
936+
}
937+
938+
void startThreads() {
939+
#ifdef __APPLE__
940+
// Increase the thread stack size on macosx to 8MB (default is 512KB). This
941+
// matches the main thread.
942+
pthread_attr_t stackSizeAttribute;
943+
int err = pthread_attr_init(&stackSizeAttribute);
944+
assert(!err);
945+
err = pthread_attr_setstacksize(&stackSizeAttribute, 8 * 1024 * 1024);
946+
assert(!err);
947+
948+
for (auto &thread : threads) {
949+
pthread_create(&thread.threadId, &stackSizeAttribute,
950+
LLVMCodeGenThreads::runThread, &thread);
951+
}
952+
953+
pthread_attr_destroy(&stackSizeAttribute);
954+
#else
955+
for (auto &thread : threads) {
956+
thread.thread = new std::thread(runThread, &thread);
957+
}
958+
#endif
959+
960+
}
961+
962+
void runMainThread() {
963+
Thread mainThread(*this, 0);
964+
mainThread.run();
890965
}
891-
LLVM_DEBUG(
892-
DiagMutex->lock();
893-
dbgs() << "thread " << ThreadIdx << ": done\n";
894-
DiagMutex->unlock();
895-
);
966+
967+
void join() {
968+
#ifdef __APPLE__
969+
for (auto &thread : threads)
970+
pthread_join(thread.threadId, 0);
971+
#else
972+
for (auto &thread: threads) {
973+
thread.thread->join();
974+
delete thread.thread;
975+
}
976+
#endif
977+
}
978+
};
896979
}
897980

898981
/// Generates LLVM IR, runs the LLVM passes and produces the output files.
@@ -1071,26 +1154,22 @@ static void performParallelIRGeneration(
10711154

10721155
SharedTimer timer("LLVM pipeline");
10731156

1074-
std::vector<std::thread> Threads;
10751157
llvm::sys::Mutex DiagMutex;
10761158

10771159
// Start all the threads and do the LLVM compilation.
1078-
for (int ThreadIdx = 1; ThreadIdx < numThreads; ++ThreadIdx) {
1079-
Threads.push_back(std::thread(ThreadEntryPoint, &irgen, &DiagMutex,
1080-
ThreadIdx));
1081-
}
1160+
LLVMCodeGenThreads codeGenThreads(&irgen, &DiagMutex, numThreads - 1);
1161+
codeGenThreads.startThreads();
10821162

10831163
// Free the memory occupied by the SILModule.
10841164
// Execute this task in parallel to the LLVM compilation.
10851165
auto SILModuleRelease = [&SILMod]() { SILMod.reset(nullptr); };
1086-
Threads.push_back(std::thread(SILModuleRelease));
1166+
auto releaseModuleThread = std::thread(SILModuleRelease);
10871167

1088-
ThreadEntryPoint(&irgen, &DiagMutex, 0);
1168+
codeGenThreads.runMainThread();
10891169

10901170
// Wait for all threads.
1091-
for (std::thread &Thread : Threads) {
1092-
Thread.join();
1093-
}
1171+
releaseModuleThread.join();
1172+
codeGenThreads.join();
10941173
}
10951174

10961175
std::unique_ptr<llvm::Module> swift::performIRGeneration(

test/IRGen/Inputs/noreturn.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
int scalarNoReturn() __attribute__((noreturn));
2+
3+
void voidNoReturn() __attribute__((noreturn));
4+
5+
typedef struct {
6+
long long a;
7+
long long b;
8+
long long c;
9+
long long d;
10+
} Large;
11+
12+
Large largeStructNoReturn() __attribute__((noreturn));
13+
14+
typedef struct {
15+
long a;
16+
long b;
17+
} Small;
18+
19+
Small smallStructNoReturn() __attribute__((noreturn));

test/IRGen/noreturn.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %target-swift-frontend -module-name A -emit-ir -primary-file %s -import-objc-header %S/Inputs/noreturn.h | %FileCheck %s
2+
3+
4+
// CHECK-LABEL: define {{.*}} void @"$s1A018testDirectReturnNoC0yyF"()
5+
// CHECK: call i32 @scalarNoReturn()
6+
// CHECK: unreachable
7+
public func testDirectReturnNoReturn() {
8+
scalarNoReturn()
9+
}
10+
11+
// CHECK-LABEL: define {{.*}} void @"$s1A019testDirect2ReturnNoC0yyF"()
12+
// CHECK: call {{.*}}@smallStructNoReturn({{.*}})
13+
// CHECK: unreachable
14+
public func testDirect2ReturnNoReturn() {
15+
smallStructNoReturn()
16+
}
17+
18+
// CHECK-LABEL: define {{.*}} void @"$s1A020testIndirectReturnNoC0yyF"()
19+
// CHECK: [[INDIRECT_RESULT:%.*]] = alloca %struct.Large
20+
// CHECK: call void @largeStructNoReturn(%struct.Large* {{.*}}[[INDIRECT_RESULT]])
21+
// CHECK: unreachable
22+
public func testIndirectReturnNoReturn() {
23+
largeStructNoReturn()
24+
}
25+
26+
// CHECK-LABEL: define {{.*}} void @"$s1A016testVoidReturnNoC0yyF"()
27+
// CHECK: call void @voidNoReturn()
28+
// CHECK: unreachable
29+
public func testVoidReturnNoReturn() {
30+
voidNoReturn()
31+
}

0 commit comments

Comments
 (0)