Skip to content

Commit b1476de

Browse files
committed
[embedded] Initial Swift Concurrency for embedded Swift
1 parent 3af8388 commit b1476de

File tree

24 files changed

+520
-145
lines changed

24 files changed

+520
-145
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ extension BuiltinInst : OnoneSimplifyable {
4242
.AssignCopyArrayBackToFront,
4343
.AssignTakeArray,
4444
.IsPOD:
45-
optimizeFirstArgumentToThinMetatype(context)
45+
optimizeArgumentToThinMetatype(argument: 0, context)
46+
case .CreateAsyncTask:
47+
// In embedded Swift, CreateAsyncTask needs a thin metatype
48+
if context.options.enableEmbeddedSwift {
49+
optimizeArgumentToThinMetatype(argument: 1, context)
50+
}
4651
default:
4752
if let literal = constantFold(context) {
4853
uses.replaceAll(with: literal, context)
@@ -174,16 +179,25 @@ private extension BuiltinInst {
174179
context.erase(instruction: self)
175180
}
176181

177-
func optimizeFirstArgumentToThinMetatype(_ context: SimplifyContext) {
178-
guard let metatypeInst = operands[0].value as? MetatypeInst,
179-
metatypeInst.type.representationOfMetatype(in: parentFunction) == .Thick else {
182+
func optimizeArgumentToThinMetatype(argument: Int, _ context: SimplifyContext) {
183+
let type: Type
184+
185+
if let metatypeInst = operands[argument].value as? MetatypeInst {
186+
type = metatypeInst.type
187+
} else if let initExistentialInst = operands[argument].value as? InitExistentialMetatypeInst {
188+
type = initExistentialInst.metatype.type
189+
} else {
190+
return
191+
}
192+
193+
guard type.representationOfMetatype(in: parentFunction) == .Thick else {
180194
return
181195
}
182196

183-
let instanceType = metatypeInst.type.instanceTypeOfMetatype(in: parentFunction)
197+
let instanceType = type.instanceTypeOfMetatype(in: parentFunction)
184198
let builder = Builder(before: self, context)
185-
let metatype = builder.createMetatype(of: instanceType, representation: .Thin)
186-
operands[0].set(to: metatype, context)
199+
let newMetatype = builder.createMetatype(of: instanceType, representation: .Thin)
200+
operands[argument].set(to: newMetatype, context)
187201
}
188202
}
189203

include/swift/ABI/MetadataValues.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,6 +2478,8 @@ enum class TaskOptionRecordKind : uint8_t {
24782478
AsyncLet = 2,
24792479
/// Request a child task for an 'async let'.
24802480
AsyncLetWithBuffer = 3,
2481+
/// Information about the result type of the task, used in embedded Swift.
2482+
ResultTypeInfo = 4,
24812483
/// Request a child task for swift_task_run_inline.
24822484
RunInline = UINT8_MAX,
24832485
};

include/swift/ABI/Task.h

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,61 @@ class NullaryContinuationJob : public Job {
185185
}
186186
};
187187

188+
/// Descibes type information and offers value methods for an arbitrary concrete
189+
/// type in a way that's compatible with regular Swift and embedded Swift. In
190+
/// regular Swift, just holds a Metadata pointer and dispatches to the value
191+
/// witness table. In embedded Swift, because we do not have any value witness
192+
/// tables present at runtime, the witnesses are stored and referenced directly.
193+
///
194+
/// This structure is created from swift_task_create, where in regular Swift, the
195+
/// compiler provides the Metadata pointer, and in embedded Swift, a
196+
/// TaskOptionRecord is used to provide the witnesses.
197+
struct ResultTypeInfo {
198+
#if !SWIFT_CONCURRENCY_EMBEDDED
199+
const Metadata *metadata = nullptr;
200+
size_t vw_size() {
201+
return metadata->vw_size();
202+
}
203+
size_t vw_alignment() {
204+
return metadata->vw_alignment();
205+
}
206+
void vw_initializeWithCopy(OpaqueValue *result, OpaqueValue *src) {
207+
metadata->vw_initializeWithCopy(result, src);
208+
}
209+
void vw_storeEnumTagSinglePayload(OpaqueValue *v, unsigned whichCase,
210+
unsigned emptyCases) {
211+
metadata->vw_storeEnumTagSinglePayload(v, whichCase, emptyCases);
212+
}
213+
void vw_destroy(OpaqueValue *v) {
214+
metadata->vw_destroy(v);
215+
}
216+
#else
217+
size_t size = 0;
218+
size_t alignMask = 0;
219+
void (*initializeWithCopy)(OpaqueValue *result, OpaqueValue *src) = nullptr;
220+
void (*storeEnumTagSinglePayload)(OpaqueValue *v, unsigned whichCase,
221+
unsigned emptyCases) = nullptr;
222+
void (*destroy)(OpaqueValue *) = nullptr;
223+
224+
size_t vw_size() {
225+
return size;
226+
}
227+
size_t vw_alignment() {
228+
return alignMask + 1;
229+
}
230+
void vw_initializeWithCopy(OpaqueValue *result, OpaqueValue *src) {
231+
initializeWithCopy(result, src);
232+
}
233+
void vw_storeEnumTagSinglePayload(OpaqueValue *v, unsigned whichCase,
234+
unsigned emptyCases) {
235+
storeEnumTagSinglePayload(v, whichCase, emptyCases);
236+
}
237+
void vw_destroy(OpaqueValue *v) {
238+
destroy(v);
239+
}
240+
#endif
241+
};
242+
188243
/// An asynchronous task. Tasks are the analogue of threads for
189244
/// asynchronous functions: that is, they are a persistent identity
190245
/// for the overall async computation.
@@ -503,7 +558,7 @@ class AsyncTask : public Job {
503558
std::atomic<WaitQueueItem> waitQueue;
504559

505560
/// The type of the result that will be produced by the future.
506-
const Metadata *resultType;
561+
ResultTypeInfo resultType;
507562

508563
SwiftError *error = nullptr;
509564

@@ -513,14 +568,14 @@ class AsyncTask : public Job {
513568
friend class AsyncTask;
514569

515570
public:
516-
explicit FutureFragment(const Metadata *resultType)
571+
explicit FutureFragment(ResultTypeInfo resultType)
517572
: waitQueue(WaitQueueItem::get(Status::Executing, nullptr)),
518573
resultType(resultType) { }
519574

520575
/// Destroy the storage associated with the future.
521576
void destroy();
522577

523-
const Metadata *getResultType() const {
578+
ResultTypeInfo getResultType() const {
524579
return resultType;
525580
}
526581

@@ -534,7 +589,7 @@ class AsyncTask : public Job {
534589
// `this` must have the same value modulo that alignment as
535590
// `fragmentOffset` has in that function.
536591
char *fragmentAddr = reinterpret_cast<char *>(this);
537-
uintptr_t alignment = resultType->vw_alignment();
592+
uintptr_t alignment = resultType.vw_alignment();
538593
char *resultAddr = fragmentAddr + sizeof(FutureFragment);
539594
uintptr_t unalignedResultAddrInt =
540595
reinterpret_cast<uintptr_t>(resultAddr);
@@ -553,12 +608,12 @@ class AsyncTask : public Job {
553608
/// Determine the size of the future fragment given the result type
554609
/// of the future.
555610
static size_t fragmentSize(size_t fragmentOffset,
556-
const Metadata *resultType) {
611+
ResultTypeInfo resultType) {
557612
assert((fragmentOffset & (alignof(FutureFragment) - 1)) == 0);
558-
size_t alignment = resultType->vw_alignment();
613+
size_t alignment = resultType.vw_alignment();
559614
size_t resultOffset = fragmentOffset + sizeof(FutureFragment);
560615
resultOffset = (resultOffset + alignment - 1) & ~(alignment - 1);
561-
size_t endOffset = resultOffset + resultType->vw_size();
616+
size_t endOffset = resultOffset + resultType.vw_size();
562617
return (endOffset - fragmentOffset);
563618
}
564619
};

include/swift/ABI/TaskOptions.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ class AsyncLetWithBufferTaskOptionRecord : public TaskOptionRecord {
141141
}
142142
};
143143

144+
class ResultTypeInfoTaskOptionRecord : public TaskOptionRecord {
145+
public:
146+
size_t size;
147+
size_t alignMask;
148+
void (*initializeWithCopy)(OpaqueValue *, OpaqueValue *);
149+
void (*storeEnumTagSinglePayload)(OpaqueValue *, unsigned, unsigned);
150+
void (*destroy)(OpaqueValue *);
151+
152+
static bool classof(const TaskOptionRecord *record) {
153+
return record->getKind() == TaskOptionRecordKind::ResultTypeInfo;
154+
}
155+
};
156+
144157
class RunInlineTaskOptionRecord : public TaskOptionRecord {
145158
void *allocation;
146159
size_t allocationBytes;

include/swift/IRGen/Linking.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,8 @@ class LinkEntity {
10121012
}
10131013

10141014
static LinkEntity forValueWitness(CanType concreteType, ValueWitness witness) {
1015-
assert(!isEmbedded(concreteType));
1015+
// Explicitly allowed in embedded Swift because we generate value witnesses
1016+
// (but not witness tables) for Swift Concurrency usage.
10161017
LinkEntity entity;
10171018
entity.Pointer = concreteType.getPointer();
10181019
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ValueWitness))

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3120,6 +3120,8 @@ bool CompilerInvocation::parseArgs(
31203120
IRGenOpts.DisableLegacyTypeInfo = true;
31213121
IRGenOpts.ReflectionMetadata = ReflectionMetadataMode::None;
31223122
IRGenOpts.EnableReflectionNames = false;
3123+
TypeCheckerOpts.SkipFunctionBodies = FunctionBodySkipping::None;
3124+
SILOpts.SkipFunctionBodies = FunctionBodySkipping::None;
31233125
SILOpts.CMOMode = CrossModuleOptimizationMode::Everything;
31243126
SILOpts.EmbeddedSwift = true;
31253127
}

lib/IRGen/GenBuiltin.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,15 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
326326
(Builtin.ID == BuiltinValueKind::CreateAsyncTaskInGroup)
327327
? args.claimNext()
328328
: nullptr;
329-
auto futureResultType = args.claimNext();
329+
330+
// In embedded Swift, futureResultType is a thin metatype, not backed by any
331+
// actual value.
332+
llvm::Value *futureResultType =
333+
llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy);
334+
if (!IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
335+
futureResultType = args.claimNext();
336+
}
337+
330338
auto taskFunction = args.claimNext();
331339
auto taskContext = args.claimNext();
332340

lib/IRGen/GenCall.cpp

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4418,18 +4418,17 @@ void irgen::emitTaskCancel(IRGenFunction &IGF, llvm::Value *task) {
44184418
call->setCallingConv(IGF.IGM.SwiftCC);
44194419
}
44204420

4421-
llvm::Value *irgen::emitTaskCreate(
4422-
IRGenFunction &IGF,
4423-
llvm::Value *flags,
4424-
llvm::Value *taskGroup,
4425-
llvm::Value *futureResultType,
4426-
llvm::Value *taskFunction,
4427-
llvm::Value *localContextInfo,
4428-
SubstitutionMap subs) {
4429-
// If there is a task group, emit a task group option structure to contain
4430-
// it.
4431-
llvm::Value *taskOptions = llvm::ConstantInt::get(
4432-
IGF.IGM.SwiftTaskOptionRecordPtrTy, 0);
4421+
llvm::Value *irgen::emitTaskCreate(IRGenFunction &IGF, llvm::Value *flags,
4422+
llvm::Value *taskGroup,
4423+
llvm::Value *futureResultType,
4424+
llvm::Value *taskFunction,
4425+
llvm::Value *localContextInfo,
4426+
SubstitutionMap subs) {
4427+
// Start with empty task options.
4428+
llvm::Value *taskOptions =
4429+
llvm::ConstantInt::get(IGF.IGM.SwiftTaskOptionRecordPtrTy, 0);
4430+
4431+
// If there is a task group, emit a task group option structure to contain it.
44334432
if (taskGroup) {
44344433
TaskOptionRecordFlags optionsFlags(TaskOptionRecordKind::TaskGroup);
44354434
llvm::Value *optionsFlagsVal = llvm::ConstantInt::get(
@@ -4440,14 +4439,73 @@ llvm::Value *irgen::emitTaskCreate(
44404439
"task_group_options");
44414440
auto optionsBaseRecord = IGF.Builder.CreateStructGEP(
44424441
optionsRecord, 0, Size());
4442+
4443+
// Flags
44434444
IGF.Builder.CreateStore(
44444445
optionsFlagsVal,
44454446
IGF.Builder.CreateStructGEP(optionsBaseRecord, 0, Size()));
4447+
// Parent
44464448
IGF.Builder.CreateStore(
44474449
taskOptions, IGF.Builder.CreateStructGEP(optionsBaseRecord, 1, Size()));
4448-
4450+
// TaskGroup
44494451
IGF.Builder.CreateStore(
44504452
taskGroup, IGF.Builder.CreateStructGEP(optionsRecord, 1, Size()));
4453+
4454+
taskOptions = IGF.Builder.CreateBitOrPointerCast(
4455+
optionsRecord.getAddress(), IGF.IGM.SwiftTaskOptionRecordPtrTy);
4456+
}
4457+
4458+
// In embedded Swift, create and pass result type info.
4459+
if (IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
4460+
auto optionsRecord =
4461+
IGF.createAlloca(IGF.IGM.SwiftResultTypeInfoTaskOptionRecordTy,
4462+
Alignment(), "result_type_info");
4463+
auto optionsBaseRecord =
4464+
IGF.Builder.CreateStructGEP(optionsRecord, 0, Size());
4465+
4466+
TaskOptionRecordFlags optionsFlags(TaskOptionRecordKind::ResultTypeInfo);
4467+
llvm::Value *optionsFlagsVal = llvm::ConstantInt::get(
4468+
IGF.IGM.SizeTy, optionsFlags.getOpaqueValue());
4469+
4470+
// Flags
4471+
IGF.Builder.CreateStore(
4472+
optionsFlagsVal,
4473+
IGF.Builder.CreateStructGEP(optionsBaseRecord, 0, Size()));
4474+
// Parent
4475+
IGF.Builder.CreateStore(
4476+
taskOptions, IGF.Builder.CreateStructGEP(optionsBaseRecord, 1, Size()));
4477+
4478+
Type unloweredType = subs.getReplacementTypes()[0];
4479+
SILType lowered = IGF.IGM.getLoweredType(unloweredType);
4480+
const TypeInfo &TI = IGF.IGM.getTypeInfo(lowered);
4481+
CanType canType = lowered.getASTType();
4482+
FixedPacking packing = TI.getFixedPacking(IGF.IGM);
4483+
4484+
// Size
4485+
IGF.Builder.CreateStore(
4486+
TI.getStaticSize(IGF.IGM),
4487+
IGF.Builder.CreateStructGEP(optionsRecord, 1, Size()));
4488+
// Align mask
4489+
IGF.Builder.CreateStore(
4490+
TI.getStaticAlignmentMask(IGF.IGM),
4491+
IGF.Builder.CreateStructGEP(optionsRecord, 2, Size()));
4492+
// initializeWithCopy witness
4493+
IGF.Builder.CreateStore(
4494+
IGF.IGM.getOrCreateValueWitnessFunction(
4495+
ValueWitness::InitializeWithCopy, packing, canType, lowered, TI),
4496+
IGF.Builder.CreateStructGEP(optionsRecord, 3, Size()));
4497+
// storeEnumTagSinglePayload witness
4498+
IGF.Builder.CreateStore(
4499+
IGF.IGM.getOrCreateValueWitnessFunction(
4500+
ValueWitness::StoreEnumTagSinglePayload, packing, canType, lowered,
4501+
TI),
4502+
IGF.Builder.CreateStructGEP(optionsRecord, 4, Size()));
4503+
// destroy witness
4504+
IGF.Builder.CreateStore(
4505+
IGF.IGM.getOrCreateValueWitnessFunction(ValueWitness::Destroy, packing,
4506+
canType, lowered, TI),
4507+
IGF.Builder.CreateStructGEP(optionsRecord, 5, Size()));
4508+
44514509
taskOptions = IGF.Builder.CreateBitOrPointerCast(
44524510
optionsRecord.getAddress(), IGF.IGM.SwiftTaskOptionRecordPtrTy);
44534511
}

lib/IRGen/GenValueWitness.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ static Address getArgAsBuffer(IRGenFunction &IGF,
389389
/// Don't add new callers of this, it doesn't make any sense.
390390
static CanType getFormalTypeInPrimaryContext(CanType abstractType) {
391391
auto *nominal = abstractType.getAnyNominal();
392-
if (abstractType->isEqual(nominal->getDeclaredType())) {
392+
if (nominal && abstractType->isEqual(nominal->getDeclaredType())) {
393393
return nominal->mapTypeIntoContext(nominal->getDeclaredInterfaceType())
394394
->getCanonicalType();
395395
}
@@ -1260,12 +1260,20 @@ addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B, ValueWitness index,
12601260
llvm_unreachable("bad value witness kind");
12611261

12621262
standard:
1263+
llvm::Function *fn = IGM.getOrCreateValueWitnessFunction(
1264+
index, packing, abstractType, concreteType, concreteTI);
1265+
addFunction(fn);
1266+
}
1267+
1268+
llvm::Function *IRGenModule::getOrCreateValueWitnessFunction(
1269+
ValueWitness index, FixedPacking packing, CanType abstractType,
1270+
SILType concreteType, const TypeInfo &type) {
12631271
llvm::Function *fn =
1264-
IGM.getAddrOfValueWitness(abstractType, index, ForDefinition);
1272+
getAddrOfValueWitness(abstractType, index, ForDefinition);
12651273
if (fn->empty())
1266-
buildValueWitnessFunction(IGM, fn, index, packing, abstractType,
1267-
concreteType, concreteTI);
1268-
addFunction(fn);
1274+
buildValueWitnessFunction(*this, fn, index, packing, abstractType,
1275+
concreteType, type);
1276+
return fn;
12691277
}
12701278

12711279
static bool shouldAddEnumWitnesses(CanType abstractType) {

lib/IRGen/IRGenModule.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,15 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
671671
SwiftTaskOptionRecordTy, // Base option record
672672
SwiftTaskGroupPtrTy, // Task group
673673
});
674+
SwiftResultTypeInfoTaskOptionRecordTy = createStructType(
675+
*this, "swift.result_type_info_task_option", {
676+
SwiftTaskOptionRecordTy, // Base option record
677+
SizeTy,
678+
SizeTy,
679+
Int8PtrTy,
680+
Int8PtrTy,
681+
Int8PtrTy,
682+
});
674683
ExecutorFirstTy = SizeTy;
675684
ExecutorSecondTy = SizeTy;
676685
SwiftExecutorTy = createStructType(*this, "swift.executor", {

lib/IRGen/IRGenModule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ class IRGenModule {
775775
llvm::PointerType *SwiftTaskGroupPtrTy;
776776
llvm::StructType *SwiftTaskOptionRecordTy;
777777
llvm::StructType *SwiftTaskGroupTaskOptionRecordTy;
778+
llvm::StructType *SwiftResultTypeInfoTaskOptionRecordTy;
778779
llvm::PointerType *SwiftJobPtrTy;
779780
llvm::IntegerType *ExecutorFirstTy;
780781
llvm::IntegerType *ExecutorSecondTy;
@@ -1565,6 +1566,11 @@ private: \
15651566
Address getAddrOfEnumCase(EnumElementDecl *Case,
15661567
ForDefinition_t forDefinition);
15671568
Address getAddrOfFieldOffset(VarDecl *D, ForDefinition_t forDefinition);
1569+
llvm::Function *getOrCreateValueWitnessFunction(ValueWitness index,
1570+
FixedPacking packing,
1571+
CanType abstractType,
1572+
SILType concreteType,
1573+
const TypeInfo &type);
15681574
llvm::Function *getAddrOfValueWitness(CanType concreteType,
15691575
ValueWitness index,
15701576
ForDefinition_t forDefinition);

0 commit comments

Comments
 (0)