Add code to create llvm::RemarkStreamer objects for all the LLVMModules in WMO mode

rdar://154403078
This commit is contained in:
Arnold Schwaighofer
2025-06-27 13:42:25 -07:00
parent 7ddf75c791
commit b30bd40b83
10 changed files with 231 additions and 31 deletions

View File

@@ -316,6 +316,10 @@ public:
/// records. /// records.
std::string OptRecordFile; std::string OptRecordFile;
/// The names of the auxiliar files to which the backend should save optimization
/// records for the remaining (other than the main one) LLVMModules.
std::vector<std::string> AuxOptRecordFiles;
/// The regex that filters the passes that should be saved to the optimization /// The regex that filters the passes that should be saved to the optimization
/// records. /// records.
std::string OptRecordPasses; std::string OptRecordPasses;

View File

@@ -253,6 +253,9 @@ public:
const PrimarySpecificPaths & const PrimarySpecificPaths &
getPrimarySpecificPathsForAtMostOnePrimary() const; getPrimarySpecificPathsForAtMostOnePrimary() const;
const PrimarySpecificPaths &
getPrimarySpecificPathsForRemaining(unsigned i) const;
const PrimarySpecificPaths & const PrimarySpecificPaths &
getPrimarySpecificPathsForPrimary(StringRef) const; getPrimarySpecificPathsForPrimary(StringRef) const;

View File

@@ -298,6 +298,44 @@ SupplementaryOutputPathsComputer::computeOutputPaths() const {
}); });
if (hadError) if (hadError)
return std::nullopt; return std::nullopt;
// In WMO mode compute supplementary output paths for optimization record
// data (opt-remarks). We need one path per LLVMModule that will be created as
// part of wmo.
if (!InputsAndOutputs.hasPrimaryInputs() && OutputFiles.size() > 1) {
unsigned i = 0;
InputsAndOutputs.forEachInput([&](const InputFile &input) -> bool {
// First input is already computed.
if (InputsAndOutputs.firstInput().getFileName() == input.getFileName()) {
++i;
return false;
}
SupplementaryOutputPaths outputs;
// Compute auxiliar opt record paths.
StringRef defaultSupplementaryOutputPathExcludingExtension =
deriveDefaultSupplementaryOutputPathExcludingExtension(OutputFiles[i], input);
auto YAMLOptRecordPath = determineSupplementaryOutputFilename(
options::OPT_save_optimization_record_path,
"",
file_types::TY_YAMLOptRecord, "",
defaultSupplementaryOutputPathExcludingExtension, true);
outputs.YAMLOptRecordPath = YAMLOptRecordPath;
auto bitstreamOptRecordPath = determineSupplementaryOutputFilename(
options::OPT_save_optimization_record_path,
"",
file_types::TY_BitstreamOptRecord, "",
defaultSupplementaryOutputPathExcludingExtension, true);
outputs.BitstreamOptRecordPath = bitstreamOptRecordPath;
outputPaths.emplace_back(std::move(outputs));
++i;
return false;
});
}
return outputPaths; return outputPaths;
} }
@@ -615,7 +653,21 @@ std::string
SupplementaryOutputPathsComputer::determineSupplementaryOutputFilename( SupplementaryOutputPathsComputer::determineSupplementaryOutputFilename(
options::ID emitOpt, std::string pathFromArguments, file_types::ID type, options::ID emitOpt, std::string pathFromArguments, file_types::ID type,
StringRef mainOutputIfUsable, StringRef mainOutputIfUsable,
StringRef defaultSupplementaryOutputPathExcludingExtension) const { StringRef defaultSupplementaryOutputPathExcludingExtension,
bool forceDefaultSupplementaryOutputPathExcludingExtension) const {
auto computeDefaultSupplementaryOutputPathExcludingExtension =
[&] () -> std::string {
llvm::SmallString<128> path(
defaultSupplementaryOutputPathExcludingExtension);
llvm::sys::path::replace_extension(path, file_types::getExtension(type));
return path.str().str();
};
if (forceDefaultSupplementaryOutputPathExcludingExtension) {
return computeDefaultSupplementaryOutputPathExcludingExtension();
}
if (!pathFromArguments.empty()) if (!pathFromArguments.empty())
return pathFromArguments; return pathFromArguments;
@@ -627,9 +679,7 @@ SupplementaryOutputPathsComputer::determineSupplementaryOutputFilename(
return mainOutputIfUsable.str(); return mainOutputIfUsable.str();
} }
llvm::SmallString<128> path(defaultSupplementaryOutputPathExcludingExtension); return computeDefaultSupplementaryOutputPathExcludingExtension();
llvm::sys::path::replace_extension(path, file_types::getExtension(type));
return path.str().str();
} }
void SupplementaryOutputPathsComputer::deriveModulePathParameters( void SupplementaryOutputPathsComputer::deriveModulePathParameters(

View File

@@ -180,7 +180,8 @@ private:
std::string determineSupplementaryOutputFilename( std::string determineSupplementaryOutputFilename(
options::ID emitOpt, std::string pathFromArgumentsOrFilelists, options::ID emitOpt, std::string pathFromArgumentsOrFilelists,
file_types::ID type, StringRef mainOutputIfUsable, file_types::ID type, StringRef mainOutputIfUsable,
StringRef defaultSupplementaryOutputPathExcludingExtension) const; StringRef defaultSupplementaryOutputPathExcludingExtension,
bool forceDefaultSupplementaryOutputPathExcludingExtension = false) const;
void deriveModulePathParameters(StringRef mainOutputFile, void deriveModulePathParameters(StringRef mainOutputFile,
options::ID &emitOption, options::ID &emitOption,

View File

@@ -380,13 +380,23 @@ void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
} }
return; return;
} }
assert(supplementaryOutputs.size() == 1 &&
"WMO only ever produces one set of supplementary outputs"); assert(supplementaryOutputs.size() == 1 ||
supplementaryOutputs.size() == AllInputs.size() &&
"WMO produces wrong number of sets of supplementary outputs");
if (outputFiles.size() == 1) { if (outputFiles.size() == 1) {
AllInputs.front().setPrimarySpecificPaths(PrimarySpecificPaths( for (auto i : indices(AllInputs)) {
outputFiles.front(), outputFilesForIndexUnits.front(), if (i == 0)
firstInputProducingOutput().getFileName(), AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
supplementaryOutputs.front())); outputFiles.front(), outputFilesForIndexUnits.front(),
firstInputProducingOutput().getFileName(),
supplementaryOutputs.front()));
else
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
"", "", "",
supplementaryOutputs.size() == 1 ? SupplementaryOutputPaths()
: supplementaryOutputs[i]));
}
return; return;
} }
assert(outputFiles.size() == AllInputs.size() && assert(outputFiles.size() == AllInputs.size() &&
@@ -394,7 +404,8 @@ void FrontendInputsAndOutputs::setMainAndSupplementaryOutputs(
for (auto i : indices(AllInputs)) for (auto i : indices(AllInputs))
AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths( AllInputs[i].setPrimarySpecificPaths(PrimarySpecificPaths(
outputFiles[i], outputFilesForIndexUnits[i], outputFiles[i], outputFiles[i], outputFilesForIndexUnits[i], outputFiles[i],
i == 0 ? supplementaryOutputs.front() : SupplementaryOutputPaths())); supplementaryOutputs.size() == 1 && i != 0 ? SupplementaryOutputPaths()
: supplementaryOutputs[i]));
} }
std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const { std::vector<std::string> FrontendInputsAndOutputs::copyOutputFilenames() const {
@@ -488,6 +499,14 @@ FrontendInputsAndOutputs::getPrimarySpecificPathsForAtMostOnePrimary() const {
: emptyPaths; : emptyPaths;
} }
const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForRemaining(unsigned i) const {
static auto emptyPaths = PrimarySpecificPaths();
unsigned firstProducingIdx = getIndexOfFirstOutputProducingInput();
return (hasInputs() && i > 0) ?
AllInputs[firstProducingIdx+i].getPrimarySpecificPaths() : emptyPaths;
}
const PrimarySpecificPaths & const PrimarySpecificPaths &
FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary( FrontendInputsAndOutputs::getPrimarySpecificPathsForPrimary(
StringRef filename) const { StringRef filename) const {

View File

@@ -740,7 +740,8 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
const auto &Invocation = Instance.getInvocation(); const auto &Invocation = Instance.getInvocation();
const FrontendOptions &opts = Invocation.getFrontendOptions(); const FrontendOptions &opts = Invocation.getFrontendOptions();
auto getSILOptions = [&](const PrimarySpecificPaths &PSPs) -> SILOptions { auto getSILOptions = [&](const PrimarySpecificPaths &PSPs,
const std::vector<PrimarySpecificPaths> &auxPSPs) -> SILOptions {
SILOptions SILOpts = Invocation.getSILOptions(); SILOptions SILOpts = Invocation.getSILOptions();
if (SILOpts.OptRecordFile.empty()) { if (SILOpts.OptRecordFile.empty()) {
// Check if the record file path was passed via supplemental outputs. // Check if the record file path was passed via supplemental outputs.
@@ -749,6 +750,15 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
PSPs.SupplementaryOutputs.YAMLOptRecordPath : PSPs.SupplementaryOutputs.YAMLOptRecordPath :
PSPs.SupplementaryOutputs.BitstreamOptRecordPath; PSPs.SupplementaryOutputs.BitstreamOptRecordPath;
} }
if (!auxPSPs.empty()) {
assert(SILOpts.AuxOptRecordFiles.empty());
for (const auto &auxFile: auxPSPs) {
SILOpts.AuxOptRecordFiles.push_back(
SILOpts.OptRecordFormat == llvm::remarks::Format::YAML ?
auxFile.SupplementaryOutputs.YAMLOptRecordPath :
auxFile.SupplementaryOutputs.BitstreamOptRecordPath);
}
}
return SILOpts; return SILOpts;
}; };
@@ -758,13 +768,24 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
// SILModule for the entire module. // SILModule for the entire module.
const PrimarySpecificPaths PSPs = const PrimarySpecificPaths PSPs =
Instance.getPrimarySpecificPathsForWholeModuleOptimizationMode(); Instance.getPrimarySpecificPathsForWholeModuleOptimizationMode();
SILOptions SILOpts = getSILOptions(PSPs);
std::vector<PrimarySpecificPaths> auxPSPs;
for (unsigned i = 1; i < opts.InputsAndOutputs.inputCount(); ++i) {
auto &auxPSP =
opts.InputsAndOutputs.getPrimarySpecificPathsForRemaining(i);
auxPSPs.push_back(auxPSP);
}
SILOptions SILOpts = getSILOptions(PSPs, auxPSPs);
IRGenOptions irgenOpts = Invocation.getIRGenOptions(); IRGenOptions irgenOpts = Invocation.getIRGenOptions();
auto SM = performASTLowering(mod, Instance.getSILTypes(), SILOpts, auto SM = performASTLowering(mod, Instance.getSILTypes(), SILOpts,
&irgenOpts); &irgenOpts);
return performCompileStepsPostSILGen(Instance, std::move(SM), mod, PSPs, return performCompileStepsPostSILGen(Instance, std::move(SM), mod, PSPs,
ReturnValue, observer); ReturnValue, observer);
} }
std::vector<PrimarySpecificPaths> emptyAuxPSPs;
// If there are primary source files, build a separate SILModule for // If there are primary source files, build a separate SILModule for
// each source file, and run the remaining SILOpt-Serialize-IRGen-LLVM // each source file, and run the remaining SILOpt-Serialize-IRGen-LLVM
// once for each such input. // once for each such input.
@@ -773,7 +794,7 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) { for (auto *PrimaryFile : Instance.getPrimarySourceFiles()) {
const PrimarySpecificPaths PSPs = const PrimarySpecificPaths PSPs =
Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile); Instance.getPrimarySpecificPathsForSourceFile(*PrimaryFile);
SILOptions SILOpts = getSILOptions(PSPs); SILOptions SILOpts = getSILOptions(PSPs, emptyAuxPSPs);
IRGenOptions irgenOpts = Invocation.getIRGenOptions(); IRGenOptions irgenOpts = Invocation.getIRGenOptions();
auto SM = performASTLowering(*PrimaryFile, Instance.getSILTypes(), auto SM = performASTLowering(*PrimaryFile, Instance.getSILTypes(),
SILOpts, &irgenOpts); SILOpts, &irgenOpts);
@@ -793,7 +814,7 @@ bool swift::performCompileStepsPostSema(CompilerInstance &Instance,
if (opts.InputsAndOutputs.isInputPrimary(SASTF->getFilename())) { if (opts.InputsAndOutputs.isInputPrimary(SASTF->getFilename())) {
const PrimarySpecificPaths &PSPs = const PrimarySpecificPaths &PSPs =
Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename()); Instance.getPrimarySpecificPathsForPrimary(SASTF->getFilename());
SILOptions SILOpts = getSILOptions(PSPs); SILOptions SILOpts = getSILOptions(PSPs, emptyAuxPSPs);
auto SM = performASTLowering(*SASTF, Instance.getSILTypes(), SILOpts); auto SM = performASTLowering(*SASTF, Instance.getSILTypes(), SILOpts);
result |= performCompileStepsPostSILGen(Instance, std::move(SM), mod, result |= performCompileStepsPostSILGen(Instance, std::move(SM), mod,
PSPs, ReturnValue, observer); PSPs, ReturnValue, observer);

View File

@@ -20,6 +20,7 @@
#include "swift/ABI/MetadataValues.h" #include "swift/ABI/MetadataValues.h"
#include "swift/ABI/ObjectFile.h" #include "swift/ABI/ObjectFile.h"
#include "swift/AST/DiagnosticsIRGen.h" #include "swift/AST/DiagnosticsIRGen.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/IRGenOptions.h" #include "swift/AST/IRGenOptions.h"
#include "swift/AST/IRGenRequests.h" #include "swift/AST/IRGenRequests.h"
#include "swift/AST/LinkLibrary.h" #include "swift/AST/LinkLibrary.h"
@@ -71,6 +72,8 @@
#include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Remarks/Remark.h"
#include "llvm/Remarks/RemarkStreamer.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
@@ -1143,7 +1146,7 @@ static void embedBitcode(llvm::Module *M, const IRGenOptions &Opts)
NewUsed->setSection("llvm.metadata"); NewUsed->setSection("llvm.metadata");
} }
static void initLLVMModule(IRGenModule &IGM, SILModule &SIL) { static void initLLVMModule(IRGenModule &IGM, SILModule &SIL, std::optional<unsigned> idx = {}) {
auto *Module = IGM.getModule(); auto *Module = IGM.getModule();
assert(Module && "Expected llvm:Module for IR generation!"); assert(Module && "Expected llvm:Module for IR generation!");
@@ -1186,17 +1189,67 @@ static void initLLVMModule(IRGenModule &IGM, SILModule &SIL) {
llvm::ConstantAsMetadata::get(Value)})); llvm::ConstantAsMetadata::get(Value)}));
if (auto *SILstreamer = SIL.getSILRemarkStreamer()) { if (auto *SILstreamer = SIL.getSILRemarkStreamer()) {
// Install RemarkStreamer into LLVM and keep the remarks file alive. This is auto remarkStream = SILstreamer->releaseStream();
// required even if no LLVM remarks are enabled, because the AsmPrinter if (remarkStream) {
// serializes meta information about the remarks into the object file. // Install RemarkStreamer into LLVM and keep the remarks file alive. This is
IGM.RemarkStream = SILstreamer->releaseStream(); // required even if no LLVM remarks are enabled, because the AsmPrinter
SILstreamer->intoLLVMContext(Context); // serializes meta information about the remarks into the object file.
auto &RS = *IGM.getLLVMContext().getMainRemarkStreamer(); IGM.RemarkStream = std::move(remarkStream);
if (IGM.getOptions().AnnotateCondFailMessage) { SILstreamer->intoLLVMContext(Context);
auto &RS = *IGM.getLLVMContext().getMainRemarkStreamer();
if (IGM.getOptions().AnnotateCondFailMessage) {
Context.setLLVMRemarkStreamer(
std::make_unique<llvm::LLVMRemarkStreamer>(RS));
} else {
// Don't filter for now.
Context.setLLVMRemarkStreamer(
std::make_unique<llvm::LLVMRemarkStreamer>(RS));
}
} else {
assert(idx && "Not generating multiple output files?");
// Construct llvmremarkstreamer objects for LLVM remarks originating in
// the LLVM backend and install it in the remaining LLVMModule(s).
auto &SILOpts = SIL.getOptions();
assert(SILOpts.AuxOptRecordFiles.size() > (*idx - 1));
const auto &filename = SILOpts.AuxOptRecordFiles[*idx - 1];
auto &diagEngine = SIL.getASTContext().Diags;
std::error_code errorCode;
auto file = std::make_unique<llvm::raw_fd_ostream>(filename, errorCode,
llvm::sys::fs::OF_None);
if (errorCode) {
diagEngine.diagnose(SourceLoc(), diag::cannot_open_file, filename,
errorCode.message());
return;
}
const auto format = SILOpts.OptRecordFormat;
llvm::Expected<std::unique_ptr<llvm::remarks::RemarkSerializer>>
remarkSerializerOrErr = llvm::remarks::createRemarkSerializer(
format, llvm::remarks::SerializerMode::Separate, *file);
if (llvm::Error err = remarkSerializerOrErr.takeError()) {
diagEngine.diagnose(SourceLoc(), diag::error_creating_remark_serializer,
toString(std::move(err)));
return;
}
auto auxRS = std::make_unique<llvm::remarks::RemarkStreamer>(
std::move(*remarkSerializerOrErr), filename);
const auto passes = SILOpts.OptRecordPasses;
if (!passes.empty()) {
if (llvm::Error err = auxRS->setFilter(passes)) {
diagEngine.diagnose(SourceLoc(), diag::error_creating_remark_serializer,
toString(std::move(err)));
return ;
}
}
Context.setMainRemarkStreamer(std::move(auxRS));
Context.setLLVMRemarkStreamer( Context.setLLVMRemarkStreamer(
std::make_unique<llvm::LLVMRemarkStreamer>(RS)); std::make_unique<llvm::LLVMRemarkStreamer>(
// FIXME: add a frontend flag to enable all LLVM remarks *Context.getMainRemarkStreamer()));
cantFail(RS.setFilter("annotation-remarks")); IGM.RemarkStream = std::move(file);
} }
} }
} }
@@ -1545,6 +1598,7 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
auto &Ctx = M->getASTContext(); auto &Ctx = M->getASTContext();
// Create an IRGenModule for each source file. // Create an IRGenModule for each source file.
bool DidRunSILCodeGenPreparePasses = false; bool DidRunSILCodeGenPreparePasses = false;
unsigned idx = 0;
for (auto *File : M->getFiles()) { for (auto *File : M->getFiles()) {
auto nextSF = dyn_cast<SourceFile>(File); auto nextSF = dyn_cast<SourceFile>(File);
if (!nextSF) if (!nextSF)
@@ -1561,11 +1615,12 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
if (!targetMachine) continue; if (!targetMachine) continue;
// Create the IR emitter. // Create the IR emitter.
auto outputName = *OutputIter++;
IRGenModule *IGM = new IRGenModule( IRGenModule *IGM = new IRGenModule(
irgen, std::move(targetMachine), nextSF, desc.ModuleName, *OutputIter++, irgen, std::move(targetMachine), nextSF, desc.ModuleName, outputName,
nextSF->getFilename(), nextSF->getPrivateDiscriminator().str()); nextSF->getFilename(), nextSF->getPrivateDiscriminator().str());
initLLVMModule(*IGM, *SILMod); initLLVMModule(*IGM, *SILMod, idx++);
if (!DidRunSILCodeGenPreparePasses) { if (!DidRunSILCodeGenPreparePasses) {
// Run SIL level IRGen preparation passes on the module the first time // Run SIL level IRGen preparation passes on the module the first time
// around. // around.

View File

@@ -0,0 +1,24 @@
open class C {
var x = 1
var y = 2
public init() {
}
public func method() {
print("x: \(x)")
}
public func method2() {
print("x2: \(y)")
}
}
@_assemblyVision
@inline(never)
public func runSomeTest(_ c: C) {
for i in 0..<100 {
c.method()
c.method2()
}
}

View File

@@ -2,11 +2,17 @@
// RUN: echo '"%s": { yaml-opt-record: "%t/foo.opt.yaml" }' > %t/filemap.yaml.yaml // RUN: echo '"%s": { yaml-opt-record: "%t/foo.opt.yaml" }' > %t/filemap.yaml.yaml
// RUN: echo '"%s": { bitstream-opt-record: "%t/foo.opt.bitstream" }' > %t/filemap.bitstream.yaml // RUN: echo '"%s": { bitstream-opt-record: "%t/foo.opt.bitstream" }' > %t/filemap.bitstream.yaml
// RUN: %target-swift-frontend -c -O -wmo -save-optimization-record=bitstream %s -module-name foo -o %t/foo.o -supplementary-output-file-map %t/filemap.bitstream.yaml // RUN: %target-swift-frontend -c -O -num-threads 2 -save-optimization-record=bitstream %s %S/Inputs/opt-record-2.swift -module-name foo -o %t/foo.o -o %t/opt-record-2.o -supplementary-output-file-map %t/filemap.bitstream.yaml
// RUN: llvm-bcanalyzer -dump "%t/foo.opt.bitstream" | %FileCheck -check-prefix=BITSTREAM %s // RUN: llvm-bcanalyzer -dump "%t/foo.opt.bitstream" | %FileCheck -check-prefix=BITSTREAM %s
// RUN: llvm-bcanalyzer -dump "%t/opt-record-2.opt.bitstream" | %FileCheck -check-prefix=BITSTREAM2 %s
// RUN: %target-swift-frontend -c -O -wmo -save-optimization-record=yaml %s -module-name foo -o %t/foo.o -supplementary-output-file-map %t/filemap.yaml.yaml // RUN: %empty-directory(%t)
// RUN: echo '"%s": { yaml-opt-record: "%t/foo.opt.yaml" }' > %t/filemap.yaml.yaml
// RUN: echo '"%s": { bitstream-opt-record: "%t/foo.opt.bitstream" }' > %t/filemap.bitstream.yaml
// RUN: %target-swift-frontend -c -O -num-threads 2 -save-optimization-record=yaml %s %S/Inputs/opt-record-2.swift -module-name foo -o %t/foo.o -o %t/opt-record-2.o -supplementary-output-file-map %t/filemap.yaml.yaml
// RUN: %FileCheck %s -check-prefix=YAML --input-file=%t/foo.opt.yaml // RUN: %FileCheck %s -check-prefix=YAML --input-file=%t/foo.opt.yaml
// RUN: %FileCheck %s -check-prefix=YAML2 --input-file=%t/opt-record-2.opt.yaml
// REQUIRES: VENDOR=apple // REQUIRES: VENDOR=apple
@@ -18,10 +24,19 @@ func foo() {
} }
#sourceLocation() // reset #sourceLocation() // reset
@_assemblyVision
public func bar() { public func bar() {
foo() foo()
runSomeTest(C())
// BITSTREAM: <Remark NumWords=13 BlockCodeSize=4> // BITSTREAM: <Remark NumWords=13 BlockCodeSize=4>
// BITSTREAM: </Remark> // BITSTREAM: </Remark>
// BITSTREAM2: <Remark NumWords={{[0-9]+}} BlockCodeSize={{[0-9]*}}>
// BITSTREAM2: </Remark>
// YAML: sil-assembly-vision-remark-gen // YAML: sil-assembly-vision-remark-gen
// YAML2: Pass: asm-printer
// YAML2: Name: InstructionCount
} }

View File

@@ -36,6 +36,14 @@
// CHECK-NEXT: { // CHECK-NEXT: {
// CHECK-NEXT: "type": "abi-baseline-json", // CHECK-NEXT: "type": "abi-baseline-json",
// CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output_emit_module.swift.tmp.abi.json" // CHECK-NEXT: "path": "{{.*[\\/]}}parseable_output_emit_module.swift.tmp.abi.json"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "type": "yaml-opt-record",
// CHECK-NEXT: "path": "parseable_output_emit_module.opt.yaml"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "type": "bitstream-opt-record",
// CHECK-NEXT: "path": "parseable_output_emit_module.opt.bitstream"
// CHECK-NEXT: } // CHECK-NEXT: }
// CHECK-NEXT: ], // CHECK-NEXT: ],
// CHECK-NEXT: "pid": [[PID:[0-9]*]] // CHECK-NEXT: "pid": [[PID:[0-9]*]]