diff --git a/llvm/test/tools/llvm-mca/X86/cv_fpo_directive_no_segfault.s b/llvm/test/tools/llvm-mca/X86/cv_fpo_directive_no_segfault.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-mca/X86/cv_fpo_directive_no_segfault.s @@ -0,0 +1,9 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -resource-pressure=false -instruction-info=false < %s | FileCheck %s + +.cv_fpo_pushreg ebx +add %eax, %eax +add %ebx, %ebx +add %ecx, %ecx +add %edx, %edx + +# CHECK: Iterations: 100 diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h --- a/llvm/tools/llvm-mca/CodeRegionGenerator.h +++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h @@ -39,7 +39,8 @@ public: CodeRegionGenerator(SourceMgr &SM) : Regions(SM) {} virtual ~CodeRegionGenerator(); - virtual Expected parseCodeRegions() = 0; + virtual Expected + parseCodeRegions(const std::unique_ptr &IP) = 0; }; /// This class is responsible for parsing input ASM and generating @@ -60,7 +61,8 @@ AssemblerDialect(0) {} unsigned getAssemblerDialect() const { return AssemblerDialect; } - Expected parseCodeRegions() override; + Expected + parseCodeRegions(const std::unique_ptr &IP) override; }; } // namespace mca diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp --- a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp +++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp @@ -106,11 +106,21 @@ Regions.beginRegion(Comment, Loc); } -Expected AsmCodeRegionGenerator::parseCodeRegions() { +Expected AsmCodeRegionGenerator::parseCodeRegions( + const std::unique_ptr &IP) { MCTargetOptions Opts; Opts.PreserveAsmComments = false; MCStreamerWrapper Str(Ctx, Regions); + // Need to initialize an MCTargetStreamer otherwise + // certain asm directives will cause a segfault. + // Using nulls() so that anything emitted by the MCTagetStreamer + // doesn't show up in the llvm-mca output. + raw_ostream &OSRef = nulls(); + formatted_raw_ostream FOSRef(OSRef); + TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(), + /*IsVerboseAsm=*/true); + // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM // comments. std::unique_ptr Parser( diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp --- a/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/llvm/tools/llvm-mca/llvm-mca.cpp @@ -389,9 +389,28 @@ std::unique_ptr MCIA( TheTarget->createMCInstrAnalysis(MCII.get())); + // Need to initialize an MCInstPrinter as it is + // required for initializing the MCTargetStreamer + // which needs to happen within the CRG.parseCodeRegions() call below. + // Without an MCTargetStreamer, certain assembly directives can trigger a + // segfault. (For example, the .cv_fpo_proc directive on x86 will segfault if + // we don't initialize the MCTargetStreamer.) + unsigned IPtempOutputAsmVariant = + OutputAsmVariant == -1 ? 0 : OutputAsmVariant; + std::unique_ptr IPtemp(TheTarget->createMCInstPrinter( + Triple(TripleName), IPtempOutputAsmVariant, *MAI, *MCII, *MRI)); + if (!IPtemp) { + WithColor::error() + << "unable to create instruction printer for target triple '" + << TheTriple.normalize() << "' with assembly variant " + << IPtempOutputAsmVariant << ".\n"; + return 1; + } + // Parse the input and create CodeRegions that llvm-mca can analyze. mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII); - Expected RegionsOrErr = CRG.parseCodeRegions(); + Expected RegionsOrErr = + CRG.parseCodeRegions(std::move(IPtemp)); if (!RegionsOrErr) { if (auto Err = handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {