Skip to content

Commit eb0eeb8

Browse files
[Caching] Add swift-scan-test to test libSwiftScan APIs
Add a new test tool, that is a very simple driver to call into libSwiftScan APIs. This enables testing libSwiftScan interfaces directly, without relying on cross repo testing from swift-driver. This allows adding new tests for cache replay feature, that has quite some unique code path from how replay works in swift-frontend.
1 parent 9d8eac2 commit eb0eeb8

File tree

7 files changed

+314
-8
lines changed

7 files changed

+314
-8
lines changed

test/CAS/swift-scan-test.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %swift-scan-test -action compute_cache_key -cas-path %t/cas -input %s -- %target-swift-frontend -cache-compile-job -Rcache-compile-job %s \
4+
// RUN: -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies -module-name Test -o %t/test.o -cas-path %t/cas \
5+
// RUN: -allow-unstable-cache-key-for-testing > %t/key.casid
6+
7+
// RUN: not %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas 2>&1 | %FileCheck %s --check-prefix=CHECK-QUERY-NOT-FOUND
8+
9+
// RUN: %target-swift-frontend -cache-compile-job -Rcache-compile-job %s -emit-module -emit-module-path %t/Test.swiftmodule -c -emit-dependencies \
10+
// RUN: -module-name Test -o %t/test.o -cas-path %t/cas -allow-unstable-cache-key-for-testing
11+
12+
// RUN: %swift-scan-test -action cache_query -id @%t/key.casid -cas-path %t/cas | %FileCheck %s --check-prefix=CHECK-QUERY
13+
14+
// RUN: %swift-scan-test -action replay_result -cas-path %t/cas -id @%t/key.casid -- %target-swift-frontend -cache-compile-job -Rcache-compile-job %s \
15+
// RUN: -emit-module -emit-module-path %t/Test2.swiftmodule -c -emit-dependencies -module-name Test -o %t/test2.o -cas-path %t/cas \
16+
// RUN: -allow-unstable-cache-key-for-testing
17+
18+
// RUN: diff %t/Test.swiftmodule %t/Test2.swiftmodule
19+
// RUN: diff %t/test.o %t/test.o
20+
21+
// CHECK-QUERY-NOT-FOUND: cached output not found
22+
// CHECK-QUERY: Cached Compilation for key "llvmcas://{{.*}}" has 4 outputs: (object) (swiftmodule) (dependencies) (cached-diagnostics)
23+
24+
func testFunc() {}

test/lit.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ config.benchmark_o = inferSwiftBinary('Benchmark_O')
345345
config.benchmark_driver = inferSwiftBinary('Benchmark_Driver')
346346
config.wasm_ld = inferSwiftBinary('wasm-ld')
347347
config.swift_plugin_server = inferSwiftBinary('swift-plugin-server')
348+
config.swift_scan_test = inferSwiftBinary('swift-scan-test')
348349

349350
config.swift_utils = make_path(config.swift_src_root, 'utils')
350351
config.line_directive = make_path(config.swift_utils, 'line-directive')
@@ -636,6 +637,7 @@ config.substitutions.append( ('%llvm-strings', config.llvm_strings) )
636637
config.substitutions.append( ('%target-ptrauth', run_ptrauth ) )
637638
config.substitutions.append( ('%swift-path', config.swift) )
638639
config.substitutions.append( ('%swift-plugin-server', config.swift_plugin_server) )
640+
config.substitutions.append( ('%swift-scan-test', config.swift_scan_test) )
639641
config.substitutions.append( ('%validate-json', f"{config.python} -m json.tool") )
640642

641643
# This must come after all substitutions containing "%swift".

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_swift_tool_subdirectory(libSwiftScan)
2828
add_swift_tool_subdirectory(libStaticMirror)
2929
add_swift_tool_subdirectory(libMockPlugin)
3030
add_swift_tool_subdirectory(swift-plugin-server)
31+
add_swift_tool_subdirectory(swift-scan-test)
3132

3233
if(SWIFT_INCLUDE_TESTS OR SWIFT_INCLUDE_TEST_BINARIES)
3334
add_swift_tool_subdirectory(swift-ide-test)

tools/libSwiftScan/libSwiftScan.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,9 +1050,9 @@ loadCachedCompilation(llvm::cas::ObjectStore &CAS, llvm::cas::ObjectRef Ref) {
10501050
}
10511051

10521052
swiftscan_cache_result_t
1053-
swiftscan_cache_load_object(swiftscan_cas_t cas,
1054-
swiftscan_cached_compilation_t id,
1055-
swiftscan_string_ref_t *error) {
1053+
swiftscan_cache_load_cached_compilation(swiftscan_cas_t cas,
1054+
swiftscan_cached_compilation_t id,
1055+
swiftscan_string_ref_t *error) {
10561056
auto failure = [&](llvm::Error E) {
10571057
*error =
10581058
swift::c_string_utils::create_clone(toString(std::move(E)).c_str());
@@ -1077,7 +1077,7 @@ swiftscan_cache_load_object(swiftscan_cas_t cas,
10771077
return SWIFTSCAN_CACHE_RESULT_SUCCESS;
10781078
}
10791079

1080-
void swiftscan_cache_load_object_async(
1080+
void swiftscan_cache_load_cached_compilation_async(
10811081
swiftscan_cas_t cas, swiftscan_cached_compilation_t id, void *ctx,
10821082
void (*callback)(void *ctx, swiftscan_cache_result_t,
10831083
swiftscan_string_ref_t error),
@@ -1218,7 +1218,7 @@ bool swiftscan_cache_compilation_has_output_kind(
12181218
}
12191219

12201220
swiftscan_cache_replay_instance_t
1221-
swiftscan_cache_create_replay_instance(int argc, const char **argv,
1221+
swiftscan_cache_replay_instance_create(int argc, const char **argv,
12221222
swiftscan_string_ref_t *error) {
12231223
auto *Instance = new SwiftScanReplayInstance();
12241224

tools/libSwiftScan/libSwiftScan.exports

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,12 @@ swiftscan_cache_query
8989
swiftscan_cache_query_async
9090
swiftscan_cache_make_global_async
9191
swiftscan_cached_compilation_dispose
92-
swiftscan_cache_load_object
93-
swiftscan_cache_load_object_async
92+
swiftscan_cache_load_cached_compilation
93+
swiftscan_cache_load_cached_compilation_async
9494
swiftscan_cache_compilation_is_loaded
9595
swiftscan_cache_get_num_cached_outputs
9696
swiftscan_cache_compilation_has_output_kind
97-
swiftscan_cache_create_replay_instance
97+
swiftscan_cache_replay_instance_create
9898
swiftscan_cache_replay_instance_dispose
9999
swiftscan_cache_action_cancel
100100
swiftscan_cache_cancellation_token_dispose

tools/swift-scan-test/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
add_swift_host_tool(swift-scan-test
2+
swift-scan-test.cpp
3+
LLVM_LINK_COMPONENTS support
4+
SWIFT_COMPONENT tools
5+
THINLTO_LD64_ADD_FLTO_CODEGEN_ONLY
6+
DOES_NOT_USE_SWIFT
7+
)
8+
9+
target_link_libraries(swift-scan-test
10+
PRIVATE
11+
swiftBasic
12+
libSwiftScan)
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
//===--- swift-scan-test.cpp - Test libSwiftScan Dylib --------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// A simple program to test libSwiftScan interfaces.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift-c/DependencyScan/DependencyScan.h"
18+
#include "swift/Basic/Defer.h"
19+
#include "swift/Basic/FileTypes.h"
20+
#include "llvm/Support/Allocator.h"
21+
#include "llvm/Support/CommandLine.h"
22+
#include "llvm/Support/StringSaver.h"
23+
24+
using namespace llvm;
25+
26+
namespace {
27+
enum Actions {
28+
compute_cache_key,
29+
cache_query,
30+
replay_result,
31+
};
32+
33+
llvm::cl::OptionCategory Category("swift-scan-test Options");
34+
llvm::cl::opt<std::string> CASPath("cas-path", llvm::cl::desc("<path>"),
35+
llvm::cl::cat(Category));
36+
llvm::cl::opt<std::string> CASID("id", llvm::cl::desc("<casid>"),
37+
llvm::cl::cat(Category));
38+
llvm::cl::opt<std::string> Input("input", llvm::cl::desc("<file>"),
39+
llvm::cl::cat(Category));
40+
llvm::cl::opt<Actions>
41+
Action("action", llvm::cl::desc("<action>"),
42+
llvm::cl::values(clEnumVal(compute_cache_key, "compute cache key"),
43+
clEnumVal(cache_query, "cache query"),
44+
clEnumVal(replay_result, "replay result")),
45+
llvm::cl::cat(Category));
46+
llvm::cl::list<std::string>
47+
SwiftCommands(llvm::cl::Positional, llvm::cl::desc("<swift-frontend args>"),
48+
llvm::cl::cat(Category));
49+
50+
} // namespace
51+
52+
StringRef toString(swiftscan_string_ref_t str) {
53+
return StringRef((const char *)str.data, str.length);
54+
}
55+
56+
int printError(swiftscan_string_ref_t err) {
57+
llvm::errs() << toString(err) << "\n";
58+
swiftscan_string_dispose(err);
59+
return EXIT_FAILURE;
60+
}
61+
62+
int action_compute_cache_key(swiftscan_cas_t cas, StringRef input,
63+
std::vector<const char *> &Args) {
64+
if (input.empty()) {
65+
llvm::errs() << "-input is not specified for compute_cache_key\n";
66+
return EXIT_FAILURE;
67+
}
68+
69+
swiftscan_string_ref_t err_msg;
70+
auto key = swiftscan_cache_compute_key(cas, Args.size(), Args.data(),
71+
input.str().c_str(), &err_msg);
72+
if (key.length == 0)
73+
return printError(err_msg);
74+
75+
llvm::outs() << toString(key) << "\n";
76+
swiftscan_string_dispose(key);
77+
78+
return EXIT_SUCCESS;
79+
}
80+
81+
static swift::file_types::ID
82+
getFileTypeFromScanOutputKind(swiftscan_output_kind_t kind) {
83+
switch (kind) {
84+
case SWIFTSCAN_OUTPUT_TYPE_OBJECT:
85+
return swift::file_types::ID::TY_Object;
86+
case SWIFTSCAN_OUTPUT_TYPE_SWIFTMODULE:
87+
return swift::file_types::ID::TY_SwiftModuleFile;
88+
case SWIFTSCAN_OUTPUT_TYPE_SWIFTINTERFACE:
89+
return swift::file_types::ID::TY_SwiftModuleInterfaceFile;
90+
case SWIFTSCAN_OUTPUT_TYPE_SWIFTPRIVATEINTERFACE:
91+
return swift::file_types::ID::TY_PrivateSwiftModuleInterfaceFile;
92+
case SWIFTSCAN_OUTPUT_TYPE_CLANG_MODULE:
93+
return swift::file_types::ID::TY_ClangModuleFile;
94+
case SWIFTSCAN_OUTPUT_TYPE_CLANG_PCH:
95+
return swift::file_types::ID::TY_PCH;
96+
case SWIFTSCAN_OUTPUT_TYPE_CLANG_HEADER:
97+
return swift::file_types::ID::TY_ClangHeader;
98+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_SOURCE_INFO:
99+
return swift::file_types::ID::TY_SwiftSourceInfoFile;
100+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_DOC:
101+
return swift::file_types::ID::TY_SwiftModuleDocFile;
102+
case SWIFTSCAN_OUTPUT_TYPE_DEPENDENCIES:
103+
return swift::file_types::ID::TY_Dependencies;
104+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_DEPS:
105+
return swift::file_types::ID::TY_SwiftDeps;
106+
case SWIFTSCAN_OUTPUT_TYPE_MODULE_TRACE:
107+
return swift::file_types::ID::TY_ModuleTrace;
108+
case SWIFTSCAN_OUTPUT_TYPE_TBD:
109+
return swift::file_types::ID::TY_TBD;
110+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_MODULE_SUMMARY:
111+
return swift::file_types::ID::TY_SwiftModuleSummaryFile;
112+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_ABI_DESCRIPTOR:
113+
return swift::file_types::ID::TY_SwiftABIDescriptor;
114+
case SWIFTSCAN_OUTPUT_TYPE_SWIFT_API_DESCRIPTOR:
115+
return swift::file_types::ID::TY_SwiftAPIDescriptor;
116+
case SWIFTSCAN_OUTPUT_TYPE_CONST_VALUE:
117+
return swift::file_types::ID::TY_ConstValues;
118+
case SWIFTSCAN_OUTPUT_TYPE_MODULE_SEMANTIC_INFO:
119+
return swift::file_types::ID::TY_ModuleSemanticInfo;
120+
case SWIFTSCAN_OUTPUT_TYPE_YAML_OPT_RECORD:
121+
return swift::file_types::ID::TY_YAMLOptRecord;
122+
case SWIFTSCAN_OUTPUT_TYPE_BITSTREAM_OPT_RECORD:
123+
return swift::file_types::ID::TY_BitstreamOptRecord;
124+
case SWIFTSCAN_OUTPUT_TYPE_CACHED_DIAGNOSTICS:
125+
return swift::file_types::ID::TY_CachedDiagnostics;
126+
}
127+
}
128+
129+
int print_cached_compilation(swiftscan_cached_compilation_t comp,
130+
const char *key) {
131+
swiftscan_string_ref_t err_msg;
132+
auto numOutput = swiftscan_cache_get_num_cached_outputs(comp, &err_msg);
133+
if (err_msg.length != 0) {
134+
printError(err_msg);
135+
return EXIT_FAILURE;
136+
}
137+
138+
llvm::outs() << "Cached Compilation for key \"" << key << "\" has "
139+
<< numOutput << " outputs: ";
140+
141+
for (unsigned enumValue = 0; enumValue <= SWIFTSCAN_OUTPUT_TYPE_LAST;
142+
++enumValue) {
143+
swiftscan_output_kind_t kind =
144+
static_cast<swiftscan_output_kind_t>(enumValue);
145+
bool hasOutput =
146+
swiftscan_cache_compilation_has_output_kind(comp, kind, &err_msg);
147+
if (err_msg.length != 0)
148+
return printError(err_msg);
149+
150+
if (hasOutput) {
151+
llvm::outs() << "("
152+
<< swift::file_types::getTypeName(
153+
getFileTypeFromScanOutputKind(kind))
154+
<< ") ";
155+
}
156+
}
157+
llvm::outs() << "\n";
158+
return EXIT_SUCCESS;
159+
}
160+
161+
int action_cache_query(swiftscan_cas_t cas, const char *key) {
162+
swiftscan_string_ref_t err_msg;
163+
auto comp = swiftscan_cache_query(cas, key, /*globally=*/false, &err_msg);
164+
if (err_msg.length != 0)
165+
return printError(err_msg);
166+
167+
if (!comp) {
168+
llvm::errs() << "cached output not found for \"" << key << "\n";
169+
return EXIT_FAILURE;
170+
}
171+
172+
SWIFT_DEFER { swiftscan_cached_compilation_dispose(comp); };
173+
auto result = swiftscan_cache_load_cached_compilation(cas, comp, &err_msg);
174+
if (result == SWIFTSCAN_CACHE_RESULT_NOT_FOUND) {
175+
llvm::errs() << "failed to load output from cache key \"" << key << "\"\n";
176+
return EXIT_FAILURE;
177+
}
178+
if (result == SWIFTSCAN_CACHE_RESULT_ERROR)
179+
return printError(err_msg);
180+
181+
assert(result == SWIFTSCAN_CACHE_RESULT_SUCCESS && "unexpected result");
182+
return print_cached_compilation(comp, key);
183+
}
184+
185+
int action_replay_result(swiftscan_cas_t cas, const char *key,
186+
std::vector<const char *> &Args) {
187+
swiftscan_string_ref_t err_msg;
188+
auto comp = swiftscan_cache_query(cas, key, /*globally=*/false, &err_msg);
189+
if (!comp)
190+
return printError(err_msg);
191+
192+
SWIFT_DEFER { swiftscan_cached_compilation_dispose(comp); };
193+
auto load = swiftscan_cache_load_cached_compilation(cas, comp, &err_msg);
194+
if (load == SWIFTSCAN_CACHE_RESULT_NOT_FOUND) {
195+
llvm::errs() << "failed to load output from cache key \"" << key << "\"\n";
196+
return EXIT_FAILURE;
197+
}
198+
if (load == SWIFTSCAN_CACHE_RESULT_ERROR)
199+
return printError(err_msg);
200+
201+
assert(load == SWIFTSCAN_CACHE_RESULT_SUCCESS && "unexpected result");
202+
203+
auto instance = swiftscan_cache_replay_instance_create(Args.size(),
204+
Args.data(), &err_msg);
205+
if (!instance)
206+
return printError(err_msg);
207+
SWIFT_DEFER { swiftscan_cache_replay_instance_dispose(instance); };
208+
209+
auto result =
210+
swiftscan_cache_replay_compilation(cas, instance, comp, &err_msg);
211+
if (result == SWIFTSCAN_CACHE_RESULT_NOT_FOUND) {
212+
llvm::errs() << "failed to load output from cache key \"" << key << "\"\n";
213+
return EXIT_FAILURE;
214+
}
215+
if (result == SWIFTSCAN_CACHE_RESULT_ERROR)
216+
return printError(err_msg);
217+
218+
assert(result == SWIFTSCAN_CACHE_RESULT_SUCCESS && "unexpected result");
219+
return EXIT_SUCCESS;
220+
}
221+
222+
std::vector<const char *> createArgs(ArrayRef<std::string> Cmd,
223+
StringSaver &Saver) {
224+
if (!Cmd.empty() && StringRef(Cmd.front()).endswith("swift-frontend"))
225+
Cmd = Cmd.drop_front();
226+
227+
std::vector<const char *> Args;
228+
for (auto A : Cmd) {
229+
StringRef Arg = Saver.save(A);
230+
Args.push_back(Arg.data());
231+
}
232+
233+
return Args;
234+
}
235+
236+
int main(int argc, char *argv[]) {
237+
llvm::cl::HideUnrelatedOptions(Category);
238+
llvm::cl::ParseCommandLineOptions(argc, argv,
239+
"Test libSwiftScan interfaces\n");
240+
241+
// Create CAS.
242+
auto option = swiftscan_cas_options_create();
243+
SWIFT_DEFER { swiftscan_cas_options_dispose(option); };
244+
swiftscan_cas_options_set_ondisk_path(option, CASPath.c_str());
245+
246+
swiftscan_string_ref_t err_msg;
247+
auto cas = swiftscan_cas_create_from_options(option, &err_msg);
248+
if (!cas)
249+
return printError(err_msg);
250+
SWIFT_DEFER { swiftscan_cas_dispose(cas); };
251+
252+
// Convert commands.
253+
llvm::BumpPtrAllocator Alloc;
254+
llvm::StringSaver Saver(Alloc);
255+
auto Args = createArgs(SwiftCommands, Saver);
256+
257+
switch (Action) {
258+
case compute_cache_key:
259+
return action_compute_cache_key(cas, Input, Args);
260+
case cache_query:
261+
return action_cache_query(cas, CASID.c_str());
262+
case replay_result:
263+
return action_replay_result(cas, CASID.c_str(), Args);
264+
}
265+
266+
return EXIT_SUCCESS;
267+
}

0 commit comments

Comments
 (0)