Skip to content

Commit e158bd0

Browse files
[CAS] Add test case for cache key computation
Add tool swift-cache-tool for caching related testing and inspection.
1 parent 8c1cff1 commit e158bd0

File tree

11 files changed

+364
-3
lines changed

11 files changed

+364
-3
lines changed

include/swift/Driver/Driver.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ class Driver {
170170
SwiftIndent, // swift-indent
171171
SymbolGraph, // swift-symbolgraph
172172
APIExtract, // swift-api-extract
173-
APIDigester // swift-api-digester
173+
APIDigester, // swift-api-digester
174+
CacheTool // swift-cache-tool
174175
};
175176

176177
class InputInfoMap;

include/swift/Option/Options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace options {
4242
SwiftAPIDigesterOption = (1 << 17),
4343
NewDriverOnlyOption = (1 << 18),
4444
ModuleInterfaceOptionIgnorable = (1 << 19),
45+
SwiftCacheToolOption = (1 << 20),
4546
};
4647

4748
enum ID {

include/swift/Option/Options.td

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ def SwiftSymbolGraphExtractOption : OptionFlag;
6969
// The option should be accepted by swift-api-digester.
7070
def SwiftAPIDigesterOption : OptionFlag;
7171

72+
// The option should be accepted by swift-cache-tool.
73+
def SwiftCacheToolOption : OptionFlag;
74+
7275
// The option only functions in the new driver.
7376
def NewDriverOnlyOption : OptionFlag;
7477

@@ -245,7 +248,7 @@ def visualc_tools_version : Separate<["-"], "visualc-tools-version">,
245248

246249
// Standard Options
247250
def _DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>,
248-
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>;
251+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, SwiftCacheToolOption]>;
249252

250253
def o : JoinedOrSeparate<["-"], "o">,
251254
Flags<[FrontendOption, AutolinkExtractOption, ModuleWrapOption,
@@ -1668,6 +1671,11 @@ def use_interface_for_module: Separate<["-", "--"], "use-interface-for-module">,
16681671
HelpText<"Prefer loading these modules via interface">,
16691672
MetaVarName<"<name>">;
16701673

1674+
def cache_tool_action: JoinedOrSeparate<["-"], "cache-tool-action">,
1675+
Flags<[NoDriverOption, SwiftCacheToolOption]>,
1676+
HelpText<"Swift Cache Tool Action Kind">,
1677+
MetaVarName<"<print-base-key|print-output-keys>">;
1678+
16711679
// ONLY SUPPORTED IN NEW DRIVER
16721680

16731681
// These flags only exist here so that the old driver doesn't fail with unknown
@@ -1811,7 +1819,7 @@ def gcc_toolchain: Separate<["-"], "gcc-toolchain">,
18111819
HelpText<"Specify a directory where the clang importer and clang linker can find headers and libraries">;
18121820

18131821
def cas_path: Separate<["-"], "cas-path">,
1814-
Flags<[FrontendOption, NewDriverOnlyOption]>,
1822+
Flags<[FrontendOption, NewDriverOnlyOption, SwiftCacheToolOption]>,
18151823
HelpText<"Path to CAS">, MetaVarName<"<path>">;
18161824

18171825
// END ONLY SUPPORTED IN NEW DRIVER

lib/Driver/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ void Driver::parseDriverKind(ArrayRef<const char *> Args) {
104104
.Case("swift-symbolgraph-extract", DriverKind::SymbolGraph)
105105
.Case("swift-api-extract", DriverKind::APIExtract)
106106
.Case("swift-api-digester", DriverKind::APIDigester)
107+
.Case("swift-cache-tool", DriverKind::CacheTool)
107108
.Default(None);
108109

109110
if (Kind.has_value())
@@ -3563,6 +3564,7 @@ void Driver::printHelp(bool ShowHidden) const {
35633564
case DriverKind::SymbolGraph:
35643565
case DriverKind::APIExtract:
35653566
case DriverKind::APIDigester:
3567+
case DriverKind::CacheTool:
35663568
ExcludedFlagsBitmask |= options::NoBatchOption;
35673569
break;
35683570
}

lib/DriverTool/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(driver_sources_and_options
33
autolink_extract_main.cpp
44
modulewrap_main.cpp
55
swift_api_digester_main.cpp
6+
swift_cache_tool_main.cpp
67
swift_indent_main.cpp
78
swift_symbolgraph_extract_main.cpp
89
swift_api_extract_main.cpp)

lib/DriverTool/driver.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ extern int swift_api_digester_main(ArrayRef<const char *> Args,
8686
extern int swift_api_extract_main(ArrayRef<const char *> Args,
8787
const char *Argv0, void *MainAddr);
8888

89+
/// Run 'swift-cache-tool'
90+
extern int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
91+
void *MainAddr);
92+
8993
/// Determine if the given invocation should run as a "subcommand".
9094
///
9195
/// Examples of "subcommands" are 'swift build' or 'swift test', which are
@@ -299,6 +303,10 @@ static int run_driver(StringRef ExecName,
299303
return swift_api_digester_main(
300304
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
301305
(void *)(intptr_t)getExecutablePath);
306+
case Driver::DriverKind::CacheTool:
307+
return swift_cache_tool_main(
308+
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0],
309+
(void *)(intptr_t)getExecutablePath);
302310
default:
303311
break;
304312
}
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
//===--- swift_cache_tool_main.cpp - Swift caching tool for inspection ----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// Utility tool for inspecting and accessing swift cache.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
//
17+
#include "swift/AST/DiagnosticsFrontend.h"
18+
#include "swift/Basic/LLVM.h"
19+
#include "swift/Basic/LLVMInitialize.h"
20+
#include "swift/Basic/Version.h"
21+
#include "swift/Frontend/CompileJobCacheKey.h"
22+
#include "swift/Frontend/Frontend.h"
23+
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
24+
#include "swift/Option/Options.h"
25+
#include "swift/Parse/ParseVersion.h"
26+
#include "llvm/CAS/ActionCache.h"
27+
#include "llvm/CAS/BuiltinUnifiedCASDatabases.h"
28+
#include "llvm/CAS/ObjectStore.h"
29+
#include "llvm/Support/JSON.h"
30+
#include <memory>
31+
32+
using namespace swift;
33+
using namespace llvm::opt;
34+
using namespace llvm::cas;
35+
36+
namespace {
37+
38+
enum class SwiftCacheToolAction {
39+
Invalid,
40+
PrintBaseKey,
41+
PrintOutputKeys
42+
};
43+
44+
class SwiftCacheToolInvocation {
45+
private:
46+
CompilerInstance Instance;
47+
CompilerInvocation Invocation;
48+
PrintingDiagnosticConsumer PDC;
49+
std::string MainExecutablePath;
50+
std::string CASPath;
51+
std::vector<std::string> FrontendArgs;
52+
SwiftCacheToolAction ActionKind = SwiftCacheToolAction::Invalid;
53+
54+
public:
55+
SwiftCacheToolInvocation(const std::string &ExecPath)
56+
: MainExecutablePath(ExecPath) {
57+
Instance.addDiagnosticConsumer(&PDC);
58+
}
59+
60+
int parseArgs(ArrayRef<const char *> Args) {
61+
using namespace options;
62+
auto &Diags = Instance.getDiags();
63+
64+
std::unique_ptr<llvm::opt::OptTable> Table = createSwiftOptTable();
65+
unsigned MissingIndex;
66+
unsigned MissingCount;
67+
llvm::opt::InputArgList ParsedArgs = Table->ParseArgs(
68+
Args, MissingIndex, MissingCount, SwiftCacheToolOption);
69+
if (MissingCount) {
70+
Diags.diagnose(SourceLoc(), diag::error_missing_arg_value,
71+
ParsedArgs.getArgString(MissingIndex), MissingCount);
72+
return 1;
73+
}
74+
75+
if (ParsedArgs.getLastArg(OPT_help)) {
76+
std::string ExecutableName =
77+
llvm::sys::path::stem(MainExecutablePath).str();
78+
Table->printHelp(llvm::outs(), ExecutableName.c_str(),
79+
"Swift Cache Tool", options::SwiftCacheToolOption, 0,
80+
/*ShowAllAliases*/ false);
81+
return 0;
82+
}
83+
84+
CASPath =
85+
ParsedArgs.getLastArgValue(OPT_cas_path, getDefaultOnDiskCASPath());
86+
87+
FrontendArgs = ParsedArgs.getAllArgValues(OPT__DASH_DASH);
88+
if (auto *A = ParsedArgs.getLastArg(OPT_cache_tool_action))
89+
ActionKind =
90+
llvm::StringSwitch<SwiftCacheToolAction>(A->getValue())
91+
.Case("print-base-key", SwiftCacheToolAction::PrintBaseKey)
92+
.Case("print-output-keys", SwiftCacheToolAction::PrintOutputKeys)
93+
.Default(SwiftCacheToolAction::Invalid);
94+
95+
if (ActionKind == SwiftCacheToolAction::Invalid) {
96+
llvm::errs() << "Invalid option specified for -cache-tool-action: "
97+
<< "use print-base-key|print-output-keys\n";
98+
return 1;
99+
}
100+
101+
return 0;
102+
}
103+
104+
int run() {
105+
switch (ActionKind) {
106+
case SwiftCacheToolAction::PrintBaseKey:
107+
return printBaseKey();
108+
case SwiftCacheToolAction::PrintOutputKeys:
109+
return printOutputKeys();
110+
case SwiftCacheToolAction::Invalid:
111+
llvm::report_fatal_error("invalid action");
112+
}
113+
}
114+
115+
private:
116+
bool setupCompiler() {
117+
// Setup invocation.
118+
SmallString<128> workingDirectory;
119+
llvm::sys::fs::current_path(workingDirectory);
120+
121+
// Parse arguments.
122+
if (FrontendArgs.empty()) {
123+
llvm::errs() << "missing swift-frontend command-line after --\n";
124+
return true;
125+
}
126+
// drop swift-frontend executable path from command-line.
127+
if (StringRef(FrontendArgs[0]).endswith("swift-frontend"))
128+
FrontendArgs.erase(FrontendArgs.begin());
129+
130+
SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 4>
131+
configurationFileBuffers;
132+
std::vector<const char*> Args;
133+
for (auto &A: FrontendArgs)
134+
Args.emplace_back(A.c_str());
135+
136+
// Make sure CASPath is the same between invocation and cache-tool by
137+
// appending the cas-path since the option doesn't affect cache key.
138+
Args.emplace_back("-cas-path");
139+
Args.emplace_back(CASPath.c_str());
140+
141+
if (Invocation.parseArgs(Args, Instance.getDiags(),
142+
&configurationFileBuffers, workingDirectory,
143+
MainExecutablePath))
144+
return true;
145+
146+
if (!Invocation.getFrontendOptions().EnableCAS) {
147+
llvm::errs() << "Requested command-line arguments do not enable CAS\n";
148+
return true;
149+
}
150+
151+
// Setup instance.
152+
std::string InstanceSetupError;
153+
if (Instance.setup(Invocation, InstanceSetupError, Args)) {
154+
llvm::errs() << "swift-frontend invocation setup error: "
155+
<< InstanceSetupError << "\n";
156+
return true;
157+
}
158+
159+
return false;
160+
}
161+
162+
Optional<ObjectRef> getBaseKey() {
163+
auto BaseKey = Instance.getCompilerBaseKey();
164+
if (!BaseKey) {
165+
Instance.getDiags().diagnose(SourceLoc(), diag::error_cas,
166+
"Base Key doesn't exist");
167+
return None;
168+
}
169+
170+
return *BaseKey;
171+
}
172+
173+
int printBaseKey() {
174+
if (setupCompiler())
175+
return 1;
176+
177+
auto &CAS = Instance.getObjectStore();
178+
auto BaseKey = getBaseKey();
179+
if (!BaseKey)
180+
return 1;
181+
182+
if (ActionKind == SwiftCacheToolAction::PrintBaseKey)
183+
llvm::outs() << CAS.getID(*BaseKey).toString() << "\n";
184+
185+
return 0;
186+
}
187+
188+
int printOutputKeys();
189+
};
190+
191+
} // end anonymous namespace
192+
193+
int SwiftCacheToolInvocation::printOutputKeys() {
194+
if (setupCompiler())
195+
return 1;
196+
197+
auto &CAS = Instance.getObjectStore();
198+
auto BaseKey = getBaseKey();
199+
if (!BaseKey)
200+
return 1;
201+
202+
struct OutputEntry {
203+
std::string InputPath;
204+
std::string OutputPath;
205+
std::string OutputKind;
206+
std::string CacheKey;
207+
};
208+
std::vector<OutputEntry> OutputKeys;
209+
bool hasError = false;
210+
auto addOutputKey = [&](StringRef InputPath, file_types::ID OutputKind,
211+
StringRef OutputPath) {
212+
auto OutputKey =
213+
createCompileJobCacheKeyForOutput(CAS, *BaseKey, InputPath, OutputKind);
214+
if (!OutputKey) {
215+
llvm::errs() << "cannot create cache key for " << OutputPath << ": "
216+
<< toString(OutputKey.takeError()) << "\n";
217+
hasError = true;
218+
}
219+
OutputKeys.emplace_back(
220+
OutputEntry{InputPath.str(), OutputPath.str(),
221+
file_types::getTypeName(OutputKind).str(),
222+
CAS.getID(*OutputKey).toString()});
223+
};
224+
auto addFromInputFile = [&](const InputFile &Input) {
225+
auto InputPath = Input.getFileName();
226+
if (!Input.outputFilename().empty())
227+
addOutputKey(
228+
InputPath,
229+
Invocation.getFrontendOptions().InputsAndOutputs.getOutputType(),
230+
Input.outputFilename());
231+
Input.getPrimarySpecificPaths()
232+
.SupplementaryOutputs.forEachSetOutputAndType(
233+
[&](const std::string &File, file_types::ID ID) {
234+
// Dont print serialized diagnostics.
235+
if (ID == file_types::ID::TY_SerializedDiagnostics)
236+
return;
237+
238+
addOutputKey(InputPath, ID, File);
239+
});
240+
};
241+
llvm::for_each(
242+
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs(),
243+
addFromInputFile);
244+
245+
if (hasError)
246+
return 1;
247+
248+
llvm::json::OStream Out(llvm::outs(), /*IndentSize=*/4);
249+
Out.array([&] {
250+
for (const auto &E : OutputKeys) {
251+
Out.object([&] {
252+
Out.attribute("OutputPath", E.OutputPath);
253+
Out.attribute("OutputKind", E.OutputKind);
254+
Out.attribute("Input", E.InputPath);
255+
Out.attribute("CacheKey", E.CacheKey);
256+
});
257+
}
258+
});
259+
260+
return 0;
261+
}
262+
263+
int swift_cache_tool_main(ArrayRef<const char *> Args, const char *Argv0,
264+
void *MainAddr) {
265+
INITIALIZE_LLVM();
266+
267+
SwiftCacheToolInvocation Invocation(
268+
llvm::sys::fs::getMainExecutable(Argv0, MainAddr));
269+
270+
if (Invocation.parseArgs(Args) != 0)
271+
return EXIT_FAILURE;
272+
273+
if (Invocation.run() != 0)
274+
return EXIT_FAILURE;
275+
276+
return EXIT_SUCCESS;
277+
}

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,12 @@ bool ArgsToFrontendOptionsConverter::
675675
Opts.InputsAndOutputs.setMainAndSupplementaryOutputs(mainOutputs,
676676
supplementaryOutputs,
677677
mainOutputForIndexUnits);
678+
// set output type.
679+
const file_types::ID outputType =
680+
FrontendOptions::formatForPrincipalOutputFileForAction(
681+
Opts.RequestedAction);
682+
Opts.InputsAndOutputs.setOutputType(outputType);
683+
678684
return false;
679685
}
680686

0 commit comments

Comments
 (0)