Skip to content
Closed
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
7 changes: 7 additions & 0 deletions include/swift/Strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#ifndef SWIFT_STRINGS_H
#define SWIFT_STRINGS_H

#include "swift/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"

namespace swift {

/// The extension for serialized modules.
Expand Down Expand Up @@ -89,6 +92,10 @@ constexpr static const char BUILTIN_TYPE_NAME_VEC[] = "Builtin.Vec";
constexpr static const char BUILTIN_TYPE_NAME_SILTOKEN[] = "Builtin.SILToken";
/// The name of the Builtin type for Word
constexpr static const char BUILTIN_TYPE_NAME_WORD[] = "Builtin.Word";

constexpr static StringLiteral OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY =
"optimize.sil.preserve_exclusivity";

} // end namespace swift

#endif // SWIFT_STRINGS_H
12 changes: 11 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2310,11 +2310,21 @@ llvm::Function *IRGenModule::getAddrOfSILFunction(SILFunction *f,

LinkInfo link = LinkInfo::get(*this, entity, forDefinition);

if (f->getInlineStrategy() == NoInline) {
switch (f->getInlineStrategy()) {
case NoInline:
attrs = attrs.addAttribute(signature.getType()->getContext(),
llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoInline);
break;
case AlwaysInline:
attrs = attrs.addAttribute(signature.getType()->getContext(),
llvm::AttributeList::FunctionIndex,
llvm::Attribute::AlwaysInline);
break;
case InlineDefault:
break;
}

if (isReadOnlyFunction(f)) {
attrs = attrs.addAttribute(signature.getType()->getContext(),
llvm::AttributeList::FunctionIndex,
Expand Down
7 changes: 7 additions & 0 deletions lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "swift/Basic/Range.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/Strings.h"
#include "llvm/Support/CommandLine.h"

using namespace swift;
Expand Down Expand Up @@ -167,6 +168,12 @@ struct AccessMarkerEliminationPass : SILModuleTransform {
void run() override {
auto &M = *getModule();
for (auto &F : M) {
if (F.hasSemanticsAttr(OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY)) {
DEBUG(llvm::dbgs() << "Skipping " << F.getName() << ". Found "
<< OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY << " tag!\n");
continue;
}

bool removedAny = AccessMarkerElimination(&F).stripMarkers();

// Only invalidate analyses if we removed some markers.
Expand Down
24 changes: 18 additions & 6 deletions lib/SILOptimizer/Mandatory/IRGenPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
///
//===----------------------------------------------------------------------===//

#include "swift/SILOptimizer/PassManager/Passes.h"
#define DEBUG_TYPE "sil-cleanup"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/Local.h"
#include "swift/Strings.h"

using namespace swift;

Expand Down Expand Up @@ -68,10 +70,20 @@ namespace {

class IRGenPrepare : public SILFunctionTransform {
void run() override {
bool shouldInvalidate = cleanFunction(*getFunction());
if (!shouldInvalidate)
return;
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
SILFunction *F = getFunction();

if (F->hasSemanticsAttr(OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY)) {
assert(F->getInlineStrategy() == NoInline &&
"All OPTIMIZE_SIL_PRESERVE_EXCLUSIVITY functions should have "
"no-inline");
// We always want to inline these at the llvm level.
F->setInlineStrategy(AlwaysInline);
}

bool shouldInvalidate = cleanFunction(*F);

if (shouldInvalidate)
invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions);
}
};

Expand Down
102 changes: 102 additions & 0 deletions test/IRGen/preserve_exclusivity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// RUN: %target-swift-frontend -parse-stdlib -parse-stdlib -emit-ir -Onone %s | %FileCheck --check-prefix=IR-Onone %s

// We check separately that:
//
// 1. We properly emit our special functions as inline always.
// 2. end-to-end we inline the access markers.

// RUN: %target-swift-frontend -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -parse-stdlib -emit-ir -O -disable-llvm-optzns %s | %FileCheck --check-prefix=IR-Osil %s
// RUN: %target-swift-frontend -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -parse-stdlib -emit-ir -O %s | %FileCheck --check-prefix=IR-Ollvm %s

@_silgen_name("marker1")
func marker1() -> ()

@_silgen_name("marker2")
func marker2() -> ()

@_silgen_name("marker3")
func marker3() -> ()

@_silgen_name("marker4")
func marker4() -> ()

// IR-Onone: define swiftcc void @"$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1)
// IR-Onone: call void @swift_beginAccess
// IR-Onone-NEXT: ret void

// IR-Osil: define swiftcc void @"$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1) [[ATTR:#[0-9][0-9]*]] {
// IR-Osil: call void @swift_beginAccess
// IR-Osil-NEXT: ret void

@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker1()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// IR-Onone: define swiftcc void @"$S20preserve_exclusivity8endNoOptyyBpF"(i8*)
// IR-Onone: call void @swift_endAccess
// IR-Onone-NEXT: ret void

// IR-Osil: define swiftcc void @"$S20preserve_exclusivity8endNoOptyyBpF"(i8*) [[ATTR]]
// IR-Osil: call void @swift_endAccess
// IR-Osil-NEXT: ret void
@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func endNoOpt(_ address: Builtin.RawPointer) {
marker2()
Builtin.endUnpairedAccess(address)
}

class Klass {}

// Make sure testNoOpt properly inlines in our functions.
//
// IR-Ollvm: define swiftcc void @"$S20preserve_exclusivity9testNoOptyyBpF"(i8*)
// IR-Ollvm: call swiftcc void @marker1
// IR-Ollvm: call void @swift_beginAccess
// IR-Ollvm: call swiftcc void @marker2
// IR-Ollvm: call void @swift_endAccess
// IR-Ollvm-NEXT: ret void
public func testNoOpt(_ k1: Builtin.RawPointer) {
beginNoOpt(k1, k1, Builtin.RawPointer.self)
endNoOpt(k1)
}

// IR-Onone: define swiftcc void @"$S20preserve_exclusivity8beginOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1)
// IR-Onone: call void @swift_beginAccess
// IR-Onone-NEXT: ret void

// IR-Osil: define swiftcc void @"$S20preserve_exclusivity8beginOptyyBp_BpxmtlF"(i8*, i8*, %swift.type*, %swift.type* %T1)
// IR-Osil-NEXT: entry
// IR-Osil-NEXT: call swiftcc void @marker3
// IR-Osil-NEXT: ret void

@inline(never)
public func beginOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker3()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// IR-Onone: define swiftcc void @"$S20preserve_exclusivity6endOptyyBpF"(i8*)
// IR-Onone: call void @swift_endAccess
// IR-Onone-NEXT: ret void

// IR-Osil: define swiftcc void @"$S20preserve_exclusivity6endOptyyBpF"(i8*)
// IR-Osil-NEXT: entry
// IR-Osil-NEXT: call swiftcc void @marker4
// IR-Osil-NEXT: ret void

@inline(never)
public func endOpt(_ address: Builtin.RawPointer) {
marker4()
Builtin.endUnpairedAccess(address)
}

public func testOpt(_ k1: Builtin.RawPointer) {
beginOpt(k1, k1, Builtin.RawPointer.self)
endOpt(k1)
}

// IR-Osil: attributes [[ATTR]] = { alwaysinline
84 changes: 84 additions & 0 deletions test/SILGen/preserve_exclusivity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// RUN: %target-swift-frontend -parse-stdlib -parse-stdlib -emit-silgen %s | %FileCheck --check-prefix=SILGEN %s
// RUN: %target-swift-frontend -parse-stdlib -parse-stdlib -emit-sil -Onone %s | %FileCheck --check-prefix=CANONICAL %s

@_silgen_name("marker1")
func marker1() -> ()

@_silgen_name("marker2")
func marker2() -> ()

@_silgen_name("marker3")
func marker3() -> ()

@_silgen_name("marker4")
func marker4() -> ()

// SILGEN: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// SILGEN: begin_unpaired_access
// SILGEN: } // end sil function '$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF

// CANONICAL: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// CANONICAL: begin_unpaired_access
// CANONICAL: } // end sil function '$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF

@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker1()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// SILGEN: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity8endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// SILGEN: end_unpaired_access
// SILGEN: } // end sil function '$S20preserve_exclusivity8endNoOptyyBpF'

// CANONICAL: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity8endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// CANONICAL: end_unpaired_access
// CANONICAL: } // end sil function '$S20preserve_exclusivity8endNoOptyyBpF'

@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func endNoOpt(_ address: Builtin.RawPointer) {
marker2()
Builtin.endUnpairedAccess(address)
}

class Klass {}

public func testNoOpt(_ k1: Builtin.RawPointer) {
beginNoOpt(k1, k1, Builtin.RawPointer.self)
endNoOpt(k1)
}

// SILGEN: sil [noinline] @$S20preserve_exclusivity8beginOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// SILGEN: begin_unpaired_access
// SILGEN: } // end sil function '$S20preserve_exclusivity8beginOptyyBp_BpxmtlF'

// CANONICAL: sil [noinline] @$S20preserve_exclusivity8beginOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// CANONICAL: begin_unpaired_access
// CANONICAL: } // end sil function '$S20preserve_exclusivity8beginOptyyBp_BpxmtlF'

@inline(never)
public func beginOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker3()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// SILGEN: sil [noinline] @$S20preserve_exclusivity6endOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// SILGEN: end_unpaired_access
// SILGEN: } // end sil function '$S20preserve_exclusivity6endOptyyBpF'

// CANONICAL: sil [noinline] @$S20preserve_exclusivity6endOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// CANONICAL: end_unpaired_access
// CANONICAL: } // end sil function '$S20preserve_exclusivity6endOptyyBpF'

@inline(never)
public func endOpt(_ address: Builtin.RawPointer) {
marker4()
Builtin.endUnpairedAccess(address)
}

public func testOpt(_ k1: Builtin.RawPointer) {
beginOpt(k1, k1, Builtin.RawPointer.self)
endOpt(k1)
}
67 changes: 67 additions & 0 deletions test/SILOptimizer/preserve_exclusivity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// RUN: %target-swift-frontend -parse-stdlib -Xllvm -sil-disable-pass=FunctionSignatureOpts -Xllvm -sil-disable-pass=GenericSpecializer -parse-stdlib -emit-sil -O %s | %FileCheck %s

@_silgen_name("marker1")
func marker1() -> ()

@_silgen_name("marker2")
func marker2() -> ()

@_silgen_name("marker3")
func marker3() -> ()

@_silgen_name("marker4")
func marker4() -> ()

// CHECK: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// CHECK: begin_unpaired_access
// CHECK: } // end sil function '$S20preserve_exclusivity10beginNoOptyyBp_BpxmtlF'

@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func beginNoOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker1()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// CHECK: sil [noinline] [_semantics "optimize.sil.preserve_exclusivity"] @$S20preserve_exclusivity8endNoOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// CHECK: end_unpaired_access
// CHECK: } // end sil function '$S20preserve_exclusivity8endNoOptyyBpF'

@inline(never)
@_semantics("optimize.sil.preserve_exclusivity")
public func endNoOpt(_ address: Builtin.RawPointer) {
marker2()
Builtin.endUnpairedAccess(address)
}

class Klass {}

public func testNoOpt(_ k1: Builtin.RawPointer) {
beginNoOpt(k1, k1, Builtin.RawPointer.self)
endNoOpt(k1)
}

// CHECK: sil [noinline] @$S20preserve_exclusivity8beginOptyyBp_BpxmtlF : $@convention(thin) <T1> (Builtin.RawPointer, Builtin.RawPointer, @thick T1.Type) -> () {
// CHECK-NOT: begin_unpaired_access
// CHECK: } // end sil function '$S20preserve_exclusivity8beginOptyyBp_BpxmtlF'

@inline(never)
public func beginOpt<T1>(_ address: Builtin.RawPointer, _ scratch: Builtin.RawPointer, _ ty1: T1.Type) {
marker3()
Builtin.beginUnpairedModifyAccess(address, scratch, ty1);
}

// CHECK: sil [noinline] @$S20preserve_exclusivity6endOptyyBpF : $@convention(thin) (Builtin.RawPointer) -> () {
// CHECK-NOT: end_unpaired_access
// CHECK: } // end sil function '$S20preserve_exclusivity6endOptyyBpF'

@inline(never)
public func endOpt(_ address: Builtin.RawPointer) {
marker4()
Builtin.endUnpairedAccess(address)
}

public func testOpt(_ k1: Builtin.RawPointer) {
beginOpt(k1, k1, Builtin.RawPointer.self)
endOpt(k1)
}