diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index 1510688d37e3d..988010672c3d5 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -429,6 +429,35 @@ BUILTIN_SIL_OPERATION(IsUnique, "isUnique", Special) /// BridgeObject to be treated as a native object by the runtime. BUILTIN_SIL_OPERATION(IsUnique_native, "isUnique_native", Special) +/// beginCOWMutation(inout T) -> Int1 +/// +/// Begins a copy-on-write mutation for a buffer reference which is passed as +/// inout argument. It returns a true if the buffer is uniquely referenced. +/// In this case the buffer may be mutated after calling this builtin. +/// +/// The beginCOWMutation builtin is very similar to isUnique. It just translates +/// to a different SIL instruction (begin_cow_mutation), which is the preferred +/// representation of COW in SIL. +BUILTIN_SIL_OPERATION(BeginCOWMutation, "beginCOWMutation", Special) + +/// beginCOWMutation_native(inout T) -> Int1 +/// +/// Like beginCOWMutation, but it's assumed that T has native Swift reference +/// counting. +BUILTIN_SIL_OPERATION(BeginCOWMutation_native, "beginCOWMutation_native", Special) + +/// endCOWMutation(inout T) +/// +/// Ends a copy-on-write mutation for a buffer reference which is passed as +/// inout argument. After calling this builtin, the buffer must not be mutated. +BUILTIN_SIL_OPERATION(EndCOWMutation, "endCOWMutation", Special) + +/// COWBufferForReading has type T -> T +/// +/// Returns the buffer reference which is passed as argument. +/// This builtin indicates to the optimizer that the buffer is not mutable. +BUILTIN_SIL_OPERATION(COWBufferForReading, "COWBufferForReading", Special) + /// bindMemory : (Builtin.RawPointer, Builtin.Word, T.Type) -> () BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special) diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 29a85b226ca3d..c5580e34748b4 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -431,13 +431,26 @@ createGenericParam(ASTContext &ctx, const char *name, unsigned index) { /// Create a generic parameter list with multiple generic parameters. static GenericParamList *getGenericParams(ASTContext &ctx, - unsigned numParameters) { + unsigned numParameters, + bool isAnyObject) { assert(numParameters <= llvm::array_lengthof(GenericParamNames)); SmallVector genericParams; for (unsigned i = 0; i != numParameters; ++i) genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i)); + + if (isAnyObject) { + CanType ao = ctx.getAnyObjectType(); + SmallVector req; + req.push_back(RequirementRepr::getTypeConstraint(TypeLoc::withoutLoc(genericParams[0]->getInterfaceType()), SourceLoc(), + TypeLoc::withoutLoc(ao))); + + auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams, + SourceLoc(), req, SourceLoc()); + return paramList; + } + auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams, SourceLoc()); return paramList; @@ -460,9 +473,10 @@ namespace { SmallVector addedRequirements; public: - BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1) + BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1, + bool isAnyObject = false) : Context(ctx) { - TheGenericParamList = getGenericParams(ctx, numGenericParams); + TheGenericParamList = getGenericParams(ctx, numGenericParams, isAnyObject); for (auto gp : TheGenericParamList->getParams()) { genericParamTypes.push_back( gp->getDeclaredInterfaceType()->castTo()); @@ -645,6 +659,14 @@ static ValueDecl *getIsUniqueOperation(ASTContext &Context, Identifier Id) { return builder.build(Id); } +static ValueDecl *getEndCOWMutation(ASTContext &Context, Identifier Id) { + // (@inout T) -> () + BuiltinFunctionBuilder builder(Context); + builder.addParameter(makeGenericParam(), ValueOwnership::InOut); + builder.setResult(makeConcrete(TupleType::getEmpty(Context))); + return builder.build(Id); +} + static ValueDecl *getBindMemoryOperation(ASTContext &Context, Identifier Id) { BuiltinFunctionBuilder builder(Context); builder.addParameter(makeConcrete(Context.TheRawPointerType)); @@ -908,6 +930,16 @@ static ValueDecl *getValueToBridgeObject(ASTContext &C, Identifier Id) { return builder.build(Id); } +static ValueDecl *getCOWBufferForReading(ASTContext &C, Identifier Id) { + // T -> T + // + BuiltinFunctionBuilder builder(C, 1, true); + auto T = makeGenericParam(); + builder.addParameter(T); + builder.setResult(T); + return builder.build(Id); +} + static ValueDecl *getUnsafeGuaranteed(ASTContext &C, Identifier Id) { // T -> (T, Int8Ty) // @@ -2249,9 +2281,16 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { case BuiltinValueKind::IsUnique: case BuiltinValueKind::IsUnique_native: + case BuiltinValueKind::BeginCOWMutation: + case BuiltinValueKind::BeginCOWMutation_native: if (!Types.empty()) return nullptr; + // BeginCOWMutation has the same signature as IsUnique. return getIsUniqueOperation(Context, Id); + case BuiltinValueKind::EndCOWMutation: + if (!Types.empty()) return nullptr; + return getEndCOWMutation(Context, Id); + case BuiltinValueKind::BindMemory: if (!Types.empty()) return nullptr; return getBindMemoryOperation(Context, Id); @@ -2380,6 +2419,10 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { if (!Types.empty()) return nullptr; return getValueToBridgeObject(Context, Id); + + case BuiltinValueKind::COWBufferForReading: + return getCOWBufferForReading(Context, Id); + case BuiltinValueKind::UnsafeGuaranteed: return getUnsafeGuaranteed(Context, Id); diff --git a/lib/SILGen/SILGenBuiltin.cpp b/lib/SILGen/SILGenBuiltin.cpp index 45e94b5575123..69bb753687243 100644 --- a/lib/SILGen/SILGenBuiltin.cpp +++ b/lib/SILGen/SILGenBuiltin.cpp @@ -901,6 +901,45 @@ emitBuiltinIsUnique_native(SILGenFunction &SGF, return ManagedValue::forUnmanaged(result); } +static ManagedValue +emitBuiltinBeginCOWMutation(SILGenFunction &SGF, + SILLocation loc, + SubstitutionMap subs, + ArrayRef args, + SGFContext C) { + return emitBuiltinIsUnique(SGF, loc, subs, args, C); +} + +static ManagedValue +emitBuiltinBeginCOWMutation_native(SILGenFunction &SGF, + SILLocation loc, + SubstitutionMap subs, + ArrayRef args, + SGFContext C) { + return emitBuiltinIsUnique_native(SGF, loc, subs, args, C); +} + +static ManagedValue +emitBuiltinEndCOWMutation(SILGenFunction &SGF, + SILLocation loc, + SubstitutionMap subs, + ArrayRef args, + SGFContext C) { + return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); +} + +static ManagedValue +emitBuiltinCOWBufferForReading(SILGenFunction &SGF, + SILLocation loc, + SubstitutionMap subs, + ArrayRef args, + SGFContext C) { + + + assert(args.size() == 1 && "isUnique_native should have one arg."); + return args[0]; +} + static ManagedValue emitBuiltinBindMemory(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, diff --git a/lib/SILOptimizer/Analysis/ArraySemantic.cpp b/lib/SILOptimizer/Analysis/ArraySemantic.cpp index 807a4d67017d6..ee50619935ccc 100644 --- a/lib/SILOptimizer/Analysis/ArraySemantic.cpp +++ b/lib/SILOptimizer/Analysis/ArraySemantic.cpp @@ -183,7 +183,13 @@ void ArraySemanticsCall::initialize(ApplyInst *AI, StringRef semanticName, // Need a 'self' argument otherwise this is not a semantic call that // we recognize. - if (getKind() < ArrayCallKind::kArrayInit && !hasSelf()) + ArrayCallKind kind = getKind(); + if (kind == ArrayCallKind::kNone) { + SemanticsCall = nullptr; + return; + } + + if (kind < ArrayCallKind::kArrayInit && !hasSelf()) SemanticsCall = nullptr; // A arguments must be passed reference count neutral except for self. diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift index d051f5ede450a..d2dbff0b194c9 100644 --- a/test/IRGen/builtins.swift +++ b/test/IRGen/builtins.swift @@ -683,6 +683,12 @@ func isUniqueIUO(_ ref: inout Builtin.NativeObject?) -> Bool { return Builtin.isUnique(&iuo) } +// CHECK-LABEL: define hidden {{.*}} @"$s8builtins19COWBufferForReadingyAA1CCADnF" +// CHECK: ret %T8builtins1CC* %0 +func COWBufferForReading(_ ref: __owned C) -> C { + return Builtin.COWBufferForReading(ref) +} + // CHECK-LABEL: define {{.*}} @{{.*}}generic_ispod_test func generic_ispod_test(_: T) { // CHECK: [[T0:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[T:%.*]], i32 10 diff --git a/test/SILGen/builtins.swift b/test/SILGen/builtins.swift index fa7792c4c3aab..9aaa51f424b55 100644 --- a/test/SILGen/builtins.swift +++ b/test/SILGen/builtins.swift @@ -600,6 +600,31 @@ func castBitPatternFromBridgeObject(_ bo: Builtin.BridgeObject) -> Builtin.Word return Builtin.castBitPatternFromBridgeObject(bo) } +// CHECK-LABEL: sil hidden [ossa] @$s8builtins16beginCOWMutationySbAA1CCzF +// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*C +// CHECK: [[BUILTIN:%.*]] = is_unique [[WRITE]] : $*C +// CHECK: return +func beginCOWMutation(_ c: inout C) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.beginCOWMutation(&c)) +} + +// CHECK-LABEL: sil hidden [ossa] @$s8builtins23beginCOWMutation_nativeySbAA1CCzF +// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*C +// CHECK: [[CAST:%.*]] = unchecked_addr_cast [[WRITE]] : $*C to $*Builtin.NativeObject +// CHECK: [[BUILTIN:%.*]] = is_unique [[CAST]] : $*Builtin.NativeObject +// CHECK: return +func beginCOWMutation_native(_ c: inout C) -> Bool { + return Bool(_builtinBooleanLiteral: Builtin.beginCOWMutation_native(&c)) +} + +// CHECK-LABEL: sil hidden [ossa] @$s8builtins14endCOWMutationyyAA1CCzF +// CHECK: begin_access +// CHECK-NEXT: tuple () +// CHECK-NEXT: end_access +func endCOWMutation(_ c: inout C) { + Builtin.endCOWMutation(&c) +} + // ---------------------------------------------------------------------------- // isUnique variants // ----------------------------------------------------------------------------