Skip to content

Commit 632c9ff

Browse files
authored
Merge pull request #34793 from aschwaighofer/irgen_async_silgen_name
IRGen: Allow calling a pre-defined async silgen_name function using the async convention
2 parents 03646be + fbfcaab commit 632c9ff

File tree

5 files changed

+64
-22
lines changed

5 files changed

+64
-22
lines changed

lib/IRGen/Callee.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,23 +155,28 @@ namespace irgen {
155155

156156
Signature Sig;
157157

158+
bool isFunctionPointerWithoutContext = false;
159+
158160
public:
159161
/// Construct a FunctionPointer for an arbitrary pointer value.
160162
/// We may add more arguments to this; try to use the other
161163
/// constructors/factories if possible.
162164
explicit FunctionPointer(KindTy kind, llvm::Value *value,
163165
PointerAuthInfo authInfo,
164-
const Signature &signature)
165-
: Kind(kind), Value(value), AuthInfo(authInfo), Sig(signature) {
166+
const Signature &signature,
167+
bool isWithoutCtxt = false)
168+
: Kind(kind), Value(value), AuthInfo(authInfo), Sig(signature),
169+
isFunctionPointerWithoutContext(isWithoutCtxt) {
166170
// The function pointer should have function type.
167171
assert(value->getType()->getPointerElementType()->isFunctionTy());
168172
// TODO: maybe assert similarity to signature.getType()?
169173
}
170174

171175
// Temporary only!
172176
explicit FunctionPointer(KindTy kind, llvm::Value *value,
173-
const Signature &signature)
174-
: FunctionPointer(kind, value, PointerAuthInfo(), signature) {}
177+
const Signature &signature, bool
178+
isWithoutCtxt = false)
179+
: FunctionPointer(kind, value, PointerAuthInfo(), signature, isWithoutCtxt) {}
175180

176181
static FunctionPointer forDirect(IRGenModule &IGM,
177182
llvm::Constant *value,
@@ -243,6 +248,10 @@ namespace irgen {
243248

244249
/// Form a FunctionPointer whose KindTy is ::Function.
245250
FunctionPointer getAsFunction(IRGenFunction &IGF) const;
251+
252+
bool useStaticContextSize() const {
253+
return isFunctionPointerWithoutContext;
254+
}
246255
};
247256

248257
class Callee {

lib/IRGen/GenCall.cpp

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,7 +1830,7 @@ void irgen::extractScalarResults(IRGenFunction &IGF, llvm::Type *bodyType,
18301830
std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
18311831
IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
18321832
FunctionPointer functionPointer, llvm::Value *thickContext,
1833-
std::pair<bool, bool> values) {
1833+
std::pair<bool, bool> values, Size initialContextSize) {
18341834
assert(values.first || values.second);
18351835
bool emitFunction = values.first;
18361836
bool emitSize = values.second;
@@ -1997,11 +1997,16 @@ std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
19971997
}
19981998
llvm::Value *size = nullptr;
19991999
if (emitSize) {
2000-
auto *ptr = functionPointer.getRawPointer();
2001-
auto *descriptorPtr =
2002-
IGF.Builder.CreateBitCast(ptr, IGF.IGM.AsyncFunctionPointerPtrTy);
2003-
auto *sizePtr = IGF.Builder.CreateStructGEP(descriptorPtr, 1);
2004-
size = IGF.Builder.CreateLoad(sizePtr, IGF.IGM.getPointerAlignment());
2000+
if (functionPointer.useStaticContextSize()) {
2001+
size = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
2002+
initialContextSize.getValue());
2003+
} else {
2004+
auto *ptr = functionPointer.getRawPointer();
2005+
auto *descriptorPtr =
2006+
IGF.Builder.CreateBitCast(ptr, IGF.IGM.AsyncFunctionPointerPtrTy);
2007+
auto *sizePtr = IGF.Builder.CreateStructGEP(descriptorPtr, 1);
2008+
size = IGF.Builder.CreateLoad(sizePtr, IGF.IGM.getPointerAlignment());
2009+
}
20052010
}
20062011
return {fn, size};
20072012
}
@@ -2270,7 +2275,8 @@ class AsyncCallEmission final : public CallEmission {
22702275
llvm::Value *dynamicContextSize32;
22712276
std::tie(calleeFunction, dynamicContextSize32) = getAsyncFunctionAndSize(
22722277
IGF, CurCallee.getOrigFunctionType()->getRepresentation(),
2273-
CurCallee.getFunctionPointer(), thickContext);
2278+
CurCallee.getFunctionPointer(), thickContext,
2279+
std::make_pair(true, true), layout.getSize());
22742280
auto *dynamicContextSize =
22752281
IGF.Builder.CreateZExt(dynamicContextSize32, IGF.IGM.SizeTy);
22762282
contextBuffer = emitAllocAsyncContext(IGF, dynamicContextSize);
@@ -4494,13 +4500,20 @@ llvm::Value *FunctionPointer::getPointer(IRGenFunction &IGF) const {
44944500
switch (Kind.value) {
44954501
case KindTy::Value::Function:
44964502
return Value;
4497-
case KindTy::Value::AsyncFunctionPointer:
4498-
auto *descriptorPtr =
4499-
IGF.Builder.CreateBitCast(Value, IGF.IGM.AsyncFunctionPointerPtrTy);
4500-
auto *addrPtr = IGF.Builder.CreateStructGEP(descriptorPtr, 0);
4501-
return IGF.emitLoadOfRelativePointer(
4502-
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
4503-
/*expectedType*/ getFunctionType()->getPointerTo());
4503+
case KindTy::Value::AsyncFunctionPointer: {
4504+
if (!isFunctionPointerWithoutContext) {
4505+
auto *descriptorPtr =
4506+
IGF.Builder.CreateBitCast(Value, IGF.IGM.AsyncFunctionPointerPtrTy);
4507+
auto *addrPtr = IGF.Builder.CreateStructGEP(descriptorPtr, 0);
4508+
return IGF.emitLoadOfRelativePointer(
4509+
Address(addrPtr, IGF.IGM.getPointerAlignment()), /*isFar*/ false,
4510+
/*expectedType*/ getFunctionType()->getPointerTo());
4511+
} else {
4512+
return IGF.Builder.CreateBitOrPointerCast(
4513+
Value, getFunctionType()->getPointerTo());
4514+
}
4515+
}
4516+
45044517
}
45054518
}
45064519

lib/IRGen/GenCall.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ namespace irgen {
313313
std::pair<llvm::Value *, llvm::Value *> getAsyncFunctionAndSize(
314314
IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
315315
FunctionPointer functionPointer, llvm::Value *thickContext,
316-
std::pair<bool, bool> values = {true, true});
316+
std::pair<bool, bool> values = {true, true},
317+
Size initialContextSize = Size(0));
317318
llvm::CallingConv::ID expandCallingConv(IRGenModule &IGM,
318319
SILFunctionTypeRepresentation convention);
319320

lib/IRGen/IRGenSIL.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,13 +2288,16 @@ void IRGenSILFunction::visitFunctionRefBaseInst(FunctionRefBaseInst *i) {
22882288
fn, NotForDefinition, false /*isDynamicallyReplaceableImplementation*/,
22892289
isa<PreviousDynamicFunctionRefInst>(i));
22902290
llvm::Value *value;
2291-
if (fn->isAsync()) {
2291+
auto isSpecialAsyncWithoutCtxtSize =
2292+
fn->isAsync() && fn->getName().equals("swift_task_future_wait");
2293+
if (fn->isAsync() && !isSpecialAsyncWithoutCtxtSize) {
22922294
value = IGM.getAddrOfAsyncFunctionPointer(fn);
22932295
value = Builder.CreateBitCast(value, fnPtr->getType());
22942296
} else {
22952297
value = fnPtr;
22962298
}
2297-
FunctionPointer fp = FunctionPointer(fnType, value, sig);
2299+
FunctionPointer fp =
2300+
FunctionPointer(fnType, value, sig, isSpecialAsyncWithoutCtxtSize);
22982301

22992302
// Store the function as a FunctionPointer so we can avoid bitcasting
23002303
// or thunking if we don't need to.

test/IRGen/async.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-experimental-concurrency | %FileCheck %s
1+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -enable-experimental-concurrency | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
22

33
// REQUIRES: concurrency
44

@@ -8,3 +8,19 @@ public func f() async { }
88
// CHECK: "$s5async1gyyYKF"
99
public func g() async throws { }
1010

11+
12+
public class SomeClass {}
13+
14+
@_silgen_name("swift_task_future_wait")
15+
public func task_future_wait(_ task: __owned SomeClass) async throws -> Int
16+
17+
// CHECK: define{{.*}} swiftcc void @"$s5async8testThisyyAA9SomeClassCnYF"(%swift.task* %0, %swift.executor* %1, %swift.context* %2)
18+
// CHECK-64: call swiftcc i8* @swift_task_alloc(%swift.task* %0, i64 64)
19+
// CHECK: tail call swiftcc void @swift_task_future_wait(
20+
public func testThis(_ task: __owned SomeClass) async {
21+
do {
22+
let _ = try await task_future_wait(task)
23+
} catch _ {
24+
print("error")
25+
}
26+
}

0 commit comments

Comments
 (0)