Skip to content

[NFC] SIL: Clarified deinit barrier APIs. #70774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,30 +98,50 @@ public struct CalleeAnalysis {
}
}

extension FullApplySite {
extension Value {
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
guard let callees = analysis.getCallees(callee: callee) else {
guard let callees = analysis.getCallees(callee: self) else {
return true
}
return callees.contains { $0.isDeinitBarrier }
}
}

extension Instruction {
public final func maySynchronize(_ analysis: CalleeAnalysis) -> Bool {
if let site = self as? FullApplySite {
return site.isBarrier(analysis)
}
return maySynchronizeNotConsideringSideEffects
extension FullApplySite {
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
return callee.isBarrier(analysis)
}
}

extension EndApplyInst {
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
}
}

extension AbortApplyInst {
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
}
}

extension Instruction {
/// Whether lifetime ends of lexical values may safely be hoisted over this
/// instruction.
///
/// Deinitialization barriers constrain variable lifetimes. Lexical
/// end_borrow, destroy_value, and destroy_addr cannot be hoisted above them.
public final func isDeinitBarrier(_ analysis: CalleeAnalysis) -> Bool {
return mayAccessPointer || mayLoadWeakOrUnowned || maySynchronize(analysis)
if let site = self as? FullApplySite {
return site.isBarrier(analysis)
}
if let eai = self as? EndApplyInst {
return eai.isBarrier(analysis)
}
if let aai = self as? AbortApplyInst {
return aai.isBarrier(analysis)
}
return mayAccessPointer || mayLoadWeakOrUnowned || maySynchronize
}
}

Expand Down
4 changes: 2 additions & 2 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ public class Instruction : CustomStringConvertible, Hashable {
return bridged.mayLoadWeakOrUnowned()
}

public final var maySynchronizeNotConsideringSideEffects: Bool {
return bridged.maySynchronizeNotConsideringSideEffects()
public final var maySynchronize: Bool {
return bridged.maySynchronize()
}

public final var mayBeDeinitBarrierNotConsideringSideEffects: Bool {
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/MemAccessUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ bool mayLoadWeakOrUnowned(SILInstruction* instruction);

/// Conservatively, whether this instruction could involve a synchronization
/// point like a memory barrier, lock or syscall.
bool maySynchronizeNotConsideringSideEffects(SILInstruction* instruction);
bool maySynchronize(SILInstruction* instruction);

/// Conservatively, whether this instruction could be a barrier to hoisting
/// destroys.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ struct BridgedInstruction {
BRIDGED_INLINE bool maySuspend() const;
bool mayAccessPointer() const;
bool mayLoadWeakOrUnowned() const;
bool maySynchronizeNotConsideringSideEffects() const;
bool maySynchronize() const;
bool mayBeDeinitBarrierNotConsideringSideEffects() const;

// =========================================================================//
Expand Down
29 changes: 23 additions & 6 deletions lib/SIL/Utils/MemAccessUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,14 @@ bool swift::isLetAddress(SILValue address) {
//===----------------------------------------------------------------------===//

bool swift::mayAccessPointer(SILInstruction *instruction) {
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
!isa<AbortApplyInst>(instruction));
if (!instruction->mayReadOrWriteMemory())
return false;
if (isa<BuiltinInst>(instruction)) {
// Consider all builtins that read/write memory to access pointers.
return true;
}
bool retval = false;
visitAccessedAddress(instruction, [&retval](Operand *operand) {
auto accessStorage = AccessStorage::compute(operand->get());
Expand All @@ -451,6 +457,11 @@ bool swift::mayAccessPointer(SILInstruction *instruction) {
}

bool swift::mayLoadWeakOrUnowned(SILInstruction *instruction) {
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
!isa<AbortApplyInst>(instruction));
if (isa<BuiltinInst>(instruction)) {
return instruction->mayReadOrWriteMemory();
}
return isa<LoadWeakInst>(instruction)
|| isa<LoadUnownedInst>(instruction)
|| isa<StrongCopyUnownedValueInst>(instruction)
Expand All @@ -459,17 +470,23 @@ bool swift::mayLoadWeakOrUnowned(SILInstruction *instruction) {

/// Conservatively, whether this instruction could involve a synchronization
/// point like a memory barrier, lock or syscall.
bool swift::maySynchronizeNotConsideringSideEffects(SILInstruction *instruction) {
return FullApplySite::isa(instruction)
|| isa<EndApplyInst>(instruction)
|| isa<AbortApplyInst>(instruction)
|| isa<HopToExecutorInst>(instruction);
bool swift::maySynchronize(SILInstruction *instruction) {
assert(!FullApplySite::isa(instruction) && !isa<EndApplyInst>(instruction) &&
!isa<AbortApplyInst>(instruction));
if (isa<BuiltinInst>(instruction)) {
return instruction->mayReadOrWriteMemory();
}
return isa<HopToExecutorInst>(instruction);
}

bool swift::mayBeDeinitBarrierNotConsideringSideEffects(SILInstruction *instruction) {
if (FullApplySite::isa(instruction) || isa<EndApplyInst>(instruction) ||
isa<AbortApplyInst>(instruction)) {
return true;
}
bool retval = mayAccessPointer(instruction)
|| mayLoadWeakOrUnowned(instruction)
|| maySynchronizeNotConsideringSideEffects(instruction);
|| maySynchronize(instruction);
assert(!retval || !isa<BranchInst>(instruction) && "br as deinit barrier!?");
return retval;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/Utils/SILBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,8 +443,8 @@ bool BridgedInstruction::mayLoadWeakOrUnowned() const {
return ::mayLoadWeakOrUnowned(unbridged());
}

bool BridgedInstruction::maySynchronizeNotConsideringSideEffects() const {
return ::maySynchronizeNotConsideringSideEffects(unbridged());
bool BridgedInstruction::maySynchronize() const {
return ::maySynchronize(unbridged());
}

bool BridgedInstruction::mayBeDeinitBarrierNotConsideringSideEffects() const {
Expand Down
15 changes: 15 additions & 0 deletions test/SILOptimizer/deinit_barrier.sil
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,18 @@ entry:
%retval = tuple ()
return %retval : $()
}

// CHECK-LABEL: begin running test {{.*}} on rdar120656227: is-deinit-barrier
// CHECK: builtin "int_memmove_RawPointer_RawPointer_Int64"
// CHECK: true
// CHECK-LABEL: end running test {{.*}} on rdar120656227: is-deinit-barrier
sil [ossa] @rdar120656227 : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer) -> () {
bb0(%42 : $Builtin.RawPointer, %9 : $Builtin.RawPointer):
%14 = integer_literal $Builtin.Int64, 27
%28 = integer_literal $Builtin.Int1, 1
specify_test "is-deinit-barrier @instruction"
%43 = builtin "int_memmove_RawPointer_RawPointer_Int64"(%42 : $Builtin.RawPointer, %9 : $Builtin.RawPointer, %14 : $Builtin.Int64, %28 : $Builtin.Int1) : $()
%68 = tuple ()
return %68 : $()
}