Merge pull request #12075 from apple/revert-12062-make-fewer-gsbs

Revert "Create fewer generic signature builders"
diff --git a/benchmark/single-source/AnyHashableWithAClass.swift b/benchmark/single-source/AnyHashableWithAClass.swift
index b46f635..e2b5a76 100644
--- a/benchmark/single-source/AnyHashableWithAClass.swift
+++ b/benchmark/single-source/AnyHashableWithAClass.swift
@@ -14,6 +14,20 @@
 // upcast the instance to the type that introduces the Hashable
 // conformance.
 
+import TestsUtils
+
+// 23% _swift_dynamicCast
+// 23% _swift_release_
+// 18% _swift_stdlib_makeAnyHashableUsingDefaultRepresentation
+// 11% _swift_stdlib_makeAnyHashableUpcastingToHashableBaseType
+// 16% _swift_retain_[n]
+//  5% swift_conformsToProtocol
+public var AnyHashableWithAClass = BenchmarkInfo(
+  name: "AnyHashableWithAClass",
+  runFunction: run_AnyHashableWithAClass,
+  tags: [.abstraction, .runtime, .cpubench]
+)
+
 class TestHashableBase : Hashable {
   var value: Int
   init(_ value: Int) {
diff --git a/benchmark/single-source/Exclusivity.swift b/benchmark/single-source/Exclusivity.swift
index 368953a..e75dca9 100644
--- a/benchmark/single-source/Exclusivity.swift
+++ b/benchmark/single-source/Exclusivity.swift
@@ -17,6 +17,36 @@
 
 import TestsUtils
 
+// At -Onone
+// 25% swift_beginAccess
+// 15% tlv_get_addr
+// 15% swift_endAccess
+public var ExclusivityGlobal = BenchmarkInfo(
+  name: "ExclusivityGlobal",
+  runFunction: run_accessGlobal,
+  tags: [.runtime, .cpubench]
+)
+// At -Onone
+// 23% swift_retain
+// 22% swift_release
+//  9% swift_beginAccess
+//  3% swift_endAccess
+public var ExclusivityInMatSet = BenchmarkInfo(
+  name: "ExclusivityInMatSet",
+  runFunction: run_accessInMatSet,
+  tags: [.runtime, .cpubench]
+)
+// At -Onone
+// 25% swift_release
+// 23% swift_retain
+// 16% swift_beginAccess
+//  8% swift_endAccess
+public var ExclusivityIndependent = BenchmarkInfo(
+  name: "ExclusivityIndependent",
+  runFunction: run_accessIndependent,
+  tags: [.runtime, .cpubench]
+)
+
 // Initially these benchmarks only measure access checks at -Onone. In
 // the future, access checks will also be emitted at -O.
 
diff --git a/benchmark/single-source/LinkedList.swift b/benchmark/single-source/LinkedList.swift
index 2bc7811..2cfbfa6 100644
--- a/benchmark/single-source/LinkedList.swift
+++ b/benchmark/single-source/LinkedList.swift
@@ -14,6 +14,14 @@
 // utils/benchmark, with modifications for performance measuring.
 import TestsUtils
 
+// 47% _swift_retain
+// 43% _swift_release
+public var LinkedList = BenchmarkInfo(
+  name: "LinkedList",
+  runFunction: run_LinkedList,
+  tags: [.runtime, .cpubench, .refcount]
+)
+
 final class Node {
   var next: Node?
   var data: Int
diff --git a/benchmark/single-source/PolymorphicCalls.swift b/benchmark/single-source/PolymorphicCalls.swift
index 1ecb15d..64aedae 100644
--- a/benchmark/single-source/PolymorphicCalls.swift
+++ b/benchmark/single-source/PolymorphicCalls.swift
@@ -22,6 +22,12 @@
 
 import TestsUtils
 
+public var PolymorphicCalls = BenchmarkInfo(
+  name: "PolymorphicCalls",
+  runFunction: run_PolymorphicCalls,
+  tags: [.abstraction, .cpubench]
+)
+
 public class A {
     let b: B
     init(b:B) {
diff --git a/benchmark/single-source/SevenBoom.swift b/benchmark/single-source/SevenBoom.swift
index 99f1fd7..be59afe 100644
--- a/benchmark/single-source/SevenBoom.swift
+++ b/benchmark/single-source/SevenBoom.swift
@@ -13,6 +13,21 @@
 import TestsUtils
 import Foundation
 
+// 15% _swift_allocObject (String.bridgeToObjectiveC)
+// 14% [NSError dealloc]
+// 14% objc_allocWithZone
+// 10% _swift_allocObject
+// 11% _swift_release_dealloc
+//  8% objc_release
+//  7% objc_msgSend
+//  5% _swift_release_
+//  2% _swift_retain_
+public var SevenBoom = BenchmarkInfo(
+  name: "SevenBoom",
+  runFunction: run_SevenBoom,
+  tags: [.runtime, .exceptions, .bridging, .cpubench]
+)
+
 @inline(never)
 func filter_seven(_ input : Int) throws {
   guard case 7 = input else {
diff --git a/benchmark/utils/TestsUtils.swift b/benchmark/utils/TestsUtils.swift
index dcd9c0a..fd9ab99 100644
--- a/benchmark/utils/TestsUtils.swift
+++ b/benchmark/utils/TestsUtils.swift
@@ -17,54 +17,54 @@
 #endif
 
 public enum BenchmarkCategories : CustomStringConvertible {
-// Validation "micro" benchmarks test a specific operation or critical path that
-// we know is important to measure.
-case validation
-// subsystems to validate and their subcategories.
-case api, Array, String, Dictionary, Codable, Set
-case sdk
-case runtime, refcount, metadata
-// Other general areas of compiled code validation.
-case abstraction, safetychecks, exceptions, bridging, concurrency
-
-// Algorithms are "micro" that test some well-known algorithm in isolation:
-// sorting, searching, hashing, fibonaci, crypto, etc.
-case algorithm
-
-// Miniapplications are contrived to mimic some subset of application behavior
-// in a way that can be easily measured. They are larger than micro-benchmarks,
-// combining multiple APIs, data structures, or algorithms. This includes small
-// standardized benchmarks, pieces of real applications that have been extracted
-// into a benchmark, important functionality like JSON parsing, etc.
-case miniapplication
-
-// Regression benchmarks is a catch-all for less important "micro"
-// benchmarks. This could be a random piece of code that was attached to a bug
-// report. We want to make sure the optimizer as a whole continues to handle
-// this case, but don't know how applicable it is to general Swift performance
-// relative to the other micro-benchmarks. In particular, these aren't weighted
-// as highly as "validation" benchmarks and likely won't be the subject of
-// future investigation unless they significantly regress.
-case regression
-
-// Most benchmarks are assumed to be "stable" and will be regularly tracked at
-// each commit. A handful may be marked unstable if continually tracking them is
-// counterproductive.
-case unstable
-
-// CPU benchmarks represent instrinsic Swift performance. They are useful for
-// measuring a fully baked Swift implementation across different platforms and
-// hardware. The benchmark should also be reasonably applicable to real Swift
-// code--it should exercise a known performance critical area. Typically these
-// will be drawn from the validation benchmarks once the language and standard
-// library implementation of the benchmark meets a reasonable efficiency
-// baseline. A benchmark should only be tagged "cpubench" after a full
-// performance investigation of the benchmark has been completed to determine
-// that it is a good representation of future Swift performance. Benchmarks
-// should not be tagged if they make use of an API that we plan on
-// reimplementing or call into code paths that have known opportunities for
-// significant optimization.
-case cpubench
+  // Validation "micro" benchmarks test a specific operation or critical path that
+  // we know is important to measure.
+  case validation
+  // subsystems to validate and their subcategories.
+  case api, Array, String, Dictionary, Codable, Set
+  case sdk
+  case runtime, refcount, metadata
+  // Other general areas of compiled code validation.
+  case abstraction, safetychecks, exceptions, bridging, concurrency
+   
+  // Algorithms are "micro" that test some well-known algorithm in isolation:
+  // sorting, searching, hashing, fibonaci, crypto, etc.
+  case algorithm
+   
+  // Miniapplications are contrived to mimic some subset of application behavior
+  // in a way that can be easily measured. They are larger than micro-benchmarks,
+  // combining multiple APIs, data structures, or algorithms. This includes small
+  // standardized benchmarks, pieces of real applications that have been extracted
+  // into a benchmark, important functionality like JSON parsing, etc.
+  case miniapplication
+   
+  // Regression benchmarks is a catch-all for less important "micro"
+  // benchmarks. This could be a random piece of code that was attached to a bug
+  // report. We want to make sure the optimizer as a whole continues to handle
+  // this case, but don't know how applicable it is to general Swift performance
+  // relative to the other micro-benchmarks. In particular, these aren't weighted
+  // as highly as "validation" benchmarks and likely won't be the subject of
+  // future investigation unless they significantly regress.
+  case regression
+   
+  // Most benchmarks are assumed to be "stable" and will be regularly tracked at
+  // each commit. A handful may be marked unstable if continually tracking them is
+  // counterproductive.
+  case unstable
+   
+  // CPU benchmarks represent instrinsic Swift performance. They are useful for
+  // measuring a fully baked Swift implementation across different platforms and
+  // hardware. The benchmark should also be reasonably applicable to real Swift
+  // code--it should exercise a known performance critical area. Typically these
+  // will be drawn from the validation benchmarks once the language and standard
+  // library implementation of the benchmark meets a reasonable efficiency
+  // baseline. A benchmark should only be tagged "cpubench" after a full
+  // performance investigation of the benchmark has been completed to determine
+  // that it is a good representation of future Swift performance. Benchmarks
+  // should not be tagged if they make use of an API that we plan on
+  // reimplementing or call into code paths that have known opportunities for
+  // significant optimization.
+  case cpubench
 
   public var description : String {
     switch self {
diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift
index c9bf9c2..88b7326 100644
--- a/benchmark/utils/main.swift
+++ b/benchmark/utils/main.swift
@@ -125,6 +125,21 @@
 import XorLoop
 
 @inline(__always)
+private func registerBenchmark(_ bench: BenchmarkInfo) {
+  registeredBenchmarks.append(bench)
+}
+
+registerBenchmark(AnyHashableWithAClass)
+registerBenchmark(ArraySetElement)
+registerBenchmark(ExclusivityGlobal)
+registerBenchmark(ExclusivityInMatSet)
+registerBenchmark(ExclusivityIndependent)
+registerBenchmark(LinkedList)
+registerBenchmark(ObjectAllocation)
+registerBenchmark(PolymorphicCalls)
+registerBenchmark(SevenBoom)
+
+@inline(__always)
 private func addTo(
   _ testSuite: inout [String : ((Int) -> (), [BenchmarkCategories])],
   _ name: String,
@@ -134,14 +149,6 @@
   testSuite[name] = (function, tags)
 }
 
-@inline(__always)
-private func registerBenchmark(_ bench: BenchmarkInfo) {
-  registeredBenchmarks.append(bench)
-}
-
-registerBenchmark(ArraySetElement)
-registerBenchmark(ObjectAllocation)
-
 // The main test suite: precommit tests
 addTo(&precommitTests, "AngryPhonebook", run_AngryPhonebook, [.validation, .api, .String])
 addTo(&precommitTests, "AnyHashableWithAClass", run_AnyHashableWithAClass, [.validation, .abstraction, .runtime])
diff --git a/docs/CompilerPerformance.md b/docs/CompilerPerformance.md
index d76259c..f12ddc2 100644
--- a/docs/CompilerPerformance.md
+++ b/docs/CompilerPerformance.md
@@ -780,7 +780,7 @@
 How the test-script determines the presence of a regression is up to you: a
 typical approach is to measure against a baseline (eg. using
 `utils/process-stats-dir.py --compare-to-csv-baseline`, if your regression range
-covers compilers that all support `--output-stats-dir`). Alternatively, just
+covers compilers that all support `-stats-output-dir`). Alternatively, just
 measure raw time or instruction counts. An example script that uses the
 `perf`-based `count_instructions` shell function (see the section on `perf`) to
 judge whether a revision contains a bug looks something like this:
diff --git a/include/swift/Basic/Statistic.h b/include/swift/Basic/Statistic.h
index ae1382a..3ee26e2 100644
--- a/include/swift/Basic/Statistic.h
+++ b/include/swift/Basic/Statistic.h
@@ -15,6 +15,7 @@
 
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Statistic.h"
+#include "swift/Basic/SourceLoc.h"
 #include "swift/Basic/Timer.h"
 
 #define SWIFT_FUNC_STAT                                                 \
@@ -53,100 +54,66 @@
 public:
   struct AlwaysOnDriverCounters
   {
-    size_t NumDriverJobsRun;
-    size_t NumDriverJobsSkipped;
-
-    size_t DriverDepCascadingTopLevel;
-    size_t DriverDepCascadingDynamic;
-    size_t DriverDepCascadingNominal;
-    size_t DriverDepCascadingMember;
-    size_t DriverDepCascadingExternal;
-
-    size_t DriverDepTopLevel;
-    size_t DriverDepDynamic;
-    size_t DriverDepNominal;
-    size_t DriverDepMember;
-    size_t DriverDepExternal;
-
-    size_t ChildrenMaxRSS;
+#define DRIVER_STATISTIC(ID) size_t ID;
+#include "Statistics.def"
+#undef DRIVER_STATISTIC
   };
 
   struct AlwaysOnFrontendCounters
   {
-    size_t NumSourceBuffers;
-    size_t NumSourceLines;
-    size_t NumSourceLinesPerSecond;
-    size_t NumLinkLibraries;
-    size_t NumLoadedModules;
-    size_t NumImportedExternalDefinitions;
-    size_t NumTotalClangImportedEntities;
-    size_t NumASTBytesAllocated;
-    size_t NumDependencies;
-    size_t NumReferencedTopLevelNames;
-    size_t NumReferencedDynamicNames;
-    size_t NumReferencedMemberNames;
-    size_t NumDecls;
-    size_t NumLocalTypeDecls;
-    size_t NumObjCMethods;
-    size_t NumInfixOperators;
-    size_t NumPostfixOperators;
-    size_t NumPrefixOperators;
-    size_t NumPrecedenceGroups;
-    size_t NumUsedConformances;
+#define FRONTEND_STATISTIC(NAME, ID) size_t ID;
+#include "Statistics.def"
+#undef FRONTEND_STATISTIC
+  };
 
-    size_t NumConformancesDeserialized;
-    size_t NumConstraintScopes;
-    size_t NumDeclsDeserialized;
-    size_t NumDeclsValidated;
-    size_t NumFunctionsTypechecked;
-    size_t NumGenericSignatureBuilders;
-    size_t NumLazyGenericEnvironments;
-    size_t NumLazyGenericEnvironmentsLoaded;
-    size_t NumLazyIterableDeclContexts;
-    size_t NominalTypeLookupDirectCount;
-    size_t NumTypesDeserialized;
-    size_t NumTypesValidated;
-    size_t NumUnloadedLazyIterableDeclContexts;
+  struct FrontendStatsTracer
+  {
+    UnifiedStatsReporter *Reporter;
+    llvm::TimeRecord SavedTime;
+    StringRef Name;
+    SourceRange Range;
+    FrontendStatsTracer(StringRef Name,
+                        SourceRange const &Range,
+                        UnifiedStatsReporter *Reporter);
+    FrontendStatsTracer();
+    FrontendStatsTracer(FrontendStatsTracer&& other);
+    FrontendStatsTracer& operator=(FrontendStatsTracer&&);
+    ~FrontendStatsTracer();
+    FrontendStatsTracer(const FrontendStatsTracer&) = delete;
+    FrontendStatsTracer& operator=(const FrontendStatsTracer&) = delete;
+  };
 
-    size_t NumSILGenFunctions;
-    size_t NumSILGenVtables;
-    size_t NumSILGenWitnessTables;
-    size_t NumSILGenDefaultWitnessTables;
-    size_t NumSILGenGlobalVariables;
-
-    size_t NumSILOptFunctions;
-    size_t NumSILOptVtables;
-    size_t NumSILOptWitnessTables;
-    size_t NumSILOptDefaultWitnessTables;
-    size_t NumSILOptGlobalVariables;
-
-    size_t NumIRGlobals;
-    size_t NumIRFunctions;
-    size_t NumIRAliases;
-    size_t NumIRIFuncs;
-    size_t NumIRNamedMetaData;
-    size_t NumIRValueSymbols;
-    size_t NumIRComdatSymbols;
-    size_t NumIRBasicBlocks;
-    size_t NumIRInsts;
-
-    size_t NumLLVMBytesOutput;
+  struct FrontendStatsEvent
+  {
+    uint64_t TimeUSec;
+    uint64_t LiveUSec;
+    bool IsEntry;
+    StringRef EventName;
+    StringRef CounterName;
+    size_t CounterDelta;
+    size_t CounterValue;
+    SourceRange SourceRange;
   };
 
 private:
-  SmallString<128> Filename;
+  SmallString<128> StatsFilename;
+  SmallString<128> TraceFilename;
   llvm::TimeRecord StartedTime;
   std::unique_ptr<llvm::NamedRegionTimer> Timer;
-
+  SourceManager *SourceMgr;
   std::unique_ptr<AlwaysOnDriverCounters> DriverCounters;
   std::unique_ptr<AlwaysOnFrontendCounters> FrontendCounters;
+  std::unique_ptr<AlwaysOnFrontendCounters> LastTracedFrontendCounters;
+  std::vector<FrontendStatsEvent> FrontendStatsEvents;
 
   void publishAlwaysOnStatsToLLVM();
   void printAlwaysOnStatsAndTimers(llvm::raw_ostream &OS);
 
   UnifiedStatsReporter(StringRef ProgramName,
                        StringRef AuxName,
-                       StringRef Directory);
+                       StringRef Directory,
+                       SourceManager *SM,
+                       bool TraceEvents);
 public:
   UnifiedStatsReporter(StringRef ProgramName,
                        StringRef ModuleName,
@@ -154,11 +121,17 @@
                        StringRef TripleName,
                        StringRef OutputType,
                        StringRef OptType,
-                       StringRef Directory);
+                       StringRef Directory,
+                       SourceManager *SM=nullptr,
+                       bool TraceEvents=false);
   ~UnifiedStatsReporter();
 
   AlwaysOnDriverCounters &getDriverCounters();
   AlwaysOnFrontendCounters &getFrontendCounters();
+  FrontendStatsTracer getStatsTracer(StringRef N,
+                                     SourceRange const &R);
+  void saveAnyFrontendStatsEvents(FrontendStatsTracer const& T,
+                                  bool IsEntry);
 };
 
 }
diff --git a/include/swift/Basic/Statistics.def b/include/swift/Basic/Statistics.def
new file mode 100644
index 0000000..343d761
--- /dev/null
+++ b/include/swift/Basic/Statistics.def
@@ -0,0 +1,103 @@
+//===--- Statistics.def - Statistics Macro Metaprogramming Database -*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the database of always-available statistic counters.
+//
+// DRIVER_STATISTIC(Id)
+//   - Id is an identifier suitable for use in C++
+//
+// FRONTEND_STATISTIC(Subsystem, Id)
+//   - Subsystem is a token to be stringified as a name prefix
+//   - Id is an identifier suitable for use in C++
+//===----------------------------------------------------------------------===//
+
+/// Driver statistics are collected for driver processes
+#ifdef DRIVER_STATISTIC
+DRIVER_STATISTIC(NumDriverJobsRun)
+DRIVER_STATISTIC(NumDriverJobsSkipped)
+
+DRIVER_STATISTIC(DriverDepCascadingTopLevel)
+DRIVER_STATISTIC(DriverDepCascadingDynamic)
+DRIVER_STATISTIC(DriverDepCascadingNominal)
+DRIVER_STATISTIC(DriverDepCascadingMember)
+DRIVER_STATISTIC(DriverDepCascadingExternal)
+
+DRIVER_STATISTIC(DriverDepTopLevel)
+DRIVER_STATISTIC(DriverDepDynamic)
+DRIVER_STATISTIC(DriverDepNominal)
+DRIVER_STATISTIC(DriverDepMember)
+DRIVER_STATISTIC(DriverDepExternal)
+
+DRIVER_STATISTIC(ChildrenMaxRSS)
+#endif
+
+/// Driver statistics are collected for frontend processes
+#ifdef FRONTEND_STATISTIC
+FRONTEND_STATISTIC(AST, NumSourceBuffers)
+FRONTEND_STATISTIC(AST, NumSourceLines)
+FRONTEND_STATISTIC(AST, NumSourceLinesPerSecond)
+FRONTEND_STATISTIC(AST, NumLinkLibraries)
+FRONTEND_STATISTIC(AST, NumLoadedModules)
+FRONTEND_STATISTIC(AST, NumImportedExternalDefinitions)
+FRONTEND_STATISTIC(AST, NumTotalClangImportedEntities)
+FRONTEND_STATISTIC(AST, NumASTBytesAllocated)
+FRONTEND_STATISTIC(AST, NumDependencies)
+FRONTEND_STATISTIC(AST, NumReferencedTopLevelNames)
+FRONTEND_STATISTIC(AST, NumReferencedDynamicNames)
+FRONTEND_STATISTIC(AST, NumReferencedMemberNames)
+FRONTEND_STATISTIC(AST, NumDecls)
+FRONTEND_STATISTIC(AST, NumLocalTypeDecls)
+FRONTEND_STATISTIC(AST, NumObjCMethods)
+FRONTEND_STATISTIC(AST, NumInfixOperators)
+FRONTEND_STATISTIC(AST, NumPostfixOperators)
+FRONTEND_STATISTIC(AST, NumPrefixOperators)
+FRONTEND_STATISTIC(AST, NumPrecedenceGroups)
+FRONTEND_STATISTIC(AST, NumUsedConformances)
+
+FRONTEND_STATISTIC(Sema, NumConformancesDeserialized)
+FRONTEND_STATISTIC(Sema, NumConstraintScopes)
+FRONTEND_STATISTIC(Sema, NumDeclsDeserialized)
+FRONTEND_STATISTIC(Sema, NumDeclsValidated)
+FRONTEND_STATISTIC(Sema, NumFunctionsTypechecked)
+FRONTEND_STATISTIC(Sema, NumGenericSignatureBuilders)
+FRONTEND_STATISTIC(Sema, NumLazyGenericEnvironments)
+FRONTEND_STATISTIC(Sema, NumLazyGenericEnvironmentsLoaded)
+FRONTEND_STATISTIC(Sema, NumLazyIterableDeclContexts)
+FRONTEND_STATISTIC(Sema, NominalTypeLookupDirectCount)
+FRONTEND_STATISTIC(Sema, NumTypesDeserialized)
+FRONTEND_STATISTIC(Sema, NumTypesValidated)
+FRONTEND_STATISTIC(Sema, NumUnloadedLazyIterableDeclContexts)
+
+FRONTEND_STATISTIC(SILModule, NumSILGenFunctions)
+FRONTEND_STATISTIC(SILModule, NumSILGenVtables)
+FRONTEND_STATISTIC(SILModule, NumSILGenWitnessTables)
+FRONTEND_STATISTIC(SILModule, NumSILGenDefaultWitnessTables)
+FRONTEND_STATISTIC(SILModule, NumSILGenGlobalVariables)
+
+FRONTEND_STATISTIC(SILModule, NumSILOptFunctions)
+FRONTEND_STATISTIC(SILModule, NumSILOptVtables)
+FRONTEND_STATISTIC(SILModule, NumSILOptWitnessTables)
+FRONTEND_STATISTIC(SILModule, NumSILOptDefaultWitnessTables)
+FRONTEND_STATISTIC(SILModule, NumSILOptGlobalVariables)
+
+FRONTEND_STATISTIC(IRModule, NumIRGlobals)
+FRONTEND_STATISTIC(IRModule, NumIRFunctions)
+FRONTEND_STATISTIC(IRModule, NumIRAliases)
+FRONTEND_STATISTIC(IRModule, NumIRIFuncs)
+FRONTEND_STATISTIC(IRModule, NumIRNamedMetaData)
+FRONTEND_STATISTIC(IRModule, NumIRValueSymbols)
+FRONTEND_STATISTIC(IRModule, NumIRComdatSymbols)
+FRONTEND_STATISTIC(IRModule, NumIRBasicBlocks)
+FRONTEND_STATISTIC(IRModule, NumIRInsts)
+
+FRONTEND_STATISTIC(LLVM, NumLLVMBytesOutput)
+#endif
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index b370360..32d68b0 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -222,6 +222,9 @@
   /// The path to which we should output statistics files.
   std::string StatsOutputDir;
 
+  /// Trace changes to stats to files in StatsOutputDir.
+  bool TraceStats = false;
+
   /// Indicates whether function body parsing should be delayed
   /// until the end of all files.
   bool DelayedFunctionBodyParsing = false;
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 40de10c..33d80e9 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -194,6 +194,9 @@
 def stats_output_dir: Separate<["-"], "stats-output-dir">,
   Flags<[FrontendOption, HelpHidden]>,
   HelpText<"Directory to write unified compilation-statistics files to">;
+def trace_stats_events: Flag<["-"], "trace-stats-events">,
+  Flags<[FrontendOption, HelpHidden]>,
+  HelpText<"Trace changes to stats in -stats-output-dir">;
 
 def emit_dependencies : Flag<["-"], "emit-dependencies">,
   Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
diff --git a/include/swift/SIL/Dominance.h b/include/swift/SIL/Dominance.h
index 16ea2ca..79e20d8 100644
--- a/include/swift/SIL/Dominance.h
+++ b/include/swift/SIL/Dominance.h
@@ -25,6 +25,18 @@
 extern template class llvm::DominatorTreeBase<swift::SILBasicBlock, true>;
 extern template class llvm::DomTreeNodeBase<swift::SILBasicBlock>;
 
+namespace llvm {
+namespace DomTreeBuilder {
+using SILDomTree = llvm::DomTreeBase<swift::SILBasicBlock>;
+using SILPostDomTree = llvm::PostDomTreeBase<swift::SILBasicBlock>;
+
+extern template void Calculate<SILDomTree, swift::SILFunction>(
+    SILDomTree &DT, swift::SILFunction &F);
+extern template void Calculate<SILPostDomTree, swift::SILFunction>(
+    SILPostDomTree &DT, swift::SILFunction &F);
+} // namespace DomTreeBuilder
+} // namespace llvm
+
 namespace swift {
 
 using DominatorTreeBase = llvm::DominatorTreeBase<swift::SILBasicBlock, false>;
diff --git a/lib/Basic/Statistic.cpp b/lib/Basic/Statistic.cpp
index 225f893..6165702 100644
--- a/lib/Basic/Statistic.cpp
+++ b/lib/Basic/Statistic.cpp
@@ -42,20 +42,34 @@
 }
 
 static std::string
-makeFileName(StringRef ProgramName,
-             StringRef AuxName) {
+makeFileName(StringRef Prefix,
+             StringRef ProgramName,
+             StringRef AuxName,
+             StringRef Suffix) {
   std::string tmp;
   raw_string_ostream stream(tmp);
   auto now = std::chrono::system_clock::now();
-  stream << "stats"
+  stream << Prefix
          << "-" << now.time_since_epoch().count()
          << "-" << ProgramName
          << "-" << AuxName
          << "-" << Process::GetRandomNumber()
-         << ".json";
+         << "." << Suffix;
   return stream.str();
 }
 
+static std::string
+makeStatsFileName(StringRef ProgramName,
+                  StringRef AuxName) {
+  return makeFileName("stats", ProgramName, AuxName, "json");
+}
+
+static std::string
+makeTraceFileName(StringRef ProgramName,
+                  StringRef AuxName) {
+  return makeFileName("trace", ProgramName, AuxName, "csv");
+}
+
 // LLVM's statistics-reporting machinery is sensitive to filenames containing
 // YAML-quote-requiring characters, which occur surprisingly often in the wild;
 // we only need a recognizable and likely-unique name for a target here, not an
@@ -108,29 +122,39 @@
                                            StringRef TripleName,
                                            StringRef OutputType,
                                            StringRef OptType,
-                                           StringRef Directory)
+                                           StringRef Directory,
+                                           SourceManager *SM,
+                                           bool TraceEvents)
   : UnifiedStatsReporter(ProgramName,
                          auxName(ModuleName,
                                  InputName,
                                  TripleName,
                                  OutputType,
                                  OptType),
-                         Directory)
+                         Directory,
+                         SM, TraceEvents)
 {
 }
 
 UnifiedStatsReporter::UnifiedStatsReporter(StringRef ProgramName,
                                            StringRef AuxName,
-                                           StringRef Directory)
-  : Filename(Directory),
+                                           StringRef Directory,
+                                           SourceManager *SM,
+                                           bool TraceEvents)
+  : StatsFilename(Directory),
+    TraceFilename(Directory),
     StartedTime(llvm::TimeRecord::getCurrentTime()),
     Timer(make_unique<NamedRegionTimer>(AuxName,
                                         "Building Target",
-                                        ProgramName, "Running Program"))
+                                        ProgramName, "Running Program")),
+    SourceMgr(SM)
 {
-  path::append(Filename, makeFileName(ProgramName, AuxName));
+  path::append(StatsFilename, makeStatsFileName(ProgramName, AuxName));
+  path::append(TraceFilename, makeTraceFileName(ProgramName, AuxName));
   EnableStatistics(/*PrintOnExit=*/false);
   SharedTimer::enableCompilationTimers();
+  if (TraceEvents)
+    LastTracedFrontendCounters = make_unique<AlwaysOnFrontendCounters>();
 }
 
 UnifiedStatsReporter::AlwaysOnDriverCounters &
@@ -149,102 +173,30 @@
   return *FrontendCounters;
 }
 
-#define PUBLISH_STAT(C,TY,NAME)                               \
-  do {                                                        \
-    static Statistic Stat = {TY, #NAME, #NAME, {0}, false};   \
-    Stat += (C).NAME;                                         \
-  } while (0)
-
 void
 UnifiedStatsReporter::publishAlwaysOnStatsToLLVM() {
   if (FrontendCounters) {
     auto &C = getFrontendCounters();
-
-    PUBLISH_STAT(C, "AST", NumSourceBuffers);
-    PUBLISH_STAT(C, "AST", NumSourceLines);
-    PUBLISH_STAT(C, "AST", NumSourceLinesPerSecond);
-    PUBLISH_STAT(C, "AST", NumLinkLibraries);
-    PUBLISH_STAT(C, "AST", NumLoadedModules);
-    PUBLISH_STAT(C, "AST", NumImportedExternalDefinitions);
-    PUBLISH_STAT(C, "AST", NumTotalClangImportedEntities);
-    PUBLISH_STAT(C, "AST", NumASTBytesAllocated);
-    PUBLISH_STAT(C, "AST", NumDependencies);
-    PUBLISH_STAT(C, "AST", NumReferencedTopLevelNames);
-    PUBLISH_STAT(C, "AST", NumReferencedDynamicNames);
-    PUBLISH_STAT(C, "AST", NumReferencedMemberNames);
-    PUBLISH_STAT(C, "AST", NumDecls);
-    PUBLISH_STAT(C, "AST", NumLocalTypeDecls);
-    PUBLISH_STAT(C, "AST", NumObjCMethods);
-    PUBLISH_STAT(C, "AST", NumInfixOperators);
-    PUBLISH_STAT(C, "AST", NumPostfixOperators);
-    PUBLISH_STAT(C, "AST", NumPrefixOperators);
-    PUBLISH_STAT(C, "AST", NumPrecedenceGroups);
-    PUBLISH_STAT(C, "AST", NumUsedConformances);
-
-    PUBLISH_STAT(C, "Sema", NumConformancesDeserialized);
-    PUBLISH_STAT(C, "Sema", NumConstraintScopes);
-    PUBLISH_STAT(C, "Sema", NumDeclsDeserialized);
-    PUBLISH_STAT(C, "Sema", NumDeclsValidated);
-    PUBLISH_STAT(C, "Sema", NumFunctionsTypechecked);
-    PUBLISH_STAT(C, "Sema", NumGenericSignatureBuilders);
-    PUBLISH_STAT(C, "Sema", NumLazyGenericEnvironments);
-    PUBLISH_STAT(C, "Sema", NumLazyGenericEnvironmentsLoaded);
-    PUBLISH_STAT(C, "Sema", NumLazyIterableDeclContexts);
-    PUBLISH_STAT(C, "Sema", NominalTypeLookupDirectCount);
-    PUBLISH_STAT(C, "Sema", NumTypesDeserialized);
-    PUBLISH_STAT(C, "Sema", NumTypesValidated);
-    PUBLISH_STAT(C, "Sema", NumUnloadedLazyIterableDeclContexts);
-
-    PUBLISH_STAT(C, "SILModule", NumSILGenFunctions);
-    PUBLISH_STAT(C, "SILModule", NumSILGenVtables);
-    PUBLISH_STAT(C, "SILModule", NumSILGenWitnessTables);
-    PUBLISH_STAT(C, "SILModule", NumSILGenDefaultWitnessTables);
-    PUBLISH_STAT(C, "SILModule", NumSILGenGlobalVariables);
-
-    PUBLISH_STAT(C, "SILModule", NumSILOptFunctions);
-    PUBLISH_STAT(C, "SILModule", NumSILOptVtables);
-    PUBLISH_STAT(C, "SILModule", NumSILOptWitnessTables);
-    PUBLISH_STAT(C, "SILModule", NumSILOptDefaultWitnessTables);
-    PUBLISH_STAT(C, "SILModule", NumSILOptGlobalVariables);
-
-    PUBLISH_STAT(C, "IRModule", NumIRGlobals);
-    PUBLISH_STAT(C, "IRModule", NumIRFunctions);
-    PUBLISH_STAT(C, "IRModule", NumIRAliases);
-    PUBLISH_STAT(C, "IRModule", NumIRIFuncs);
-    PUBLISH_STAT(C, "IRModule", NumIRNamedMetaData);
-    PUBLISH_STAT(C, "IRModule", NumIRValueSymbols);
-    PUBLISH_STAT(C, "IRModule", NumIRComdatSymbols);
-    PUBLISH_STAT(C, "IRModule", NumIRBasicBlocks);
-    PUBLISH_STAT(C, "IRModule", NumIRInsts);
-
-    PUBLISH_STAT(C, "LLVM", NumLLVMBytesOutput);
+#define FRONTEND_STATISTIC(TY, NAME)                            \
+    do {                                                        \
+      static Statistic Stat = {#TY, #NAME, #NAME, {0}, false};  \
+      Stat += (C).NAME;                                         \
+    } while (0);
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
   }
   if (DriverCounters) {
     auto &C = getDriverCounters();
-    PUBLISH_STAT(C, "Driver", NumDriverJobsRun);
-    PUBLISH_STAT(C, "Driver", NumDriverJobsSkipped);
-
-    PUBLISH_STAT(C, "Driver", DriverDepCascadingTopLevel);
-    PUBLISH_STAT(C, "Driver", DriverDepCascadingDynamic);
-    PUBLISH_STAT(C, "Driver", DriverDepCascadingNominal);
-    PUBLISH_STAT(C, "Driver", DriverDepCascadingMember);
-    PUBLISH_STAT(C, "Driver", DriverDepCascadingExternal);
-
-    PUBLISH_STAT(C, "Driver", DriverDepTopLevel);
-    PUBLISH_STAT(C, "Driver", DriverDepDynamic);
-    PUBLISH_STAT(C, "Driver", DriverDepNominal);
-    PUBLISH_STAT(C, "Driver", DriverDepMember);
-    PUBLISH_STAT(C, "Driver", DriverDepExternal);
-    PUBLISH_STAT(C, "Driver", ChildrenMaxRSS);
+#define DRIVER_STATISTIC(NAME)                                       \
+    do {                                                             \
+      static Statistic Stat = {"Driver", #NAME, #NAME, {0}, false};  \
+      Stat += (C).NAME;                                              \
+    } while (0);
+#include "swift/Basic/Statistics.def"
+#undef DRIVER_STATISTIC
   }
 }
 
-#define PRINT_STAT(OS,DELIM,C,TY,NAME)                   \
-  do {                                                   \
-    OS << DELIM << "\t\"" TY "." #NAME "\": " << C.NAME; \
-    delim = ",\n";                                       \
-  } while (0)
-
 void
 UnifiedStatsReporter::printAlwaysOnStatsAndTimers(raw_ostream &OS) {
   // Adapted from llvm::PrintStatisticsJSON
@@ -252,83 +204,23 @@
   const char *delim = "";
   if (FrontendCounters) {
     auto &C = getFrontendCounters();
-
-    PRINT_STAT(OS, delim, C, "AST", NumSourceBuffers);
-    PRINT_STAT(OS, delim, C, "AST", NumSourceLines);
-    PRINT_STAT(OS, delim, C, "AST", NumSourceLinesPerSecond);
-    PRINT_STAT(OS, delim, C, "AST", NumLinkLibraries);
-    PRINT_STAT(OS, delim, C, "AST", NumLoadedModules);
-    PRINT_STAT(OS, delim, C, "AST", NumImportedExternalDefinitions);
-    PRINT_STAT(OS, delim, C, "AST", NumTotalClangImportedEntities);
-    PRINT_STAT(OS, delim, C, "AST", NumASTBytesAllocated);
-    PRINT_STAT(OS, delim, C, "AST", NumDependencies);
-    PRINT_STAT(OS, delim, C, "AST", NumReferencedTopLevelNames);
-    PRINT_STAT(OS, delim, C, "AST", NumReferencedDynamicNames);
-    PRINT_STAT(OS, delim, C, "AST", NumReferencedMemberNames);
-    PRINT_STAT(OS, delim, C, "AST", NumDecls);
-    PRINT_STAT(OS, delim, C, "AST", NumLocalTypeDecls);
-    PRINT_STAT(OS, delim, C, "AST", NumObjCMethods);
-    PRINT_STAT(OS, delim, C, "AST", NumInfixOperators);
-    PRINT_STAT(OS, delim, C, "AST", NumPostfixOperators);
-    PRINT_STAT(OS, delim, C, "AST", NumPrefixOperators);
-    PRINT_STAT(OS, delim, C, "AST", NumPrecedenceGroups);
-    PRINT_STAT(OS, delim, C, "AST", NumUsedConformances);
-
-    PRINT_STAT(OS, delim, C, "Sema", NumConformancesDeserialized);
-    PRINT_STAT(OS, delim, C, "Sema", NumConstraintScopes);
-    PRINT_STAT(OS, delim, C, "Sema", NumDeclsDeserialized);
-    PRINT_STAT(OS, delim, C, "Sema", NumDeclsValidated);
-    PRINT_STAT(OS, delim, C, "Sema", NumFunctionsTypechecked);
-    PRINT_STAT(OS, delim, C, "Sema", NumGenericSignatureBuilders);
-    PRINT_STAT(OS, delim, C, "Sema", NumLazyGenericEnvironments);
-    PRINT_STAT(OS, delim, C, "Sema", NumLazyGenericEnvironmentsLoaded);
-    PRINT_STAT(OS, delim, C, "Sema", NumLazyIterableDeclContexts);
-    PRINT_STAT(OS, delim, C, "Sema", NominalTypeLookupDirectCount);
-    PRINT_STAT(OS, delim, C, "Sema", NumTypesDeserialized);
-    PRINT_STAT(OS, delim, C, "Sema", NumTypesValidated);
-    PRINT_STAT(OS, delim, C, "Sema", NumUnloadedLazyIterableDeclContexts);
-
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenFunctions);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenVtables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenWitnessTables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenDefaultWitnessTables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILGenGlobalVariables);
-
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptFunctions);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptVtables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptWitnessTables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptDefaultWitnessTables);
-    PRINT_STAT(OS, delim, C, "SILModule", NumSILOptGlobalVariables);
-
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRGlobals);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRFunctions);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRAliases);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRIFuncs);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRNamedMetaData);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRValueSymbols);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRComdatSymbols);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRBasicBlocks);
-    PRINT_STAT(OS, delim, C, "IRModule", NumIRInsts);
-
-    PRINT_STAT(OS, delim, C, "LLVM", NumLLVMBytesOutput);
+#define FRONTEND_STATISTIC(TY, NAME)                        \
+    do {                                                    \
+      OS << delim << "\t\"" #TY "." #NAME "\": " << C.NAME; \
+      delim = ",\n";                                        \
+    } while (0);
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
   }
   if (DriverCounters) {
     auto &C = getDriverCounters();
-    PRINT_STAT(OS, delim, C, "Driver", NumDriverJobsRun);
-    PRINT_STAT(OS, delim, C, "Driver", NumDriverJobsSkipped);
-
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingTopLevel);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingDynamic);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingNominal);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingMember);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepCascadingExternal);
-
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepTopLevel);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepDynamic);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepNominal);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepMember);
-    PRINT_STAT(OS, delim, C, "Driver", DriverDepExternal);
-    PRINT_STAT(OS, delim, C, "Driver", ChildrenMaxRSS);
+#define DRIVER_STATISTIC(NAME)                              \
+    do {                                                    \
+      OS << delim << "\t\"Driver." #NAME "\": " << C.NAME;  \
+      delim = ",\n";                                        \
+    } while (0);
+#include "swift/Basic/Statistics.def"
+#undef DRIVER_STATISTIC
   }
   // Print timers.
   TimerGroup::printAllJSONValues(OS, delim);
@@ -336,6 +228,91 @@
   OS.flush();
 }
 
+UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
+    StringRef Name,
+    SourceRange const &Range,
+    UnifiedStatsReporter *Reporter)
+  : Reporter(Reporter),
+    SavedTime(llvm::TimeRecord::getCurrentTime()),
+    Name(Name),
+    Range(Range)
+{
+  if (Reporter)
+    Reporter->saveAnyFrontendStatsEvents(*this, true);
+}
+
+UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer()
+  : Reporter(nullptr)
+{
+}
+
+UnifiedStatsReporter::FrontendStatsTracer&
+UnifiedStatsReporter::FrontendStatsTracer::operator=(
+    FrontendStatsTracer&& other)
+{
+  Reporter = other.Reporter;
+  SavedTime = other.SavedTime;
+  Name = other.Name;
+  Range = other.Range;
+  other.Reporter = nullptr;
+  return *this;
+}
+
+UnifiedStatsReporter::FrontendStatsTracer::FrontendStatsTracer(
+    FrontendStatsTracer&& other)
+  : Reporter(other.Reporter),
+    SavedTime(other.SavedTime),
+    Name(other.Name),
+    Range(other.Range)
+{
+  other.Reporter = nullptr;
+}
+
+UnifiedStatsReporter::FrontendStatsTracer::~FrontendStatsTracer()
+{
+  if (Reporter)
+    Reporter->saveAnyFrontendStatsEvents(*this, false);
+}
+
+UnifiedStatsReporter::FrontendStatsTracer
+UnifiedStatsReporter::getStatsTracer(StringRef N,
+                                     SourceRange const &R)
+{
+  if (LastTracedFrontendCounters)
+    // Return live tracer object.
+    return FrontendStatsTracer(N, R, this);
+  else
+    // Return inert tracer object.
+    return FrontendStatsTracer();
+}
+
+void
+UnifiedStatsReporter::saveAnyFrontendStatsEvents(
+    FrontendStatsTracer const& T,
+    bool IsEntry)
+{
+  if (!LastTracedFrontendCounters)
+    return;
+  auto Now = llvm::TimeRecord::getCurrentTime();
+  auto StartUS = uint64_t(1000000.0 * T.SavedTime.getProcessTime());
+  auto NowUS = uint64_t(1000000.0 * Now.getProcessTime());
+  auto LiveUS = IsEntry ? 0 : NowUS - StartUS;
+  auto &C = getFrontendCounters();
+#define FRONTEND_STATISTIC(TY, NAME)                          \
+  do {                                                        \
+    auto delta = C.NAME - LastTracedFrontendCounters->NAME;   \
+    static char const *name = #TY "." #NAME;                  \
+    if (delta != 0) {                                         \
+      LastTracedFrontendCounters->NAME = C.NAME;              \
+      FrontendStatsEvents.emplace_back(FrontendStatsEvent {   \
+          NowUS, LiveUS, IsEntry, T.Name, name,               \
+            delta, C.NAME, T.Range});                         \
+    }                                                         \
+  } while (0);
+#include "swift/Basic/Statistics.def"
+#undef FRONTEND_STATISTIC
+}
+
 UnifiedStatsReporter::~UnifiedStatsReporter()
 {
   // NB: Timer needs to be Optional<> because it needs to be destructed early;
@@ -364,7 +341,7 @@
   }
 
   std::error_code EC;
-  raw_fd_ostream ostream(Filename, EC, fs::F_Append | fs::F_Text);
+  raw_fd_ostream ostream(StatsFilename, EC, fs::F_Append | fs::F_Text);
   if (EC)
     return;
 
@@ -387,6 +364,27 @@
 #else
   printAlwaysOnStatsAndTimers(ostream);
 #endif
+
+  if (LastTracedFrontendCounters && SourceMgr) {
+    std::error_code EC;
+    raw_fd_ostream tstream(TraceFilename, EC, fs::F_Append | fs::F_Text);
+    if (EC)
+      return;
+    tstream << "Time,Live,IsEntry,EventName,CounterName,"
+            << "CounterDelta,CounterValue,SourceRange\n";
+    for (auto const &E : FrontendStatsEvents) {
+      tstream << E.TimeUSec << ','
+              << E.LiveUSec << ','
+              << (E.IsEntry ? "\"entry\"," : "\"exit\",")
+              << '"' << E.EventName << '"' << ','
+              << '"' << E.CounterName << '"' << ','
+              << E.CounterDelta << ','
+              << E.CounterValue << ',';
+      tstream << '"';
+      E.SourceRange.print(tstream, *SourceMgr, false);
+      tstream << '"' << '\n';
+    }
+  }
 }
 
 } // namespace swift
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 626df74..f0e03d0 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -151,6 +151,7 @@
   inputArgs.AddLastArg(arguments, options::OPT_swift_version);
   inputArgs.AddLastArg(arguments, options::OPT_enforce_exclusivity_EQ);
   inputArgs.AddLastArg(arguments, options::OPT_stats_output_dir);
+  inputArgs.AddLastArg(arguments, options::OPT_trace_stats_events);
   inputArgs.AddLastArg(arguments,
                        options::OPT_solver_shrink_unsolved_threshold);
   inputArgs.AddLastArg(arguments, options::OPT_O_Group);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 0a12441..92ba309 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -194,6 +194,9 @@
   Opts.DebugTimeCompilation |= Args.hasArg(OPT_debug_time_compilation);
   if (const Arg *A = Args.getLastArg(OPT_stats_output_dir)) {
     Opts.StatsOutputDir = A->getValue();
+    if (Args.getLastArg(OPT_trace_stats_events)) {
+      Opts.TraceStats = true;
+    }
   }
 
   if (const Arg *A = Args.getLastArg(OPT_validate_tbd_against_ir_EQ)) {
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 0a0cfbb..3998777 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -1360,13 +1360,17 @@
     StringRef OutFile = FEOpts.getSingleOutputFilename();
     StringRef OutputType = llvm::sys::path::extension(OutFile);
     std::string TripleName = LangOpts.Target.normalize();
+    auto &SM = Instance->getSourceMgr();
+    auto Trace = Invocation.getFrontendOptions().TraceStats;
     StatsReporter = llvm::make_unique<UnifiedStatsReporter>("swift-frontend",
                                                             FEOpts.ModuleName,
                                                             InputName,
                                                             TripleName,
                                                             OutputType,
                                                             OptType,
-                                                            StatsOutputDir);
+                                                            StatsOutputDir,
+                                                            &SM,
+                                                            Trace);
   }
 
   const DiagnosticOptions &diagOpts = Invocation.getDiagnosticOptions();
diff --git a/lib/SIL/Dominance.cpp b/lib/SIL/Dominance.cpp
index 2cce9fc..09b406d 100644
--- a/lib/SIL/Dominance.cpp
+++ b/lib/SIL/Dominance.cpp
@@ -14,7 +14,6 @@
 #include "swift/SIL/SILBasicBlock.h"
 #include "swift/SIL/SILArgument.h"
 #include "swift/SIL/Dominance.h"
-#include "llvm/Support/GenericDomTree.h"
 #include "llvm/Support/GenericDomTreeConstruction.h"
 
 using namespace swift;
@@ -22,14 +21,15 @@
 template class llvm::DominatorTreeBase<SILBasicBlock, false>;
 template class llvm::DominatorTreeBase<SILBasicBlock, true>;
 template class llvm::DomTreeNodeBase<SILBasicBlock>;
-using SILDomTree = llvm::DomTreeBase<SILBasicBlock>;
-using SILPostDomTree = llvm::PostDomTreeBase<SILBasicBlock>;
-template void
-llvm::DomTreeBuilder::Calculate<SILDomTree, swift::SILFunction>(
+
+namespace llvm {
+namespace DomTreeBuilder {
+template void Calculate<SILDomTree, swift::SILFunction>(
     SILDomTree &DT, swift::SILFunction &F);
-template void
-llvm::DomTreeBuilder::Calculate<SILPostDomTree, swift::SILFunction>(
+template void Calculate<SILPostDomTree, swift::SILFunction>(
     SILPostDomTree &DT, swift::SILFunction &F);
+} // namespace DomTreeBuilder
+} // namespace llvm
 
 /// Compute the immediate-dominators map.
 DominanceInfo::DominanceInfo(SILFunction *F)
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index 9f46093..fcfc379 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -3936,6 +3936,10 @@
       : TC(TC), IsFirstPass(IsFirstPass), IsSecondPass(IsSecondPass) {}
 
   void visit(Decl *decl) {
+    UnifiedStatsReporter::FrontendStatsTracer Tracer;
+    if (TC.Context.Stats)
+      Tracer = TC.Context.Stats->getStatsTracer("type-checking",
+                                                decl->getSourceRange());
     PrettyStackTraceDecl StackTrace("type-checking", decl);
     
     DeclVisitor<DeclChecker>::visit(decl);