Skip to content

Commit 1aa18c9

Browse files
Merge pull request #23112 from aschwaighofer/irgen_noreturn_c_function_calls
IRGen: Teach IRGen about calling noreturn C functions
2 parents 1dd4a1e + 135e73d commit 1aa18c9

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
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
}

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)