Skip to content

Commit 6350397

Browse files
committed
[Exclusivity] Add builtins needed for dynamic enforcement of exclusivity.
This is chopped off from Devin Coughlin's PR so I can test the actual fix that should make the rest of his commit work. rdar://problem/31972680
1 parent b05094f commit 6350397

File tree

6 files changed

+177
-0
lines changed

6 files changed

+177
-0
lines changed

include/swift/AST/Builtins.def

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,27 @@ BUILTIN_SIL_OPERATION(Gep, "gep", Integer)
294294
/// allocated element type 'E'.
295295
BUILTIN_SIL_OPERATION(GetTailAddr, "getTailAddr", Integer)
296296

297+
/// performInstantaneousReadAccess(Builtin.RawPointer, T.Type) -> ()
298+
/// Begin and then immediately end a read access to the given raw pointer,
299+
/// which will be treated as an address of type 'T'.
300+
BUILTIN_SIL_OPERATION(PerformInstantaneousReadAccess,
301+
"performInstantaneousReadAccess", Special)
302+
303+
/// beginUnpairedModifyAccess(Builtin.RawPointer, Builtin.RawPointer,
304+
/// T.Type) -> ()
305+
/// Begins but does not end a 'modify' access to the first raw pointer argument.
306+
/// The second raw pointer must be a pointer to an UnsafeValueBuffer, which
307+
/// will be used by the runtime to record the access. The lifetime of the
308+
/// value buffer must be longer than that of the access itself. The accessed
309+
/// address will be treated as having type 'T'.
310+
BUILTIN_SIL_OPERATION(BeginUnpairedModifyAccess, "beginUnpairedModifyAccess",
311+
Special)
312+
313+
/// endUnpairedAccess(Builtin.RawPointer) -> ()
314+
/// Ends an in-progress unpaired access. The raw pointer argument must be
315+
/// be a pointer to an UnsafeValueBuffer that records an in progress access.
316+
BUILTIN_SIL_OPERATION(EndUnpairedAccess, "endUnpairedAccess", Special)
317+
297318
/// condfail(Int1) -> ()
298319
/// Triggers a runtime failure if the condition is true.
299320
BUILTIN_SIL_OPERATION(CondFail, "condfail", Special)

lib/AST/Builtins.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,31 @@ static ValueDecl *getGetTailAddrOperation(ASTContext &Context, Identifier Id,
738738
return builder.build(Id);
739739
}
740740

741+
static ValueDecl *getBeginUnpairedAccessOperation(ASTContext &Context,
742+
Identifier Id) {
743+
BuiltinGenericSignatureBuilder builder(Context);
744+
builder.addParameter(makeConcrete(Context.TheRawPointerType));
745+
builder.addParameter(makeConcrete(Context.TheRawPointerType));
746+
builder.addParameter(makeMetatype(makeGenericParam(0)));
747+
builder.setResult(makeConcrete(Context.TheEmptyTupleType));
748+
return builder.build(Id);
749+
}
750+
751+
static ValueDecl *
752+
getPerformInstantaneousReadAccessOperation(ASTContext &Context,
753+
Identifier Id) {
754+
BuiltinGenericSignatureBuilder builder(Context);
755+
builder.addParameter(makeConcrete(Context.TheRawPointerType));
756+
builder.addParameter(makeMetatype(makeGenericParam(0)));
757+
builder.setResult(makeConcrete(Context.TheEmptyTupleType));
758+
return builder.build(Id);
759+
}
760+
761+
static ValueDecl *getEndUnpairedAccessOperation(ASTContext &Context,
762+
Identifier Id) {
763+
return getBuiltinFunction(Id, { Context.TheRawPointerType },
764+
Context.TheEmptyTupleType);
765+
}
741766
static ValueDecl *getSizeOrAlignOfOperation(ASTContext &Context,
742767
Identifier Id) {
743768
BuiltinGenericSignatureBuilder builder(Context);
@@ -1644,6 +1669,18 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
16441669
if (Types.size() != 1) return nullptr;
16451670
return getGetTailAddrOperation(Context, Id, Types[0]);
16461671

1672+
case BuiltinValueKind::PerformInstantaneousReadAccess:
1673+
if (!Types.empty()) return nullptr;
1674+
return getPerformInstantaneousReadAccessOperation(Context, Id);
1675+
1676+
case BuiltinValueKind::BeginUnpairedModifyAccess:
1677+
if (!Types.empty()) return nullptr;
1678+
return getBeginUnpairedAccessOperation(Context, Id);
1679+
1680+
case BuiltinValueKind::EndUnpairedAccess:
1681+
if (!Types.empty()) return nullptr;
1682+
return getEndUnpairedAccessOperation(Context, Id);
1683+
16471684
#define BUILTIN(id, name, Attrs)
16481685
#define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) case BuiltinValueKind::id:
16491686
#include "swift/AST/Builtins.def"

lib/SIL/SILOwnershipVerifier.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,9 @@ BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(AddressOf)
14311431
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(GepRaw)
14321432
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(Gep)
14331433
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(GetTailAddr)
1434+
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(PerformInstantaneousReadAccess)
1435+
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(BeginUnpairedModifyAccess)
1436+
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(EndUnpairedAccess)
14341437
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(CondFail)
14351438
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(FixLifetime)
14361439
BUILTINS_THAT_SHOULD_HAVE_BEEN_LOWERED_TO_SILINSTS(IsUnique)

lib/SIL/ValueOwnershipKindClassifier.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ CONSTANT_OWNERSHIP_BUILTIN(Trivial, AddressOf)
475475
CONSTANT_OWNERSHIP_BUILTIN(Trivial, GepRaw)
476476
CONSTANT_OWNERSHIP_BUILTIN(Trivial, Gep)
477477
CONSTANT_OWNERSHIP_BUILTIN(Trivial, GetTailAddr)
478+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, PerformInstantaneousReadAccess)
479+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, BeginUnpairedModifyAccess)
480+
CONSTANT_OWNERSHIP_BUILTIN(Trivial, EndUnpairedAccess)
478481
CONSTANT_OWNERSHIP_BUILTIN(Trivial, OnFastPath)
479482
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUnique)
480483
CONSTANT_OWNERSHIP_BUILTIN(Trivial, IsUniqueOrPinned)

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,90 @@ static ManagedValue emitBuiltinGetTailAddr(SILGenFunction &SGF,
517517
return ManagedValue::forUnmanaged(addr);
518518
}
519519

520+
/// Specialized emitter for Builtin.beginUnpairedModifyAccess.
521+
static ManagedValue emitBuiltinBeginUnpairedModifyAccess(SILGenFunction &SGF,
522+
SILLocation loc,
523+
SubstitutionList substitutions,
524+
ArrayRef<ManagedValue> args,
525+
SGFContext C) {
526+
assert(substitutions.size() == 1 &&
527+
"Builtin.beginUnpairedModifyAccess should have one substitution");
528+
assert(args.size() == 3 &&
529+
"beginUnpairedModifyAccess should be given three arguments");
530+
531+
SILType elemTy = SGF.getLoweredType(substitutions[0].getReplacement());
532+
SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
533+
elemTy.getAddressType(),
534+
/*strict*/ true,
535+
/*invariant*/ false);
536+
537+
SILType valueBufferTy =
538+
SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType);
539+
540+
SILValue buffer = SGF.B.createPointerToAddress(loc, args[1].getUnmanagedValue(),
541+
valueBufferTy.getAddressType(),
542+
/*strict*/ true,
543+
/*invariant*/ false);
544+
SGF.B.createBeginUnpairedAccess(loc, addr, buffer, SILAccessKind::Modify,
545+
SILAccessEnforcement::Dynamic,
546+
/*noNestedConflict*/ false);
547+
548+
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
549+
}
550+
551+
/// Specialized emitter for Builtin.performInstantaneousReadAccess
552+
static ManagedValue emitBuiltinPerformInstantaneousReadAccess(SILGenFunction &SGF,
553+
SILLocation loc,
554+
SubstitutionList substitutions,
555+
ArrayRef<ManagedValue> args,
556+
SGFContext C) {
557+
assert(substitutions.size() == 1 &&
558+
"Builtin.performInstantaneousReadAccess should have one substitution");
559+
assert(args.size() == 2 &&
560+
"Builtin.performInstantaneousReadAccess should be given "
561+
"two arguments");
562+
563+
SILType elemTy = SGF.getLoweredType(substitutions[0].getReplacement());
564+
SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
565+
elemTy.getAddressType(),
566+
/*strict*/ true,
567+
/*invariant*/ false);
568+
569+
// Begin and then immediately end a read access. No nested conflict is
570+
// possible because there are no instructions between the begin and the
571+
// end of the access.
572+
SILValue access = SGF.B.createBeginAccess(loc, addr, SILAccessKind::Read,
573+
SILAccessEnforcement::Dynamic,
574+
/*noNestedConflict*/ true);
575+
SGF.B.createEndAccess(loc, access, /*aborted*/ false);
576+
577+
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
578+
}
579+
580+
/// Specialized emitter for Builtin.endUnpairedAccessModifyAccess.
581+
static ManagedValue emitBuiltinEndUnpairedAccess(SILGenFunction &SGF,
582+
SILLocation loc,
583+
SubstitutionList substitutions,
584+
ArrayRef<ManagedValue> args,
585+
SGFContext C) {
586+
assert(substitutions.size() == 0 &&
587+
"Builtin.endUnpairedAccess should have no substitutions");
588+
assert(args.size() == 1 &&
589+
"endUnpairedAccess should be given one argument");
590+
591+
SILType valueBufferTy =
592+
SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType);
593+
594+
SILValue buffer = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(),
595+
valueBufferTy.getAddressType(),
596+
/*strict*/ true,
597+
/*invariant*/ false);
598+
SGF.B.createEndUnpairedAccess(loc, buffer, SILAccessEnforcement::Dynamic,
599+
/*aborted*/ false);
600+
601+
return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc));
602+
}
603+
520604
/// Specialized emitter for Builtin.condfail.
521605
static ManagedValue emitBuiltinCondFail(SILGenFunction &SGF,
522606
SILLocation loc,

test/SILGen/builtins.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,35 @@ func getTailAddr<T1, T2>(start: Builtin.RawPointer, i: Builtin.Word, ty1: T1.Typ
369369
return Builtin.getTailAddr_Word(start, i, ty1, ty2)
370370
}
371371

372+
// CHECK-LABEL: sil hidden @$S8builtins25beginUnpairedModifyAccess{{[_0-9a-zA-Z]*}}F
373+
// CHECK: [[P2A_ADDR:%.*]] = pointer_to_address %0
374+
// CHECK: [[P2A_SCRATCH:%.*]] = pointer_to_address %1
375+
// CHECK: begin_unpaired_access [modify] [dynamic] [[P2A_ADDR]] : $*T1, [[P2A_SCRATCH]] : $*Builtin.UnsafeValueBuffer
376+
// CHECK: [[RESULT:%.*]] = tuple ()
377+
// CHECK: [[RETURN:%.*]] = tuple ()
378+
// CHECK: return [[RETURN]] : $()
379+
// CHECK: } // end sil function '$S8builtins25beginUnpairedModifyAccess{{[_0-9a-zA-Z]*}}F'
380+
func beginUnpairedModifyAccess<T1>(address: Builtin.RawPointer, scratch: Builtin.RawPointer, ty1: T1.Type) {
381+
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
382+
}
383+
384+
// CHECK-LABEL: sil hidden @$S8builtins17endUnpairedAccess{{[_0-9a-zA-Z]*}}F : $@convention(thin) (Builtin.RawPointer) -> () {
385+
// CHECK: [[P2A_ADDR:%.*]] = pointer_to_address %0
386+
// CHECK: end_unpaired_access [dynamic] [[P2A_ADDR]]
387+
// CHECK: } // end sil function '$S8builtins17endUnpairedAccess{{[_0-9a-zA-Z]*}}F'
388+
func endUnpairedAccess(address: Builtin.RawPointer) {
389+
Builtin.endUnpairedAccess(address)
390+
}
391+
392+
// CHECK-LABEL: sil hidden @$S8builtins30performInstantaneousReadAccess{{[_0-9a-zA-Z]*}}F
393+
// CHECK: [[P2A_ADDR:%.*]] = pointer_to_address %0
394+
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[P2A_ADDR]] : $*T1
395+
// CHECK-NEXT: end_access [[ACCESS]] : $*T1
396+
// CHECK: } // end sil function '$S8builtins30performInstantaneousReadAccess{{[_0-9a-zA-Z]*}}F'
397+
func performInstantaneousReadAccess<T1>(address: Builtin.RawPointer, scratch: Builtin.RawPointer, ty1: T1.Type) {
398+
Builtin.performInstantaneousReadAccess(address, ty1);
399+
}
400+
372401
// CHECK-LABEL: sil hidden @$S8builtins8condfail{{[_0-9a-zA-Z]*}}F
373402
func condfail(_ i: Builtin.Int1) {
374403
Builtin.condfail(i)

0 commit comments

Comments
 (0)