Skip to content

Commit 3da18b6

Browse files
committed
SIL: Serialize and deserialize has_symbol instructions.
1 parent ae32b8e commit 3da18b6

File tree

12 files changed

+99
-29
lines changed

12 files changed

+99
-29
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6029,9 +6029,6 @@ ERROR(availability_macro_in_inlinable, none,
60296029
"availability macro cannot be used in " FRAGILE_FUNC_KIND "0",
60306030
(unsigned))
60316031

6032-
ERROR(has_symbol_condition_in_inlinable, none,
6033-
"'#_hasSymbol' cannot be used in " FRAGILE_FUNC_KIND "0", (unsigned))
6034-
60356032
#undef FRAGILE_FUNC_KIND
60366033

60376034
NOTE(resilience_decl_declared_here_public,

include/swift/SIL/SILInstruction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4101,7 +4101,8 @@ class HasSymbolInst final : public LiteralInst {
41014101
SILType::getBuiltinIntegerType(1, Decl->getASTContext())),
41024102
Decl{Decl} {}
41034103

4104-
ValueDecl *getDecl() { return Decl; }
4104+
ValueDecl *getDecl() const { return Decl; }
4105+
void getReferencedFunctions(llvm::SmallVector<SILFunction *, 4> &fns) const;
41054106

41064107
ArrayRef<Operand> getAllOperands() const { return {}; }
41074108
MutableArrayRef<Operand> getAllOperands() { return {}; }

lib/SIL/IR/SILInstructions.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "swift/SIL/SILCloner.h"
2727
#include "swift/SIL/SILInstruction.h"
2828
#include "swift/SIL/SILModule.h"
29+
#include "swift/SIL/SILSymbolVisitor.h"
2930
#include "swift/SIL/SILVisitor.h"
3031
#include "llvm/ADT/APInt.h"
3132
#include "llvm/ADT/SmallString.h"
@@ -2993,3 +2994,13 @@ SILPhiArgument *SwitchEnumInst::createOptionalSomeResult() {
29932994
auto someBB = getCaseDestination(someDecl);
29942995
return createResult(someBB, getOperand()->getType().unwrapOptionalType());
29952996
}
2997+
2998+
void HasSymbolInst::getReferencedFunctions(
2999+
llvm::SmallVector<SILFunction *, 4> &fns) const {
3000+
auto &M = getModule();
3001+
enumerateFunctionsForHasSymbol(M, getDecl(), [&M, &fns](SILDeclRef declRef) {
3002+
SILFunction *fn = M.lookUpFunction(declRef);
3003+
assert(fn);
3004+
fns.push_back(fn);
3005+
});
3006+
}

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ class DeadFunctionAndGlobalElimination {
364364
ensureAlive(GA->getReferencedGlobal());
365365
} else if (auto *GV = dyn_cast<GlobalValueInst>(&I)) {
366366
ensureAlive(GV->getReferencedGlobal());
367+
} else if (auto *HSI = dyn_cast<HasSymbolInst>(&I)) {
368+
SmallVector<SILFunction *, 4> fns;
369+
HSI->getReferencedFunctions(fns);
370+
for (auto fn : fns) {
371+
ensureAlive(fn);
372+
}
367373
}
368374
}
369375
}

lib/Sema/MiscDiagnostics.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4515,21 +4515,6 @@ static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
45154515
return true;
45164516
}
45174517

4518-
auto fragileKind = DC->getFragileFunctionKind();
4519-
if (fragileKind.kind != FragileFunctionKind::None) {
4520-
// #_hasSymbol cannot be used in inlinable code because of limitations of
4521-
// the current implementation strategy. It relies on recording the
4522-
// referenced ValueDecl, mangling a helper function name using that
4523-
// ValueDecl, and then passing the responsibility of generating the
4524-
// definition for that helper function to IRGen. In order to lift this
4525-
// restriction, we will need teach SIL to encode the ValueDecl, or take
4526-
// another approach entirely.
4527-
ctx.Diags.diagnose(info->getStartLoc(),
4528-
diag::has_symbol_condition_in_inlinable,
4529-
fragileKind.getSelector());
4530-
return true;
4531-
}
4532-
45334518
auto decl = info->getReferencedDecl().getDecl();
45344519
if (!decl) {
45354520
// Diagnose because we weren't able to interpret the expression as one
@@ -4538,7 +4523,8 @@ static bool diagnoseHasSymbolCondition(PoundHasSymbolInfo *info,
45384523
return true;
45394524
}
45404525

4541-
if (!decl->isWeakImported(DC->getParentModule())) {
4526+
if (DC->getFragileFunctionKind().kind == FragileFunctionKind::None &&
4527+
!decl->isWeakImported(DC->getParentModule())) {
45424528
// `if #_hasSymbol(someStronglyLinkedSymbol)` is functionally a no-op
45434529
// and may indicate the developer has mis-identified the declaration
45444530
// they want to check (or forgot to import the module weakly).

lib/Serialization/DeserializeSIL.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,10 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
12801280
Attr, Attr2);
12811281
RawOpCode = (unsigned)SILInstructionKind::IncrementProfilerCounterInst;
12821282
break;
1283+
case SIL_INST_HAS_SYMBOL:
1284+
SILInstHasSymbolLayout::readRecord(scratch, ValID, ListOfValues);
1285+
RawOpCode = (unsigned)SILInstructionKind::HasSymbolInst;
1286+
break;
12831287
}
12841288

12851289
// FIXME: validate
@@ -2992,7 +2996,13 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn,
29922996
break;
29932997
}
29942998
case SILInstructionKind::HasSymbolInst: {
2995-
llvm_unreachable("unimplemented"); // FIXME: implement deserialization
2999+
ValueDecl *decl = cast<ValueDecl>(MF->getDecl(ValID));
3000+
ResultInst = Builder.createHasSymbol(Loc, decl);
3001+
// Deserialize the functions that are implicitly referenced by the
3002+
// instruction.
3003+
for (auto fnID : ListOfValues) {
3004+
(void)getFuncForReference(MF->getIdentifierText(fnID));
3005+
}
29963006
break;
29973007
}
29983008
}

lib/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 721; // has_symbol SIL instruction
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 722; // has_symbol SIL serialization
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///

lib/Serialization/SILFormat.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ namespace sil_block {
158158
SIL_INST_LINEAR_FUNCTION_EXTRACT,
159159
SIL_INST_INCREMENT_PROFILER_COUNTER,
160160
SIL_MOVEONLY_DEINIT,
161+
SIL_INST_HAS_SYMBOL,
161162
};
162163

163164
using SILInstNoOperandLayout = BCRecordLayout<
@@ -529,6 +530,12 @@ namespace sil_block {
529530
BCVBR<8>, // counter index
530531
BCVBR<8> // num counters
531532
>;
533+
534+
using SILInstHasSymbolLayout = BCRecordLayout<
535+
SIL_INST_HAS_SYMBOL,
536+
ValueIDField, // decl
537+
BCArray<IdentifierIDField> // referenced functions
538+
>;
532539
}
533540

534541
} // end namespace serialization

lib/Serialization/SerializeSIL.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2490,7 +2490,20 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
24902490
break;
24912491
}
24922492
case SILInstructionKind::HasSymbolInst: {
2493-
llvm_unreachable("unimplemented"); // FIXME: implement serialization
2493+
auto *hsi = cast<HasSymbolInst>(&SI);
2494+
auto *decl = hsi->getDecl();
2495+
// Although the instruction doesn't have them as members, we need to
2496+
// ensure that any SILFunctions that are technically referenced by the
2497+
// instruction get serialized.
2498+
SmallVector<SILFunction *, 4> fns;
2499+
hsi->getReferencedFunctions(fns);
2500+
SmallVector<IdentifierID, 4> functionRefs;
2501+
for (auto fn : fns) {
2502+
functionRefs.push_back(addSILFunctionRef(fn));
2503+
}
2504+
SILInstHasSymbolLayout::emitRecord(
2505+
Out, ScratchRecord, SILAbbrCodes[SILInstHasSymbolLayout::Code],
2506+
S.addDeclRef(decl), functionRefs);
24942507
break;
24952508
}
24962509
}
@@ -2931,6 +2944,7 @@ void SILSerializer::writeSILBlock(const SILModule *SILMod) {
29312944
registerSILAbbr<SILInstDifferentiableFunctionExtractLayout>();
29322945
registerSILAbbr<SILInstLinearFunctionExtractLayout>();
29332946
registerSILAbbr<SILInstIncrementProfilerCounterLayout>();
2947+
registerSILAbbr<SILInstHasSymbolLayout>();
29342948

29352949
registerSILAbbr<VTableLayout>();
29362950
registerSILAbbr<VTableEntryLayout>();

test/Interpreter/has_symbol.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@
3333
// to remote executors.
3434
// UNSUPPORTED: remote_run || device_run
3535

36-
// rdar://102159307 - #_hasSymbol needs to be implemented with a SILInstruction
37-
// REQUIRES: swift_test_mode_optimize_none
38-
3936
@_weakLinked import helper
4037

4138
// HAS-ANSWER: 42

test/SILOptimizer/has_symbol.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -O -emit-module -emit-module-path %t/Library.swiftmodule -parse-as-library %t/Library.swift -enable-library-evolution
4+
// RUN: %target-swift-frontend -O -emit-sil %t/Client.swift -I %t -module-name test | %FileCheck %s
5+
6+
// REQUIRES: VENDOR=apple
7+
8+
//--- Library.swift
9+
10+
@usableFromInline func usableFromInlineFunc() {}
11+
12+
public struct S {
13+
@usableFromInline var member: Int = 0
14+
public init() {}
15+
}
16+
17+
@_alwaysEmitIntoClient
18+
public func serializedHasSymbolFunc(_ s: S) -> Bool {
19+
guard #_hasSymbol(usableFromInlineFunc) else { return false }
20+
guard #_hasSymbol(s.member) else { return false }
21+
return true
22+
}
23+
24+
//--- Client.swift
25+
26+
@_weakLinked import Library
27+
28+
public func foo() -> Bool {
29+
// CHECK: {{%[0-9]+}} = has_symbol #usableFromInlineFunc
30+
// CHECK: {{%[0-9]+}} = has_symbol #S.member
31+
return serializedHasSymbolFunc(S())
32+
}
33+
34+
// Verify that the functions referenced by the deserialized `has_symbol`
35+
// instructions have also been deserialized and remain after dead function
36+
// elimination.
37+
38+
// CHECK: sil @$s7Library20usableFromInlineFuncyyF : $@convention(thin) () -> ()
39+
// CHECK: sil @$s7Library1SV6memberSivg : $@convention(method) (@in_guaranteed S) -> Int
40+
// CHECK: sil @$s7Library1SV6memberSivs : $@convention(method) (Int, @inout S) -> ()
41+
// CHECK: sil @$s7Library1SV6memberSivM : $@yield_once @convention(method) (@inout S) -> @yields @inout Int

test/Sema/has_symbol.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,15 @@ func doIt(_ closure: () -> ()) {
121121

122122
@inlinable
123123
func testInlinable() {
124-
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@inlinable' function}}
124+
if #_hasSymbol(noArgFunc) {}
125125
doIt {
126-
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@inlinable' function}}
126+
if #_hasSymbol(noArgFunc) {}
127127
}
128128
}
129129

130130
@_alwaysEmitIntoClient
131131
func testAEIC() {
132-
if #_hasSymbol(noArgFunc) {} // expected-error {{'#_hasSymbol' cannot be used in an '@_alwaysEmitIntoClient' function}}
132+
if #_hasSymbol(noArgFunc) {}
133133
}
134134

135135
func testClosure() {

0 commit comments

Comments
 (0)