Skip to content

Commit f080a9c

Browse files
authored
Merge pull request #9655 from atrick/access
2 parents d0549ac + 2e8645e commit f080a9c

File tree

3 files changed

+133
-29
lines changed

3 files changed

+133
-29
lines changed

docs/SIL.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2456,7 +2456,7 @@ index_raw_pointer
24562456
%2 = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Int<n>
24572457
// %0 must be of $Builtin.RawPointer type
24582458
// %1 must be of a builtin integer type
2459-
// %2 will be of type $*T
2459+
// %2 will be of type $Builtin.RawPointer
24602460

24612461
Given a ``Builtin.RawPointer`` value ``%0``, returns a pointer value at the
24622462
byte offset ``%1`` relative to ``%0``.

lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ static void diagnoseExclusivityViolation(const AccessedStorage &Storage,
365365
const BeginAccessInst *NewAccess,
366366
ASTContext &Ctx) {
367367

368+
DEBUG(llvm::dbgs() << "Conflict on " << *PriorAccess
369+
<< "\n vs " << *NewAccess
370+
<< "\n in function " << *PriorAccess->getFunction());
371+
368372
// Can't have a conflict if both accesses are reads.
369373
assert(!(PriorAccess->getAccessKind() == SILAccessKind::Read &&
370374
NewAccess->getAccessKind() == SILAccessKind::Read));
@@ -431,30 +435,15 @@ static SILValue findUnderlyingObject(SILValue Value) {
431435
static AccessedStorage findAccessedStorage(SILValue Source) {
432436
SILValue Iter = Source;
433437
while (true) {
434-
// Inductive cases: look through operand to find ultimate source.
435-
if (auto *PBI = dyn_cast<ProjectBoxInst>(Iter)) {
436-
Iter = PBI->getOperand();
437-
continue;
438-
}
439-
440-
if (auto *CVI = dyn_cast<CopyValueInst>(Iter)) {
441-
Iter = CVI->getOperand();
442-
continue;
443-
}
444-
445-
if (auto *MII = dyn_cast<MarkUninitializedInst>(Iter)) {
446-
Iter = MII->getOperand();
447-
continue;
448-
}
449-
450-
// Base cases: make sure ultimate source is recognized.
438+
// Base case for globals: make sure ultimate source is recognized.
451439
if (auto *GAI = dyn_cast<GlobalAddrInst>(Iter)) {
452440
return AccessedStorage(GAI->getReferencedGlobal());
453441
}
454442

443+
// Base case for class objects.
455444
if (auto *REA = dyn_cast<RefElementAddrInst>(Iter)) {
456445
// Do a best-effort to find the identity of the object being projected
457-
// from. It is OK to unsound here (i.e., miss when two ref_element_addrs
446+
// from. It is OK to be unsound here (i.e. miss when two ref_element_addrs
458447
// actually refer the same address) because these will be dynamically
459448
// checked.
460449
SILValue Object = findUnderlyingObject(REA->getOperand());
@@ -463,18 +452,50 @@ static AccessedStorage findAccessedStorage(SILValue Source) {
463452
return AccessedStorage(AccessedStorageKind::ClassProperty, OP);
464453
}
465454

466-
if (isa<AllocBoxInst>(Iter) || isa<BeginAccessInst>(Iter) ||
467-
isa<SILFunctionArgument>(Iter)) {
468-
// Treat the instruction itself as the identity of the storage being
469-
// being accessed.
455+
switch (Iter->getKind()) {
456+
// Inductive cases: look through operand to find ultimate source.
457+
case ValueKind::ProjectBoxInst:
458+
case ValueKind::CopyValueInst:
459+
case ValueKind::MarkUninitializedInst:
460+
case ValueKind::UncheckedAddrCastInst:
461+
// Inlined access to subobjects.
462+
case ValueKind::StructElementAddrInst:
463+
case ValueKind::TupleElementAddrInst:
464+
case ValueKind::UncheckedTakeEnumDataAddrInst:
465+
case ValueKind::RefTailAddrInst:
466+
case ValueKind::TailAddrInst:
467+
case ValueKind::IndexAddrInst:
468+
Iter = cast<SILInstruction>(Iter)->getOperand(0);
469+
continue;
470+
471+
// Base address producers.
472+
case ValueKind::AllocBoxInst:
473+
// An AllocBox is a fully identified memory location.
474+
case ValueKind::AllocStackInst:
475+
// An AllocStack is a fully identified memory location, which may occur
476+
// after inlining code already subjected to stack promotion.
477+
case ValueKind::BeginAccessInst:
478+
// The current access is nested within another access.
479+
// View the outer access as a separate location because nested accesses do
480+
// not conflict with each other.
481+
case ValueKind::SILFunctionArgument:
482+
// A function argument is effectively a nested access, enforced
483+
// independently in the caller and callee.
484+
case ValueKind::PointerToAddressInst:
485+
// An addressor provides access to a global or class property via a
486+
// RawPointer. Calling the addressor casts that raw pointer to an address.
470487
return AccessedStorage(Iter);
471-
}
472488

473-
// For now we're still allowing arbitrary addresses here. Once
474-
// we start doing a best-effort static check for dynamically-enforced
475-
// accesses we should lock this down to only recognized sources.
476-
assert(Iter->getType().isAddress() || Iter->getType().is<SILBoxType>());
477-
return AccessedStorage(Iter);
489+
// Unsupported address producers.
490+
// Initialization is always local.
491+
case ValueKind::InitEnumDataAddrInst:
492+
case ValueKind::InitExistentialAddrInst:
493+
// Accessing an existential value requires a cast.
494+
case ValueKind::OpenExistentialAddrInst:
495+
default:
496+
DEBUG(llvm::dbgs() << "Bad memory access source: " << Iter);
497+
llvm_unreachable("Unexpected access source.");
498+
}
478499
}
479500
}
480501

test/SILOptimizer/exclusivity_static_diagnostics.sil

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,3 +462,86 @@ bb23:
462462
bbUnreachable:
463463
br bb22
464464
}
465+
466+
// Check that a pointer_to_address access passes diagnostics.
467+
//
468+
// CHECK-LABEL: sil hidden @pointerToAddr
469+
sil hidden @pointerToAddr : $@convention(thin) (Builtin.RawPointer) -> Int {
470+
bb0(%0: $Builtin.RawPointer):
471+
%adr = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Int
472+
%access = begin_access [read] [dynamic] %adr : $*Int
473+
%val = load [trivial] %access : $*Int
474+
end_access %access : $*Int
475+
return %val : $Int
476+
}
477+
478+
// Helper.
479+
struct S {
480+
var x: Int
481+
}
482+
483+
// Check inlined struct element access.
484+
// This only happens when mandatory passes are applied repeatedly.
485+
// e.g. importing from a debug standard library.
486+
//
487+
// CHECK-LABEL: sil hidden @inlinedStructElement
488+
sil hidden @inlinedStructElement : $@convention(thin) (@inout S) -> Int {
489+
bb0(%0 : $*S):
490+
%2 = begin_access [modify] [static] %0 : $*S
491+
%3 = struct_element_addr %2 : $*S, #S.x
492+
%4 = begin_access [read] [static] %3 : $*Int
493+
%5 = load [trivial] %4 : $*Int
494+
end_access %4 : $*Int
495+
end_access %2 : $*S
496+
return %5 : $Int
497+
}
498+
499+
// Check inlined tuple element access.
500+
// This only happens when mandatory passes are applied repeatedly.
501+
//
502+
// CHECK-LABEL: sil hidden @inlinedTupleElement
503+
sil hidden @inlinedTupleElement : $@convention(thin) (@inout (Int, Int)) -> Int {
504+
bb0(%0 : $*(Int, Int)):
505+
%2 = begin_access [modify] [static] %0 : $*(Int, Int)
506+
%3 = tuple_element_addr %2 : $*(Int, Int), 0
507+
%4 = begin_access [read] [static] %3 : $*Int
508+
%5 = load [trivial] %4 : $*Int
509+
end_access %4 : $*Int
510+
end_access %2 : $*(Int, Int)
511+
return %5 : $Int
512+
}
513+
514+
// Check inlined enum access.
515+
// This only happens when mandatory passes are applied repeatedly.
516+
//
517+
// CHECK-LABEL: sil hidden @inlinedEnumValue
518+
sil hidden @inlinedEnumValue : $@convention(thin) (Int) -> (@out Optional<Int>, Int) {
519+
bb0(%0 : $*Optional<Int>, %1 : $Int):
520+
%6 = unchecked_take_enum_data_addr %0 : $*Optional<Int>, #Optional.some!enumelt.1
521+
%7 = begin_access [read] [static] %6 : $*Int
522+
%8 = load [trivial] %7 : $*Int
523+
end_access %7 : $*Int
524+
return %8 : $Int
525+
}
526+
527+
// Helper.
528+
class Storage {}
529+
530+
// Check inlined array access.
531+
// This only happens when mandatory passes are applied repeatedly.
532+
//
533+
// CHECK-LABEL: sil hidden @inlinedArrayProp
534+
sil hidden @inlinedArrayProp : $@convention(thin) (@guaranteed Storage, Builtin.Word) -> Int {
535+
bb0(%0 : $Storage, %1 : $Builtin.Word):
536+
%2 = ref_tail_addr %0 : $Storage, $UInt
537+
%3 = begin_access [read] [static] %2 : $*UInt
538+
%4 = tail_addr %3 : $*UInt, %1 : $Builtin.Word, $Int
539+
%5 = begin_access [read] [static] %4 : $*Int
540+
%6 = index_addr %5 : $*Int, %1 : $Builtin.Word
541+
%7 = begin_access [read] [static] %6 : $*Int
542+
%8 = load [trivial] %7 : $*Int
543+
end_access %7 : $*Int
544+
end_access %5 : $*Int
545+
end_access %3 : $*UInt
546+
return %8 : $Int
547+
}

0 commit comments

Comments
 (0)