Skip to content

Commit 3656afe

Browse files
authored
Merge pull request swiftlang#32600 from eeckstein/support-cow-builtins
[5.3] parse COW support builtins as no-ops
2 parents 3b9218a + e1a14cf commit 3656afe

File tree

6 files changed

+152
-4
lines changed

6 files changed

+152
-4
lines changed

include/swift/AST/Builtins.def

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,35 @@ BUILTIN_SIL_OPERATION(IsUnique, "isUnique", Special)
429429
/// BridgeObject to be treated as a native object by the runtime.
430430
BUILTIN_SIL_OPERATION(IsUnique_native, "isUnique_native", Special)
431431

432+
/// beginCOWMutation<T : AnyObject>(inout T) -> Int1
433+
///
434+
/// Begins a copy-on-write mutation for a buffer reference which is passed as
435+
/// inout argument. It returns a true if the buffer is uniquely referenced.
436+
/// In this case the buffer may be mutated after calling this builtin.
437+
///
438+
/// The beginCOWMutation builtin is very similar to isUnique. It just translates
439+
/// to a different SIL instruction (begin_cow_mutation), which is the preferred
440+
/// representation of COW in SIL.
441+
BUILTIN_SIL_OPERATION(BeginCOWMutation, "beginCOWMutation", Special)
442+
443+
/// beginCOWMutation_native<T : AnyObject>(inout T) -> Int1
444+
///
445+
/// Like beginCOWMutation, but it's assumed that T has native Swift reference
446+
/// counting.
447+
BUILTIN_SIL_OPERATION(BeginCOWMutation_native, "beginCOWMutation_native", Special)
448+
449+
/// endCOWMutation<T : AnyObject>(inout T)
450+
///
451+
/// Ends a copy-on-write mutation for a buffer reference which is passed as
452+
/// inout argument. After calling this builtin, the buffer must not be mutated.
453+
BUILTIN_SIL_OPERATION(EndCOWMutation, "endCOWMutation", Special)
454+
455+
/// COWBufferForReading has type <T: AnyObject> T -> T
456+
///
457+
/// Returns the buffer reference which is passed as argument.
458+
/// This builtin indicates to the optimizer that the buffer is not mutable.
459+
BUILTIN_SIL_OPERATION(COWBufferForReading, "COWBufferForReading", Special)
460+
432461
/// bindMemory : <T> (Builtin.RawPointer, Builtin.Word, T.Type) -> ()
433462
BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special)
434463

lib/AST/Builtins.cpp

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,26 @@ createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
431431

432432
/// Create a generic parameter list with multiple generic parameters.
433433
static GenericParamList *getGenericParams(ASTContext &ctx,
434-
unsigned numParameters) {
434+
unsigned numParameters,
435+
bool isAnyObject) {
435436
assert(numParameters <= llvm::array_lengthof(GenericParamNames));
436437

437438
SmallVector<GenericTypeParamDecl*, 2> genericParams;
438439
for (unsigned i = 0; i != numParameters; ++i)
439440
genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i));
440441

442+
443+
if (isAnyObject) {
444+
CanType ao = ctx.getAnyObjectType();
445+
SmallVector<RequirementRepr, 1> req;
446+
req.push_back(RequirementRepr::getTypeConstraint(TypeLoc::withoutLoc(genericParams[0]->getInterfaceType()), SourceLoc(),
447+
TypeLoc::withoutLoc(ao)));
448+
449+
auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams,
450+
SourceLoc(), req, SourceLoc());
451+
return paramList;
452+
}
453+
441454
auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams,
442455
SourceLoc());
443456
return paramList;
@@ -460,9 +473,10 @@ namespace {
460473
SmallVector<Requirement, 2> addedRequirements;
461474

462475
public:
463-
BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1)
476+
BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1,
477+
bool isAnyObject = false)
464478
: Context(ctx) {
465-
TheGenericParamList = getGenericParams(ctx, numGenericParams);
479+
TheGenericParamList = getGenericParams(ctx, numGenericParams, isAnyObject);
466480
for (auto gp : TheGenericParamList->getParams()) {
467481
genericParamTypes.push_back(
468482
gp->getDeclaredInterfaceType()->castTo<GenericTypeParamType>());
@@ -645,6 +659,14 @@ static ValueDecl *getIsUniqueOperation(ASTContext &Context, Identifier Id) {
645659
return builder.build(Id);
646660
}
647661

662+
static ValueDecl *getEndCOWMutation(ASTContext &Context, Identifier Id) {
663+
// <T> (@inout T) -> ()
664+
BuiltinFunctionBuilder builder(Context);
665+
builder.addParameter(makeGenericParam(), ValueOwnership::InOut);
666+
builder.setResult(makeConcrete(TupleType::getEmpty(Context)));
667+
return builder.build(Id);
668+
}
669+
648670
static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) {
649671
BuiltinFunctionBuilder builder(Context);
650672
builder.addParameter(makeConcrete(Context.TheRawPointerType));
@@ -908,6 +930,16 @@ static ValueDecl *getValueToBridgeObject(ASTContext &C, Identifier Id) {
908930
return builder.build(Id);
909931
}
910932

933+
static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) {
934+
// <T : AnyObject> T -> T
935+
//
936+
BuiltinFunctionBuilder builder(C, 1, true);
937+
auto T = makeGenericParam();
938+
builder.addParameter(T);
939+
builder.setResult(T);
940+
return builder.build(Id);
941+
}
942+
911943
static ValueDecl *getUnsafeGuaranteed(ASTContext &C, Identifier Id) {
912944
// <T : AnyObject> T -> (T, Int8Ty)
913945
//
@@ -2249,9 +2281,16 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
22492281

22502282
case BuiltinValueKind::IsUnique:
22512283
case BuiltinValueKind::IsUnique_native:
2284+
case BuiltinValueKind::BeginCOWMutation:
2285+
case BuiltinValueKind::BeginCOWMutation_native:
22522286
if (!Types.empty()) return nullptr;
2287+
// BeginCOWMutation has the same signature as IsUnique.
22532288
return getIsUniqueOperation(Context, Id);
22542289

2290+
case BuiltinValueKind::EndCOWMutation:
2291+
if (!Types.empty()) return nullptr;
2292+
return getEndCOWMutation(Context, Id);
2293+
22552294
case BuiltinValueKind::BindMemory:
22562295
if (!Types.empty()) return nullptr;
22572296
return getBindMemoryOperation(Context, Id);
@@ -2380,6 +2419,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
23802419
if (!Types.empty())
23812420
return nullptr;
23822421
return getValueToBridgeObject(Context, Id);
2422+
2423+
case BuiltinValueKind::COWBufferForReading:
2424+
return getCOWBufferForReading(Context, Id);
2425+
23832426
case BuiltinValueKind::UnsafeGuaranteed:
23842427
return getUnsafeGuaranteed(Context, Id);
23852428

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,45 @@ emitBuiltinIsUnique_native(SILGenFunction &SGF,
901901
return ManagedValue::forUnmanaged(result);
902902
}
903903

904+
static ManagedValue
905+
emitBuiltinBeginCOWMutation(SILGenFunction &SGF,
906+
SILLocation loc,
907+
SubstitutionMap subs,
908+
ArrayRef<ManagedValue> args,
909+
SGFContext C) {
910+
return emitBuiltinIsUnique(SGF, loc, subs, args, C);
911+
}
912+
913+
static ManagedValue
914+
emitBuiltinBeginCOWMutation_native(SILGenFunction &SGF,
915+
SILLocation loc,
916+
SubstitutionMap subs,
917+
ArrayRef<ManagedValue> args,
918+
SGFContext C) {
919+
return emitBuiltinIsUnique_native(SGF, loc, subs, args, C);
920+
}
921+
922+
static ManagedValue
923+
emitBuiltinEndCOWMutation(SILGenFunction &SGF,
924+
SILLocation loc,
925+
SubstitutionMap subs,
926+
ArrayRef<ManagedValue> args,
927+
SGFContext C) {
928+
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
929+
}
930+
931+
static ManagedValue
932+
emitBuiltinCOWBufferForReading(SILGenFunction &SGF,
933+
SILLocation loc,
934+
SubstitutionMap subs,
935+
ArrayRef<ManagedValue> args,
936+
SGFContext C) {
937+
938+
939+
assert(args.size() == 1 && "isUnique_native should have one arg.");
940+
return args[0];
941+
}
942+
904943
static ManagedValue emitBuiltinBindMemory(SILGenFunction &SGF,
905944
SILLocation loc,
906945
SubstitutionMap subs,

lib/SILOptimizer/Analysis/ArraySemantic.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,13 @@ void ArraySemanticsCall::initialize(ApplyInst *AI, StringRef semanticName,
183183

184184
// Need a 'self' argument otherwise this is not a semantic call that
185185
// we recognize.
186-
if (getKind() < ArrayCallKind::kArrayInit && !hasSelf())
186+
ArrayCallKind kind = getKind();
187+
if (kind == ArrayCallKind::kNone) {
188+
SemanticsCall = nullptr;
189+
return;
190+
}
191+
192+
if (kind < ArrayCallKind::kArrayInit && !hasSelf())
187193
SemanticsCall = nullptr;
188194

189195
// A arguments must be passed reference count neutral except for self.

test/IRGen/builtins.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,12 @@ func isUniqueIUO(_ ref: inout Builtin.NativeObject?) -> Bool {
683683
return Builtin.isUnique(&iuo)
684684
}
685685

686+
// CHECK-LABEL: define hidden {{.*}} @"$s8builtins19COWBufferForReadingyAA1CCADnF"
687+
// CHECK: ret %T8builtins1CC* %0
688+
func COWBufferForReading(_ ref: __owned C) -> C {
689+
return Builtin.COWBufferForReading(ref)
690+
}
691+
686692
// CHECK-LABEL: define {{.*}} @{{.*}}generic_ispod_test
687693
func generic_ispod_test<T>(_: T) {
688694
// CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10

test/SILGen/builtins.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,31 @@ func castBitPatternFromBridgeObject(_ bo: Builtin.BridgeObject) -> Builtin.Word
600600
return Builtin.castBitPatternFromBridgeObject(bo)
601601
}
602602

603+
// CHECK-LABEL: sil hidden [ossa] @$s8builtins16beginCOWMutationySbAA1CCzF
604+
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*C
605+
// CHECK: [[BUILTIN:%.*]] = is_unique [[WRITE]] : $*C
606+
// CHECK: return
607+
func beginCOWMutation(_ c: inout C) -> Bool {
608+
return Bool(_builtinBooleanLiteral: Builtin.beginCOWMutation(&c))
609+
}
610+
611+
// CHECK-LABEL: sil hidden [ossa] @$s8builtins23beginCOWMutation_nativeySbAA1CCzF
612+
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*C
613+
// CHECK: [[CAST:%.*]] = unchecked_addr_cast [[WRITE]] : $*C to $*Builtin.NativeObject
614+
// CHECK: [[BUILTIN:%.*]] = is_unique [[CAST]] : $*Builtin.NativeObject
615+
// CHECK: return
616+
func beginCOWMutation_native(_ c: inout C) -> Bool {
617+
return Bool(_builtinBooleanLiteral: Builtin.beginCOWMutation_native(&c))
618+
}
619+
620+
// CHECK-LABEL: sil hidden [ossa] @$s8builtins14endCOWMutationyyAA1CCzF
621+
// CHECK: begin_access
622+
// CHECK-NEXT: tuple ()
623+
// CHECK-NEXT: end_access
624+
func endCOWMutation(_ c: inout C) {
625+
Builtin.endCOWMutation(&c)
626+
}
627+
603628
// ----------------------------------------------------------------------------
604629
// isUnique variants
605630
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)