Skip to content

Commit 8e9cd5d

Browse files
Merge pull request swiftlang#76150 from aschwaighofer/async_entry_ret_metadata
IRGen: Add metadata for async funclets denoting frame entry and frame exists
2 parents 38ef675 + eaf90df commit 8e9cd5d

File tree

10 files changed

+159
-2
lines changed

10 files changed

+159
-2
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ class IRGenOptions {
478478
// Whether to run the HotColdSplitting pass when optimizing.
479479
unsigned EnableHotColdSplit : 1;
480480

481+
unsigned EmitAsyncFramePushPopMetadata : 1;
482+
481483
/// The number of threads for multi-threaded code generation.
482484
unsigned NumThreads = 0;
483485

@@ -567,7 +569,7 @@ class IRGenOptions {
567569
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
568570
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
569571
UseFragileResilientProtocolWitnesses(false),
570-
EnableHotColdSplit(false),
572+
EnableHotColdSplit(false), EmitAsyncFramePushPopMetadata(false),
571573
CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()),
572574
TypeInfoFilter(TypeInfoDumpFilter::All),
573575
PlatformCCallingConvention(llvm::CallingConv::C), UseCASBackend(false),

include/swift/LLVMPasses/Passes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ namespace swift {
149149
llvm::PreservedAnalyses run(llvm::Module &M,
150150
llvm::ModuleAnalysisManager &AM);
151151
};
152+
153+
struct AsyncEntryReturnMetadataPass
154+
: public llvm::PassInfoMixin<AsyncEntryReturnMetadataPass> {
155+
llvm::PreservedAnalyses run(llvm::Module &M,
156+
llvm::ModuleAnalysisManager &AM);
157+
};
152158
} // end namespace swift
153159

154160
#endif

include/swift/Option/FrontendOptions.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,13 @@ def disable_fragile_resilient_protocol_witnesses :
13151315
Flag<["-"], "disable-fragile-relative-protocol-tables">,
13161316
HelpText<"Disable relative protocol witness tables">;
13171317

1318+
def enable_async_frame_push_pop_metadata :
1319+
Flag<["-"], "enable-async-frame-push-pop-metadata">,
1320+
HelpText<"Enable async frame push pop metadata">;
1321+
def disable_async_frame_push_pop_metadata :
1322+
Flag<["-"], "disable-async-frame-push-pop-metadata">,
1323+
HelpText<"Disable async frame push pop metadata">;
1324+
13181325
def enable_split_cold_code :
13191326
Flag<["-"], "enable-split-cold-code">,
13201327
HelpText<"Enable splitting of cold code when optimizing">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3461,6 +3461,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
34613461
Args.hasFlag(OPT_enable_split_cold_code,
34623462
OPT_disable_split_cold_code,
34633463
Opts.EnableHotColdSplit);
3464+
Opts.EmitAsyncFramePushPopMetadata =
3465+
Args.hasFlag(OPT_enable_async_frame_push_pop_metadata,
3466+
OPT_disable_async_frame_push_pop_metadata,
3467+
Opts.EmitAsyncFramePushPopMetadata);
34643468
Opts.EnableLargeLoadableTypesReg2Mem =
34653469
Args.hasFlag(OPT_enable_large_loadable_types_reg2mem,
34663470
OPT_disable_large_loadable_types_reg2mem,

lib/IRGen/GenCall.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5747,6 +5747,7 @@ void irgen::emitAsyncReturn(
57475747
// Setup the coro.end.async intrinsic call.
57485748
auto &Builder = IGF.Builder;
57495749
auto mustTailCallFn = IGF.createAsyncDispatchFn(fnPtr,Args);
5750+
57505751
auto handle = IGF.getCoroutineHandle();
57515752
auto rawFnPtr =
57525753
Builder.CreateBitOrPointerCast(fnPtr.getRawPointer(), IGF.IGM.Int8PtrTy);

lib/IRGen/IRGen.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,14 @@ void swift::performLLVMOptimizations(const IRGenOptions &Opts,
270270
if (Level != OptimizationLevel::O0)
271271
FPM.addPass(SwiftARCOptPass());
272272
});
273-
PB.registerOptimizerLastEPCallback([](ModulePassManager &MPM,
273+
PB.registerOptimizerLastEPCallback([&](ModulePassManager &MPM,
274274
OptimizationLevel Level) {
275275
if (Level != OptimizationLevel::O0)
276276
MPM.addPass(createModuleToFunctionPassAdaptor(SwiftARCContractPass()));
277277
if (Level == OptimizationLevel::O0)
278278
MPM.addPass(AlwaysInlinerPass());
279+
if (Opts.EmitAsyncFramePushPopMetadata)
280+
MPM.addPass(AsyncEntryReturnMetadataPass());
279281
});
280282
}
281283

lib/IRGen/IRGenSIL.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2523,6 +2523,10 @@ void IRGenSILFunction::emitSILFunction() {
25232523
CurFn,
25242524
LinkEntity::forSILFunction(CurSILFn),
25252525
getAsyncContextLayout(*this).getSize());
2526+
2527+
if (IGM.getOptions().EmitAsyncFramePushPopMetadata) {
2528+
CurFn->addFnAttr("async_entry");
2529+
}
25262530
}
25272531
if (isAsyncFn) {
25282532
IGM.noteSwiftAsyncFunctionDef();

lib/LLVMPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_swift_host_library(swiftLLVMPasses STATIC
66
LLVMARCContract.cpp
77
LLVMInlineTree.cpp
88
LLVMMergeFunctions.cpp
9+
LLVMEmitAsyncEntryReturnMetadata.cpp
910

1011
LLVM_LINK_COMPONENTS
1112
analysis
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===--- LLVMEmitAsyncEntryReturnMetadata.cpp - Async function metadata ---===//
2+
//
3+
4+
#include "swift/LLVMPasses/Passes.h"
5+
#include "llvm/Pass.h"
6+
#include "llvm/IR/Constants.h"
7+
#include "llvm/Transforms/Utils/ModuleUtils.h"
8+
9+
using namespace llvm;
10+
using namespace swift;
11+
12+
#define DEBUG_TYPE "swift-async-return"
13+
14+
PreservedAnalyses AsyncEntryReturnMetadataPass::run(Module &M,
15+
ModuleAnalysisManager &AM) {
16+
bool changed = false;
17+
18+
SmallVector<llvm::Function *, 16> asyncEntries;
19+
SmallVector<llvm::Function *, 16> asyncReturns;
20+
for (auto &F : M) {
21+
if (F.isDeclaration())
22+
continue;
23+
24+
if (F.hasFnAttribute("async_entry"))
25+
asyncEntries.push_back(&F);
26+
if (F.hasFnAttribute("async_ret"))
27+
asyncReturns.push_back(&F);
28+
}
29+
30+
auto &ctxt = M.getContext();
31+
auto int32Ty = llvm::Type::getInt32Ty(ctxt);
32+
auto sizeTy = M.getDataLayout().getIntPtrType(ctxt, /*addrspace*/ 0);
33+
34+
auto addSection = [&] (const char * sectionName, const char *globalName,
35+
SmallVectorImpl<llvm::Function *> & entries) {
36+
if (entries.empty())
37+
return;
38+
39+
auto intArrayTy = llvm::ArrayType::get(int32Ty, entries.size());
40+
auto global =
41+
new llvm::GlobalVariable(M, intArrayTy, true,
42+
llvm::GlobalValue::InternalLinkage,
43+
nullptr, /*init*/ globalName,
44+
nullptr, /*insertBefore*/
45+
llvm::GlobalValue::NotThreadLocal,
46+
0/*address space*/);
47+
global->setAlignment(Align(4));
48+
global->setSection(sectionName);
49+
size_t index = 0;
50+
SmallVector<llvm::Constant*, 16> offsets;
51+
for (auto *fn : entries) {
52+
llvm::Constant *indices[] = { llvm::ConstantInt::get(int32Ty, 0),
53+
llvm::ConstantInt::get(int32Ty, index)};
54+
++index;
55+
56+
llvm::Constant *base = llvm::ConstantExpr::getInBoundsGetElementPtr(
57+
intArrayTy, global, indices);
58+
base = llvm::ConstantExpr::getPtrToInt(base, sizeTy);
59+
auto *target = llvm::ConstantExpr::getPtrToInt(fn, sizeTy);
60+
llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
61+
62+
if (sizeTy != int32Ty) {
63+
offset = llvm::ConstantExpr::getTrunc(offset, int32Ty);
64+
}
65+
offsets.push_back(offset);
66+
}
67+
auto constant = llvm::ConstantArray::get(intArrayTy, offsets);
68+
global->setInitializer(constant);
69+
appendToUsed(M, global);
70+
71+
llvm::GlobalVariable::SanitizerMetadata Meta;
72+
Meta.IsDynInit = false;
73+
Meta.NoAddress = true;
74+
global->setSanitizerMetadata(Meta);
75+
76+
changed = true;
77+
};
78+
79+
addSection("__TEXT,__swift_as_entry, coalesced, no_dead_strip",
80+
"__swift_async_entry_functlets",
81+
asyncEntries);
82+
addSection("__TEXT,__swift_as_ret, coalesced, no_dead_strip",
83+
"__swift_async_ret_functlets",
84+
asyncReturns);
85+
86+
if (!changed)
87+
return PreservedAnalyses::all();
88+
89+
return PreservedAnalyses::none();
90+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -module-name async -disable-availability-checking -enable-async-frame-push-pop-metadata | %FileCheck %s --check-prefix=ENABLED
2+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -module-name async -disable-availability-checking -O -enable-async-frame-push-pop-metadata | %FileCheck %s --check-prefix=ENABLED
3+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -module-name async -disable-availability-checking -disable-async-frame-push-pop-metadata | %FileCheck %s --check-prefix=DISABLED
4+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -module-name async -disable-availability-checking | %FileCheck %s --check-prefix=DISABLED
5+
6+
// REQUIRES: OS=macosx || OS=iphoneos
7+
// REQUIRES: PTRSIZE=64
8+
9+
// ENABLED: @__swift_async_entry_functlets = internal constant [2 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s5async6calleeyyYaF" to i64), i64 ptrtoint (ptr @__swift_async_entry_functlets to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s5async6callerySiSbYaF" to i64), i64 ptrtoint (ptr getelementptr inbounds ([2 x i32], ptr @__swift_async_entry_functlets, i32 0, i32 1) to i64)) to i32)], section "__TEXT,__swift_as_entry, coalesced, no_dead_strip", no_sanitize_address, align 4
10+
// ENABLED: @__swift_async_ret_functlets = internal constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s5async6callerySiSbYaFTQ1_" to i64), i64 ptrtoint (ptr @__swift_async_ret_functlets to i64)) to i32)], section "__TEXT,__swift_as_ret, coalesced, no_dead_strip", no_sanitize_address, align 4
11+
12+
// DISABLED-NOT: @__swift_async_entry_functlets
13+
// DISABLED-NOT: @__swift_async_ret_functlets
14+
// DISABLED-NOT: s5async6calleeyyYaF.0
15+
// DISABLED-NOT: s5async6callerySiSbYaF.0
16+
17+
@inline(never)
18+
public func plusOne() {
19+
print("+1")
20+
}
21+
22+
@inline(never)
23+
public func minusOne() {
24+
}
25+
26+
@inline(never)
27+
public func callee() async {
28+
print("callee")
29+
}
30+
31+
public func caller(_ b: Bool) async -> Int {
32+
plusOne()
33+
34+
if b {
35+
await callee()
36+
}
37+
38+
minusOne()
39+
return 1
40+
}

0 commit comments

Comments
 (0)