Merge pull request #84248 from rjmccall/complete-metadata-for-concurrency-builtins-6.2.1

[6.2.1] Fix IRGen to pass complete metadata to various concurrency builtins
This commit is contained in:
John McCall
2025-09-12 10:23:55 -04:00
committed by GitHub
4 changed files with 88 additions and 4 deletions

View File

@@ -249,7 +249,7 @@ llvm::Value *irgen::emitBuiltinStartAsyncLet(IRGenFunction &IGF,
llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy);
if (!IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
futureResultTypeMetadata =
IGF.emitAbstractTypeMetadataRef(futureResultType);
IGF.emitTypeMetadataRef(futureResultType);
}
// The concurrency runtime for older Apple OSes has a bug in task formation
@@ -352,7 +352,7 @@ llvm::Value *irgen::emitCreateTaskGroup(IRGenFunction &IGF,
return group;
}
auto resultTypeMetadata = IGF.emitAbstractTypeMetadataRef(resultType);
auto resultTypeMetadata = IGF.emitTypeMetadataRef(resultType);
llvm::CallInst *call;
if (groupFlags) {
@@ -416,7 +416,7 @@ void irgen::emitTaskRunInline(IRGenFunction &IGF, SubstitutionMap subs,
assert(subs.getReplacementTypes().size() == 1 &&
"taskRunInline should have a type substitution");
auto resultType = subs.getReplacementTypes()[0]->getCanonicalType();
auto resultTypeMetadata = IGF.emitAbstractTypeMetadataRef(resultType);
auto resultTypeMetadata = IGF.emitTypeMetadataRef(resultType);
auto *call = IGF.Builder.CreateCall(
IGF.IGM.getTaskRunInlineFunctionPointer(),

View File

@@ -6771,7 +6771,8 @@ namespace {
return;
}
// Emit a reference to the superclass.
// Emit a reference to the superclass. This should be abstract for now,
// but transitively completing the class will complete it.
auto superclass = IGF.emitAbstractTypeMetadataRef(
getSuperclassForMetadata(IGM, Target));

View File

@@ -1281,6 +1281,9 @@ static llvm::Value *emitWitnessTableAccessorCall(
// Emit the source metadata if we haven't yet.
if (!*srcMetadataCache) {
// Witness table accesses only require abstract type metadata; this
// is so that we can create the witness tables without introducing
// cycle problems.
*srcMetadataCache = IGF.emitAbstractTypeMetadataRef(conformingType);
}
@@ -3460,6 +3463,7 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
return MetadataResponse::forComplete(associatedWTable);
}
// Witness table lookups only require abstract metadata.
auto *sourceMetadata =
IGF.emitAbstractTypeMetadataRef(sourceType);
@@ -3526,6 +3530,7 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
associatedMetadata = response.getMetadata();
} else {
// Ok, fall back to realizing the (possibly concrete) type.
// Witness table lookups only require abstract metadata.
associatedMetadata =
IGF.emitAbstractTypeMetadataRef(sourceKey.Type);
}

View File

@@ -10,6 +10,10 @@ import Builtin
import Swift
import _Concurrency
struct Pair<T> {
var value: (T, T)
}
// CHECK-LABEL: define hidden swift{{(tail)?}}cc void @get_task(ptr swiftasync %0)
sil hidden [ossa] @get_task : $@async @convention(thin) () -> @owned Builtin.NativeObject {
bb0:
@@ -241,6 +245,33 @@ bb0(%0 : @owned $Error, %1 : $Builtin.RawUnsafeContinuation):
return %21 : $()
}
// CHECK-LABEL: define {{.*}} void @async_let_generic(
sil public @async_let_generic : $@convention(thin) @async <T> () -> @out Pair<T> {
bb0(%out : $*Pair<T>):
%1 = function_ref @async_let_generic_helper : $@convention(thin) @Sendable @async <τ_0_0> () -> (@out Pair<τ_0_0>, @error any Error)
%2 = thin_to_thick_function %1 to $@Sendable @async <τ_0_0> () -> (@out Pair<τ_0_0>, @error any Error)
%fn = convert_function %2 to $@async @callee_guaranteed @substituted <τ_0_0> () -> (@out τ_0_0, @error any Error) for <Pair<T>>
%outPtr = address_to_pointer %out to $Builtin.RawPointer
%scratch = enum $Optional<Builtin.RawPointer>, #Optional.none!enumelt
// We've set up a function that has no reason to request type metadata
// for Pair<T> except to pass it to swift_asyncLet_begin. Make sure that we
// request complete metadata.
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s8builtins4PairVMa"([[INT]] 0, ptr %T)
// CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK-NEXT: call swiftcc void @swift_asyncLet_begin({{.*}}, ptr [[METADATA]], {{.*}})
%asyncLet = builtin "startAsyncLetWithLocalBuffer"<Pair<T>>(%scratch, %fn, %outPtr) : $Builtin.RawPointer
%t1 = builtin "endAsyncLetLifetime"(%asyncLet, %fn) : $()
%result = tuple ()
return %result
}
sil private @async_let_generic_helper : $@convention(thin) @Sendable @async <T> () -> (@out Pair<T>, @error any Error) {
bb0(%out : $*Pair<T>):
unreachable
}
// CHECK-LABEL: define hidden swift{{(tail)?}}cc void @task_group_create_destroy
sil hidden [ossa] @task_group_create_destroy : $@async () -> () {
bb0:
@@ -258,6 +289,31 @@ bb0:
return %21 : $()
}
// CHECK-LABEL: define hidden swift{{(tail)?}}cc void @task_group_create_destroy_generic
sil hidden [ossa] @task_group_create_destroy_generic : $@async <T> () -> () {
bb0:
// CHECK: [[TASKGROUP:%.*]] = alloca [32 x ptr], align 16
// CHECK: call void @llvm.lifetime.start.p0(i64 -1, ptr [[TASKGROUP]])
// We've set up a function that has no reason to request type metadata
// for Pair<T> except to pass it to swift_taskGroup_initialize. Make sure
// that we request complete metadata.
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s8builtins4PairVMa"([[INT]] 0, ptr %T)
// CHECK-NEXT: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK-NEXT: call swiftcc void @swift_taskGroup_initialize(ptr [[TASKGROUP]], ptr [[METADATA]])
%0 = metatype $@thin Pair<T>.Type
%1 = builtin "createTaskGroup"<Pair<T>>(%0: $@thin Pair<T>.Type) : $Builtin.RawPointer
// CHECK-NEXT: call swiftcc void @swift_taskGroup_destroy(ptr [[TASKGROUP]])
// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[TASKGROUP]])
builtin "destroyTaskGroup"(%1 : $Builtin.RawPointer) : $()
%21 = tuple ()
return %21 : $()
}
// CHECK-LABEL: define{{.*}} swiftcc void @testRunInline(
// CHECK-SAME: ptr noalias sret(%swift.opaque) [[RESULT:%[^,]+]],
@@ -276,3 +332,25 @@ entry(%result : $*T, %closure : $@noescape @async @callee_guaranteed @substitute
%void = builtin "taskRunInline"<T>(%result : $*T, %closure : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <T>) : $()
return %void : $()
}
// CHECK-LABEL: define{{.*}} swiftcc void @testRunInlineGeneric(
// CHECK-SAME: ptr noalias sret(%swift.opaque) [[RESULT:%[^,]+]],
// CHECK-SAME: ptr [[CLOSURE:%[^,]+]],
// CHECK-SAME: ptr [[CLOSURE_CONTEXT:%[^,]+]],
// CHECK-SAME: ptr %T
// CHECK-SAME: {
// Make sure we request complete metadata.
// CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s8builtins4PairVMa"([[INT]] 0, ptr %T)
// CHECK-NEXT: [[FUTURE_RESULT_TYPE:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK: call swiftcc void @swift_task_run_inline(
// CHECK-SAME: ptr [[RESULT]],
// CHECK-SAME: ptr [[CLOSURE]],
// CHECK-SAME: ptr [[CLOSURE_CONTEXT]],
// CHECK-SAME: ptr [[FUTURE_RESULT_TYPE]])
// CHECK: }
sil hidden @testRunInlineGeneric : $@convention(thin) <T> (@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Pair<T>>) -> @out T {
entry(%result : $*T, %closure : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Pair<T>>):
%void = builtin "taskRunInline"<Pair<T>>(%result : $*T, %closure : $@noescape @async @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Pair<T>>) : $()
return %void : $()
}