Skip to content

Commit 0442c7c

Browse files
Merge pull request #82646 from aschwaighofer/wip_opt_remarks_wmo
Support LLVM optimization remarks in WMO mode
2 parents cc17c04 + b30bd40 commit 0442c7c

File tree

10 files changed

+231
-31
lines changed

10 files changed

+231
-31
lines changed

include/swift/AST/SILOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,10 @@ class SILOptions {
316316
/// records.
317317
std::string OptRecordFile;
318318

319+
/// The names of the auxiliar files to which the backend should save optimization
320+
/// records for the remaining (other than the main one) LLVMModules.
321+
std::vector<std::string> AuxOptRecordFiles;
322+
319323
/// The regex that filters the passes that should be saved to the optimization
320324
/// records.
321325
std::string OptRecordPasses;

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ class FrontendInputsAndOutputs {
253253
const PrimarySpecificPaths &
254254
getPrimarySpecificPathsForAtMostOnePrimary() const;
255255

256+
const PrimarySpecificPaths &
257+
getPrimarySpecificPathsForRemaining(unsigned i) const;
258+
256259
const PrimarySpecificPaths &
257260
getPrimarySpecificPathsForPrimary(StringRef) const;
258261

lib/Frontend/ArgsToFrontendOutputsConverter.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,44 @@ SupplementaryOutputPathsComputer::computeOutputPaths() const {
298298
});
299299
if (hadError)
300300
return std::nullopt;
301+
302+
// In WMO mode compute supplementary output paths for optimization record
303+
// data (opt-remarks). We need one path per LLVMModule that will be created as
304+
// part of wmo.
305+
if (!InputsAndOutputs.hasPrimaryInputs() && OutputFiles.size() > 1) {
306+
unsigned i = 0;
307+
InputsAndOutputs.forEachInput([&](const InputFile &input) -> bool {
308+
// First input is already computed.
309+
if (InputsAndOutputs.firstInput().getFileName() == input.getFileName()) {
310+
++i;
311+
return false;
312+
}
313+
SupplementaryOutputPaths outputs;
314+
315+
// Compute auxiliar opt record paths.
316+
StringRef defaultSupplementaryOutputPathExcludingExtension =
317+
deriveDefaultSupplementaryOutputPathExcludingExtension(OutputFiles[i], input);
318+
319+
auto YAMLOptRecordPath = determineSupplementaryOutputFilename(
320+
options::OPT_save_optimization_record_path,
321+
"",
322+
file_types::TY_YAMLOptRecord, "",
323+
defaultSupplementaryOutputPathExcludingExtension, true);
324+
outputs.YAMLOptRecordPath = YAMLOptRecordPath;
325+
326+
auto bitstreamOptRecordPath = determineSupplementaryOutputFilename(
327+
options::OPT_save_optimization_record_path,
328+
"",
329+
file_types::TY_BitstreamOptRecord, "",
330+
defaultSupplementaryOutputPathExcludingExtension, true);
331+
332+
outputs.BitstreamOptRecordPath = bitstreamOptRecordPath;
333+
334+
outputPaths.emplace_back(std::move(outputs));
335+
++i;
336+
return false;
337+
});
338+
}
301339
return outputPaths;
302340
}
303341

@@ -615,7 +653,21 @@ std::string
615653
SupplementaryOutputPathsComputer::determineSupplementaryOutputFilename(
616654
options::ID emitOpt, std::string pathFromArguments, file_types::ID type,
617655
StringRef mainOutputIfUsable,
618-
StringRef defaultSupplementaryOutputPathExcludingExtension) const {
656+
StringRef defaultSupplementaryOutputPathExcludingExtension,
657+
bool forceDefaultSupplementaryOutputPathExcludingExtension) const {
658+
659+
auto computeDefaultSupplementaryOutputPathExcludingExtension =
660+
[&] () -> std::string {
661+
llvm::SmallString<128> path(
662+
defaultSupplementaryOutputPathExcludingExtension);
663+
664+
llvm::sys::path::replace_extension(path, file_types::getExtension(type));
665+
return path.str().str();
666+
};
667+
668+
if (forceDefaultSupplementaryOutputPathExcludingExtension) {
669+
return computeDefaultSupplementaryOutputPathExcludingExtension();
670+
}
619671

620672
if (!pathFromArguments.empty())
621673
return pathFromArguments;
@@ -627,9 +679,7 @@ SupplementaryOutputPathsComputer::determineSupplementaryOutputFilename(
627679
return mainOutputIfUsable.str();
628680
}
629681

630-
llvm::SmallString<128> path(defaultSupplementaryOutputPathExcludingExtension);
631-
llvm::sys::path::replace_extension(path, file_types::getExtension(type));
632-
return path.str().str();
682+
return computeDefaultSupplementaryOutputPathExcludingExtension();
633683
}
634684

635685
void SupplementaryOutputPathsComputer::deriveModulePathParameters(

lib/Frontend/ArgsToFrontendOutputsConverter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ class SupplementaryOutputPathsComputer {
180180
std::string determineSupplementaryOutputFilename(
181181
options::ID emitOpt, std::string pathFromArgumentsOrFilelists,
182182
file_types::ID type, StringRef mainOutputIfUsable,
183-
StringRef defaultSupplementaryOutputPathExcludingExtension) const;
183+
StringRef defaultSupplementaryOutputPathExcludingExtension,
184+
bool forceDefaultSupplementaryOutputPathExcludingExtension = false) const;
184185

185186
void deriveModulePathParameters(StringRef mainOutputFile,
186187
options::ID &emitOption,

lib/Frontend/FrontendInputsAndOutputs.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -380,21 +380,32 @@ void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
380380
}
381381
return;
382382
}
383-
assert(supplementaryOutputs.size() == 1 &&
384-
"WMO only ever produces one set of supplementary outputs");
383+
384+
assert(supplementaryOutputs.size() == 1 ||
385+
supplementaryOutputs.size() == AllInputs.size() &&
386+
"WMO produces wrong number of sets of supplementary outputs");
385387
if (outputFiles.size() == 1) {
386-
AllInputs.front().setPrimarySpecificPaths(PrimarySpecificPaths(
387-
outputFiles.front(), outputFilesForIndexUnits.front(),
388-
firstInputProducingOutput().getFileName(),
389-
supplementaryOutputs.front()));
388+
for (auto i : indices(AllInputs)) {
389+
if (i == 0)
390+
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
391+
outputFiles.front(), outputFilesForIndexUnits.front(),
392+
firstInputProducingOutput().getFileName(),
393+
supplementaryOutputs.front()));
394+
else
395+
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
396+
"", "", "",
397+
supplementaryOutputs.size() == 1 ? SupplementaryOutputPaths()
398+
: supplementaryOutputs[i]));
399+
}
390400
return;
391401
}
392402
assert(outputFiles.size() == AllInputs.size() &&
393403
"Multi-threaded WMO requires one main output per input");
394404
for (auto i : indices(AllInputs))
395405
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
396406
outputFiles[i], outputFilesForIndexUnits[i], outputFiles[i],
397-
i == 0 ? supplementaryOutputs.front() : SupplementaryOutputPaths()));
407+
supplementaryOutputs.size() == 1 && i != 0 ? SupplementaryOutputPaths()
408+
: supplementaryOutputs[i]));
398409
}
399410

400411
std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const {
@@ -488,6 +499,14 @@ FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const {
488499
: emptyPaths;
489500
}
490501

502+
const PrimarySpecificPaths &
503+
FrontendInputsAndOutputs::getPrimarySpecificPathsForRemaining(unsigned i) const {
504+
static auto emptyPaths = PrimarySpecificPaths();
505+
unsigned firstProducingIdx = getIndexOfFirstOutputProducingInput();
506+
return (hasInputs() && i > 0) ?
507+
AllInputs[firstProducingIdx+i].getPrimarySpecificPaths() : emptyPaths;
508+
}
509+
491510
const PrimarySpecificPaths &
492511
FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary(
493512
StringRef filename) const {

lib/FrontendTool/FrontendTool.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,8 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
740740
const auto &Invocation = Instance.getInvocation();
741741
const FrontendOptions &opts = Invocation.getFrontendOptions();
742742

743-
auto getSILOptions = [&](const PrimarySpecificPaths &PSPs) -> SILOptions {
743+
auto getSILOptions = [&](const PrimarySpecificPaths &PSPs,
744+
const std::vector<PrimarySpecificPaths> &auxPSPs) -> SILOptions {
744745
SILOptions SILOpts = Invocation.getSILOptions();
745746
if (SILOpts.OptRecordFile.empty()) {
746747
// Check if the record file path was passed via supplemental outputs.
@@ -749,6 +750,15 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
749750
PSPs.SupplementaryOutputs.YAMLOptRecordPath :
750751
PSPs.SupplementaryOutputs.BitstreamOptRecordPath;
751752
}
753+
if (!auxPSPs.empty()) {
754+
assert(SILOpts.AuxOptRecordFiles.empty());
755+
for (const auto &auxFile: auxPSPs) {
756+
SILOpts.AuxOptRecordFiles.push_back(
757+
SILOpts.OptRecordFormat == llvm::remarks::Format::YAML ?
758+
auxFile.SupplementaryOutputs.YAMLOptRecordPath :
759+
auxFile.SupplementaryOutputs.BitstreamOptRecordPath);
760+
}
761+
}
752762
return SILOpts;
753763
};
754764

@@ -758,13 +768,24 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
758768
// SILModule for the entire module.
759769
const PrimarySpecificPaths PSPs =
760770
Instance.getPrimarySpecificPathsForWholeModuleOptimizationMode();
761-
SILOptions SILOpts = getSILOptions(PSPs);
771+
772+
std::vector<PrimarySpecificPaths> auxPSPs;
773+
for (unsigned i = 1; i < opts.InputsAndOutputs.inputCount(); ++i) {
774+
auto &auxPSP =
775+
opts.InputsAndOutputs.getPrimarySpecificPathsForRemaining(i);
776+
auxPSPs.push_back(auxPSP);
777+
}
778+
779+
SILOptions SILOpts = getSILOptions(PSPs, auxPSPs);
762780
IRGenOptions irgenOpts = Invocation.getIRGenOptions();
763781
auto SM = performASTLowering(mod, Instance.getSILTypes(), SILOpts,
764782
&irgenOpts);
765783
return performCompileStepsPostSILGen(Instance, std::move(SM), mod, PSPs,
766784
ReturnValue, observer);
767785
}
786+
787+
788+
std::vector<PrimarySpecificPaths> emptyAuxPSPs;
768789
// If there are primary source files, build a separate SILModule for
769790
// each source file, and run the remaining SILOpt-Serialize-IRGen-LLVM
770791
// once for each such input.
@@ -773,7 +794,7 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
773794
for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) {
774795
const PrimarySpecificPaths PSPs =
775796
Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
776-
SILOptions SILOpts = getSILOptions(PSPs);
797+
SILOptions SILOpts = getSILOptions(PSPs, emptyAuxPSPs);
777798
IRGenOptions irgenOpts = Invocation.getIRGenOptions();
778799
auto SM = performASTLowering(*PrimaryFile, Instance.getSILTypes(),
779800
SILOpts, &irgenOpts);
@@ -793,7 +814,7 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
793814
if (opts.InputsAndOutputs.isInputPrimary(SASTF->getFilename())) {
794815
const PrimarySpecificPaths &PSPs =
795816
Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
796-
SILOptions SILOpts = getSILOptions(PSPs);
817+
SILOptions SILOpts = getSILOptions(PSPs, emptyAuxPSPs);
797818
auto SM = performASTLowering(*SASTF, Instance.getSILTypes(), SILOpts);
798819
result |= performCompileStepsPostSILGen(Instance, std::move(SM), mod,
799820
PSPs, ReturnValue, observer);

lib/IRGen/IRGen.cpp

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/ABI/MetadataValues.h"
2121
#include "swift/ABI/ObjectFile.h"
2222
#include "swift/AST/DiagnosticsIRGen.h"
23+
#include "swift/AST/DiagnosticsFrontend.h"
2324
#include "swift/AST/IRGenOptions.h"
2425
#include "swift/AST/IRGenRequests.h"
2526
#include "swift/AST/LinkLibrary.h"
@@ -71,6 +72,8 @@
7172
#include "llvm/Passes/PassBuilder.h"
7273
#include "llvm/Passes/PassPlugin.h"
7374
#include "llvm/Passes/StandardInstrumentations.h"
75+
#include "llvm/Remarks/Remark.h"
76+
#include "llvm/Remarks/RemarkStreamer.h"
7477
#include "llvm/Support/CommandLine.h"
7578
#include "llvm/Support/Debug.h"
7679
#include "llvm/Support/ErrorHandling.h"
@@ -1143,7 +1146,7 @@ static void embedBitcode(llvm::Module *M, const IRGenOptions &Opts)
11431146
NewUsed->setSection("llvm.metadata");
11441147
}
11451148

1146-
static void initLLVMModule(IRGenModule &IGM, SILModule &SIL) {
1149+
static void initLLVMModule(IRGenModule &IGM, SILModule &SIL, std::optional<unsigned> idx = {}) {
11471150
auto *Module = IGM.getModule();
11481151
assert(Module && "Expected llvm:Module for IR generation!");
11491152

@@ -1186,17 +1189,67 @@ static void initLLVMModule(IRGenModule &IGM, SILModule &SIL) {
11861189
llvm::ConstantAsMetadata::get(Value)}));
11871190

11881191
if (auto *SILstreamer = SIL.getSILRemarkStreamer()) {
1189-
// Install RemarkStreamer into LLVM and keep the remarks file alive. This is
1190-
// required even if no LLVM remarks are enabled, because the AsmPrinter
1191-
// serializes meta information about the remarks into the object file.
1192-
IGM.RemarkStream = SILstreamer->releaseStream();
1193-
SILstreamer->intoLLVMContext(Context);
1194-
auto &RS = *IGM.getLLVMContext().getMainRemarkStreamer();
1195-
if (IGM.getOptions().AnnotateCondFailMessage) {
1192+
auto remarkStream = SILstreamer->releaseStream();
1193+
if (remarkStream) {
1194+
// Install RemarkStreamer into LLVM and keep the remarks file alive. This is
1195+
// required even if no LLVM remarks are enabled, because the AsmPrinter
1196+
// serializes meta information about the remarks into the object file.
1197+
IGM.RemarkStream = std::move(remarkStream);
1198+
SILstreamer->intoLLVMContext(Context);
1199+
auto &RS = *IGM.getLLVMContext().getMainRemarkStreamer();
1200+
if (IGM.getOptions().AnnotateCondFailMessage) {
1201+
Context.setLLVMRemarkStreamer(
1202+
std::make_unique<llvm::LLVMRemarkStreamer>(RS));
1203+
} else {
1204+
// Don't filter for now.
1205+
Context.setLLVMRemarkStreamer(
1206+
std::make_unique<llvm::LLVMRemarkStreamer>(RS));
1207+
}
1208+
} else {
1209+
assert(idx && "Not generating multiple output files?");
1210+
1211+
// Construct llvmremarkstreamer objects for LLVM remarks originating in
1212+
// the LLVM backend and install it in the remaining LLVMModule(s).
1213+
auto &SILOpts = SIL.getOptions();
1214+
assert(SILOpts.AuxOptRecordFiles.size() > (*idx - 1));
1215+
1216+
const auto &filename = SILOpts.AuxOptRecordFiles[*idx - 1];
1217+
auto &diagEngine = SIL.getASTContext().Diags;
1218+
std::error_code errorCode;
1219+
auto file = std::make_unique<llvm::raw_fd_ostream>(filename, errorCode,
1220+
llvm::sys::fs::OF_None);
1221+
if (errorCode) {
1222+
diagEngine.diagnose(SourceLoc(), diag::cannot_open_file, filename,
1223+
errorCode.message());
1224+
return;
1225+
}
1226+
1227+
const auto format = SILOpts.OptRecordFormat;
1228+
llvm::Expected<std::unique_ptr<llvm::remarks::RemarkSerializer>>
1229+
remarkSerializerOrErr = llvm::remarks::createRemarkSerializer(
1230+
format, llvm::remarks::SerializerMode::Separate, *file);
1231+
if (llvm::Error err = remarkSerializerOrErr.takeError()) {
1232+
diagEngine.diagnose(SourceLoc(), diag::error_creating_remark_serializer,
1233+
toString(std::move(err)));
1234+
return;
1235+
}
1236+
1237+
auto auxRS = std::make_unique<llvm::remarks::RemarkStreamer>(
1238+
std::move(*remarkSerializerOrErr), filename);
1239+
const auto passes = SILOpts.OptRecordPasses;
1240+
if (!passes.empty()) {
1241+
if (llvm::Error err = auxRS->setFilter(passes)) {
1242+
diagEngine.diagnose(SourceLoc(), diag::error_creating_remark_serializer,
1243+
toString(std::move(err)));
1244+
return ;
1245+
}
1246+
}
1247+
1248+
Context.setMainRemarkStreamer(std::move(auxRS));
11961249
Context.setLLVMRemarkStreamer(
1197-
std::make_unique<llvm::LLVMRemarkStreamer>(RS));
1198-
// FIXME: add a frontend flag to enable all LLVM remarks
1199-
cantFail(RS.setFilter("annotation-remarks"));
1250+
std::make_unique<llvm::LLVMRemarkStreamer>(
1251+
*Context.getMainRemarkStreamer()));
1252+
IGM.RemarkStream = std::move(file);
12001253
}
12011254
}
12021255
}
@@ -1545,6 +1598,7 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
15451598
auto &Ctx = M->getASTContext();
15461599
// Create an IRGenModule for each source file.
15471600
bool DidRunSILCodeGenPreparePasses = false;
1601+
unsigned idx = 0;
15481602
for (auto *File : M->getFiles()) {
15491603
auto nextSF = dyn_cast<SourceFile>(File);
15501604
if (!nextSF)
@@ -1561,11 +1615,12 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
15611615
if (!targetMachine) continue;
15621616

15631617
// Create the IR emitter.
1618+
auto outputName = *OutputIter++;
15641619
IRGenModule *IGM = new IRGenModule(
1565-
irgen, std::move(targetMachine), nextSF, desc.ModuleName, *OutputIter++,
1620+
irgen, std::move(targetMachine), nextSF, desc.ModuleName, outputName,
15661621
nextSF->getFilename(), nextSF->getPrivateDiscriminator().str());
15671622

1568-
initLLVMModule(*IGM, *SILMod);
1623+
initLLVMModule(*IGM, *SILMod, idx++);
15691624
if (!DidRunSILCodeGenPreparePasses) {
15701625
// Run SIL level IRGen preparation passes on the module the first time
15711626
// around.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
open class C {
2+
var x = 1
3+
var y = 2
4+
5+
public init() {
6+
}
7+
8+
public func method() {
9+
print("x: \(x)")
10+
}
11+
12+
public func method2() {
13+
print("x2: \(y)")
14+
}
15+
}
16+
17+
@_assemblyVision
18+
@inline(never)
19+
public func runSomeTest(_ c: C) {
20+
for i in 0..<100 {
21+
c.method()
22+
c.method2()
23+
}
24+
}

0 commit comments

Comments
 (0)