Skip to content

Commit 62ae2bf

Browse files
author
David Ungar
authored
Merge pull request swiftlang#28164 from davidungar/WIP-custom-diff
[Incremental compilation] Source-range-based dependencies
2 parents f5665df + 6305f1f commit 62ae2bf

File tree

119 files changed

+4016
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+4016
-344
lines changed

include/swift/AST/DiagnosticsDriver.def

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ WARNING(incremental_requires_build_record_entry,none,
107107
"ignoring -incremental; output file map has no master dependencies "
108108
"entry (\"%0\" under \"\")", (StringRef))
109109

110+
WARNING(unable_to_open_incremental_comparison_log,none,
111+
"unable to open incremental comparison log file '%0'", (StringRef))
112+
110113
ERROR(error_os_minimum_deployment,none,
111114
"Swift requires a minimum deployment target of %0", (StringRef))
112115
ERROR(error_sdk_too_old,none,
@@ -163,10 +166,31 @@ WARNING(warn_opt_remark_disabled, none,
163166
WARNING(warn_ignoring_batch_mode,none,
164167
"ignoring '-enable-batch-mode' because '%0' was also specified", (StringRef))
165168

169+
WARNING(warn_ignoring_source_range_dependencies,none,
170+
"ignoring '-enable-source-range-dependencies' because '%0' was also specified", (StringRef))
171+
172+
WARNING(warn_bad_swift_ranges_header,none,
173+
"ignoring '-enable-source-range-dependencies' because of bad header in '%0'", (StringRef))
174+
175+
WARNING(warn_bad_swift_ranges_format,none,
176+
"ignoring '-enable-source-range-dependencies' because of bad format '%1' in '%0'", (StringRef, StringRef))
177+
166178
WARNING(warn_use_filelists_deprecated, none,
167179
"the option '-driver-use-filelists' is deprecated; use "
168180
"'-driver-filelist-threshold=0' instead", ())
169181

182+
WARNING(warn_unable_to_load_swift_ranges, none,
183+
"unable to load swift ranges file \"%0\", %1",
184+
(StringRef, StringRef))
185+
186+
WARNING(warn_unable_to_load_compiled_swift, none,
187+
"unable to load previously compiled swift file \"%0\", %1",
188+
(StringRef, StringRef))
189+
190+
WARNING(warn_unable_to_load_primary, none,
191+
"unable to load primary swift file \"%0\", %1",
192+
(StringRef, StringRef))
193+
170194
ERROR(cannot_find_migration_script, none,
171195
"missing migration script from path '%0'", (StringRef))
172196

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ ERROR(error_mode_cannot_emit_dependencies,none,
120120
"this mode does not support emitting dependency files", ())
121121
ERROR(error_mode_cannot_emit_reference_dependencies,none,
122122
"this mode does not support emitting reference dependency files", ())
123+
ERROR(error_mode_cannot_emit_swift_ranges,none,
124+
"this mode does not support emitting unparsed ranges files", ())
125+
ERROR(error_mode_cannot_emit_compiled_source,none,
126+
"this mode does not support emitting compiled source files", ())
123127
ERROR(error_mode_cannot_emit_header,none,
124128
"this mode does not support emitting Objective-C headers", ())
125129
ERROR(error_mode_cannot_emit_loaded_module_trace,none,
@@ -138,6 +142,10 @@ ERROR(cannot_emit_ir_skipping_function_bodies,none,
138142

139143
WARNING(emit_reference_dependencies_without_primary_file,none,
140144
"ignoring -emit-reference-dependencies (requires -primary-file)", ())
145+
WARNING(emit_swift_ranges_without_primary_file,none,
146+
"ignoring -emit-swift-ranges (requires -primary-file)", ())
147+
WARNING(emit_compiled_source_without_primary_file,none,
148+
"ignoring -emit-compiled-source (requires -primary-file)", ())
141149

142150
ERROR(error_bad_module_name,none,
143151
"module name \"%0\" is not a valid identifier"
@@ -283,6 +291,14 @@ ERROR(error_invalid_debug_prefix_map, none,
283291
"invalid argument '%0' to -debug-prefix-map; it must be of the form "
284292
"'original=remapped'", (StringRef))
285293

294+
295+
ERROR(error_unable_to_write_swift_ranges_file, none,
296+
"unable to write unparsed ranges file '$0': %1", (StringRef, StringRef))
297+
298+
ERROR(error_unable_to_write_compiled_source_file, none,
299+
"unable to write compiled source file: '$0': %1", (StringRef, StringRef))
300+
301+
286302
ERROR(invalid_vfs_overlay_file,none,
287303
"invalid virtual overlay file '%0'", (StringRef))
288304

include/swift/AST/IncrementalRanges.h

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
//===------------- IncrementalRanges.h -----------------------------*- C++
2+
//-*-===//
3+
//
4+
// This source file is part of the Swift.org open source project
5+
//
6+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
7+
// Licensed under Apache License v2.0 with Runtime Library Exception
8+
//
9+
// See https://swift.org/LICENSE.txt for license information
10+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef SWIFT_AST_INCREMENTALRANGES_H
15+
#define SWIFT_AST_INCREMENTALRANGES_H
16+
17+
// These are the declarations for managing serializable source locations so that
18+
// the frontend and the driver can implement incremental compilation based on
19+
// source ranges.
20+
21+
#include "swift/Basic/LLVM.h"
22+
#include "swift/Basic/NullablePtr.h"
23+
#include "swift/Basic/SourceLoc.h"
24+
#include "swift/Basic/StringExtras.h"
25+
#include "llvm/Support/YAMLTraits.h"
26+
#include <vector>
27+
28+
namespace swift {
29+
class PersistentParserState;
30+
class SourceManager;
31+
class DiagnosticEngine;
32+
class SourceFile;
33+
} // namespace swift
34+
35+
//==============================================================================
36+
// MARK: Range types
37+
//==============================================================================
38+
39+
namespace swift {
40+
namespace incremental_ranges {
41+
42+
struct SerializableSourceRange;
43+
44+
typedef std::vector<SerializableSourceRange> Ranges;
45+
typedef std::map<std::string, Ranges> RangesByFilename;
46+
} // namespace incremental_ranges
47+
} // namespace swift
48+
49+
//==============================================================================
50+
// MARK: SerializableSourceLocation
51+
//==============================================================================
52+
namespace swift {
53+
namespace incremental_ranges {
54+
55+
/// A source location that can be written from the frontend and read by the
56+
/// driver. 1-origin: lines and columns start at 1
57+
struct SerializableSourceLocation {
58+
uint64_t line = 0;
59+
uint64_t column = 0;
60+
61+
SerializableSourceLocation(const SourceLoc loc, const SourceManager &SM);
62+
SerializableSourceLocation(uint64_t line, uint64_t column)
63+
: line(line), column(column) {}
64+
SerializableSourceLocation() = default;
65+
static const SerializableSourceLocation endOfAnyFile;
66+
67+
bool operator< (const SerializableSourceLocation &x) const {
68+
return line < x.line ? true
69+
: line > x.line ? false
70+
: column < x.column;
71+
}
72+
bool operator==(const SerializableSourceLocation &x) const {
73+
return line == x.line && column == x.column;
74+
}
75+
bool operator<=(const SerializableSourceLocation &x) const {
76+
return *this < x || *this == x;
77+
}
78+
void print(raw_ostream &out) const;
79+
void dump() const;
80+
};
81+
82+
} // namespace incremental_ranges
83+
} // namespace swift
84+
85+
template <>
86+
struct llvm::yaml::MappingTraits<
87+
swift::incremental_ranges::SerializableSourceLocation> {
88+
static const bool flow = true;
89+
static void
90+
mapping(llvm::yaml::IO &io,
91+
swift::incremental_ranges::SerializableSourceLocation &loc) {
92+
io.mapRequired("line", loc.line), io.mapRequired("column", loc.column);
93+
}
94+
};
95+
//==============================================================================
96+
// MARK: SerializableSourceRange
97+
//==============================================================================
98+
99+
namespace swift {
100+
namespace incremental_ranges {
101+
/// A range in the source, that can be written by the frontend and read by the
102+
/// driver. Half-open, to facilitate representing empty ranges. In other words,
103+
/// an empty region will have start == end
104+
struct SerializableSourceRange {
105+
SerializableSourceLocation start, end;
106+
107+
SerializableSourceRange(const CharSourceRange r, const SourceManager &SM);
108+
SerializableSourceRange(SerializableSourceLocation start,
109+
SerializableSourceLocation end);
110+
SerializableSourceRange() = default;
111+
112+
static const SerializableSourceRange wholeFile;
113+
static Ranges RangesForWholeFile();
114+
115+
bool isEmpty() const { return start == end; }
116+
117+
bool overlaps(const SerializableSourceRange &x) const {
118+
return start < x.end && x.start < end;
119+
}
120+
bool operator==(const SerializableSourceRange &x) const {
121+
return start == x.start && end == x.end;
122+
}
123+
bool isImproperSubsetOf(const SerializableSourceRange &) const;
124+
bool properlyPreceeds(const SerializableSourceRange &) const;
125+
static bool isProperlySorted(ArrayRef<SerializableSourceRange>);
126+
127+
bool
128+
isImproperSubsetOfAny(ArrayRef<SerializableSourceRange> supersetRanges) const;
129+
bool isImproperSubsetOfAnySlowlyAndSimply(
130+
ArrayRef<SerializableSourceRange> supersetRanges) const;
131+
132+
/// Optimized for fewer ranges in the subset
133+
/// Return first outlier found in subset not in superset
134+
static Optional<SerializableSourceRange>
135+
findOutlierIfAny(ArrayRef<SerializableSourceRange> subset,
136+
ArrayRef<SerializableSourceRange> superset);
137+
138+
static Ranges findAllOutliers(ArrayRef<SerializableSourceRange> subset,
139+
ArrayRef<SerializableSourceRange> superset);
140+
141+
std::string printString() const;
142+
void print(raw_ostream &out) const;
143+
void dump() const;
144+
};
145+
146+
} // namespace incremental_ranges
147+
} // namespace swift
148+
149+
150+
template <>
151+
struct llvm::yaml::MappingTraits<
152+
swift::incremental_ranges::SerializableSourceRange> {
153+
static const bool flow = true;
154+
static void mapping(llvm::yaml::IO &io,
155+
swift::incremental_ranges::SerializableSourceRange &sr) {
156+
io.mapRequired("start", sr.start), io.mapRequired("end", sr.end);
157+
}
158+
};
159+
160+
//==============================================================================
161+
// MARK: SwiftRangesFileContents
162+
//==============================================================================
163+
164+
namespace swift {
165+
namespace incremental_ranges {
166+
167+
/// The complete contents of the file written by the frontend and read by the
168+
/// driver containing source range information for one primary input file.
169+
struct SwiftRangesFileContents {
170+
/// For each non-primary, the unparsed ranges in it.
171+
/// At present these represent the bodies of types defined in the nonprimary
172+
/// that are not used in the primary.
173+
RangesByFilename unparsedRangesByNonPrimary;
174+
Ranges noninlinableFunctionBodies;
175+
176+
SwiftRangesFileContents() : SwiftRangesFileContents({}, {}) {}
177+
178+
SwiftRangesFileContents(RangesByFilename &&unparsedRangesByNonPrimary,
179+
Ranges &&noninlinableFunctionBodies)
180+
: unparsedRangesByNonPrimary(std::move(unparsedRangesByNonPrimary)),
181+
noninlinableFunctionBodies(std::move(noninlinableFunctionBodies)) {}
182+
183+
/// Return None for error.
184+
static Optional<SwiftRangesFileContents>
185+
load(const StringRef primaryPath, const llvm::MemoryBuffer &swiftRangesBuffer,
186+
const bool showIncrementalBuildDecisions, DiagnosticEngine &diags);
187+
188+
void dump(StringRef primaryFilename) const;
189+
190+
static constexpr const char *header = "### Swift source ranges file v0 ###\n";
191+
};
192+
} // namespace incremental_ranges
193+
} // namespace swift
194+
195+
template <>
196+
struct llvm::yaml::MappingTraits<
197+
swift::incremental_ranges::SwiftRangesFileContents> {
198+
static void
199+
mapping(llvm::yaml::IO &io,
200+
swift::incremental_ranges::SwiftRangesFileContents &srfc) {
201+
io.mapRequired("unparsedRangesByNonPrimary",
202+
srfc.unparsedRangesByNonPrimary);
203+
io.mapRequired("noninlinableFunctionBodies",
204+
srfc.noninlinableFunctionBodies);
205+
}
206+
};
207+
208+
LLVM_YAML_IS_SEQUENCE_VECTOR(swift::incremental_ranges::SerializableSourceRange)
209+
LLVM_YAML_IS_STRING_MAP(swift::incremental_ranges::Ranges)
210+
LLVM_YAML_IS_STRING_MAP(swift::incremental_ranges::RangesByFilename)
211+
212+
//==============================================================================
213+
// MARK: SwiftRangesEmitter
214+
//==============================================================================
215+
namespace swift {
216+
namespace incremental_ranges {
217+
/// Gathers up the information from the frontend, processes it, and writes it.
218+
class SwiftRangesEmitter {
219+
const StringRef outputPath;
220+
SourceFile *const primaryFile;
221+
const PersistentParserState &persistentState;
222+
const SourceManager &sourceMgr;
223+
DiagnosticEngine &diags;
224+
225+
public:
226+
SwiftRangesEmitter(StringRef outputPath, SourceFile *primaryFile,
227+
const PersistentParserState &persistentState,
228+
const SourceManager &sourceMgr, DiagnosticEngine &diags)
229+
: outputPath(outputPath), primaryFile(primaryFile),
230+
persistentState(persistentState), sourceMgr(sourceMgr), diags(diags) {}
231+
232+
/// True for error
233+
bool emit() const;
234+
235+
public:
236+
void emitRanges(llvm::raw_ostream &out) const;
237+
238+
private:
239+
RangesByFilename collectSerializedUnparsedRangesByNonPrimary() const;
240+
241+
Ranges collectSortedSerializedNoninlinableFunctionBodies() const;
242+
std::vector<CharSourceRange> collectNoninlinableFunctionBodies() const;
243+
244+
std::map<std::string, std::vector<CharSourceRange>>
245+
collectUnparsedRanges() const;
246+
std::vector<CharSourceRange>
247+
sortRanges(std::vector<CharSourceRange> ranges) const;
248+
249+
/// Assuming \p ranges is sorted, coalesce overlapping ranges in place and
250+
/// return end of the resultant vector.
251+
std::vector<CharSourceRange>
252+
coalesceSortedRanges(std::vector<CharSourceRange>) const;
253+
254+
std::vector<SerializableSourceRange>
255+
serializeRanges(std::vector<CharSourceRange> ranges) const;
256+
257+
bool isImmediatelyBeforeOrOverlapping(CharSourceRange prev,
258+
CharSourceRange next) const;
259+
};
260+
} // namespace incremental_ranges
261+
} // namespace swift
262+
263+
//==============================================================================
264+
// MARK: CompiledSourceEmitter
265+
//==============================================================================
266+
namespace swift {
267+
namespace incremental_ranges {
268+
/// The class that writes out the unchanged source code in the primary input so
269+
/// that the driver can diff it later, after the user has changed the file.
270+
class CompiledSourceEmitter {
271+
const StringRef outputPath;
272+
const SourceFile *const primaryFile;
273+
const SourceManager &sourceMgr;
274+
DiagnosticEngine &diags;
275+
276+
public:
277+
CompiledSourceEmitter(StringRef outputPath, const SourceFile *primaryFile,
278+
const SourceManager &sourceMgr, DiagnosticEngine &diags)
279+
: outputPath(outputPath), primaryFile(primaryFile), sourceMgr(sourceMgr),
280+
diags(diags) {}
281+
282+
/// True for error
283+
bool emit();
284+
};
285+
286+
} // namespace incremental_ranges
287+
} // namespace swift
288+
289+
#endif // SWIFT_AST_INCREMENTALRANGES_H

include/swift/Basic/FileTypes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ TYPE("llvm-bc", LLVM_BC, "bc", "")
5959
TYPE("diagnostics", SerializedDiagnostics, "dia", "")
6060
TYPE("objc-header", ObjCHeader, "h", "")
6161
TYPE("swift-dependencies", SwiftDeps, "swiftdeps", "")
62+
TYPE("swift-ranges", SwiftRanges, "swiftranges", "")
63+
TYPE("compiled-source", CompiledSource, "compiledsource", "")
6264
TYPE("remap", Remapping, "remap", "")
6365
TYPE("imported-modules", ImportedModules, "importedmodules", "")
6466
TYPE("tbd", TBD, "tbd", "")

include/swift/Basic/FileTypes.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ static inline void forAllTypes(llvm::function_ref<void(file_types::ID)> fn) {
6363
fn(static_cast<ID>(i));
6464
}
6565

66+
/// Some files are produced by the frontend and read by the driver in order to
67+
/// support incremental compilation. Invoke the passed-in function for every
68+
/// such file type.
69+
static inline void
70+
forEachIncrementalOutputType(llvm::function_ref<void(file_types::ID)> fn) {
71+
static const std::vector<file_types::ID> incrementalOutputTypes = {
72+
file_types::TY_SwiftDeps, file_types::TY_SwiftRanges,
73+
file_types::TY_CompiledSource};
74+
for (auto type : incrementalOutputTypes)
75+
fn(type);
76+
}
77+
6678
} // end namespace file_types
6779
} // end namespace swift
6880

0 commit comments

Comments
 (0)