mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-01 23:06:11 +00:00
[clang-cl] Support the /JMC flag
The introduction and some examples are on this page: https://devblogs.microsoft.com/cppblog/announcing-jmc-stepping-in-visual-studio/ The `/JMC` flag enables these instrumentations: - Insert at the beginning of every function immediately after the prologue with a call to `void __fastcall __CheckForDebuggerJustMyCode(unsigned char *JMC_flag)`. The argument for `__CheckForDebuggerJustMyCode` is the address of a boolean global variable (the global variable is initialized to 1) with the name convention `__<hash>_<filename>`. All such global variables are placed in the `.msvcjmc` section. - The `<hash>` part of `__<hash>_<filename>` has a one-to-one mapping with a directory path. MSVC uses some unknown hashing function. Here I used DJB. - Add a dummy/empty COMDAT function `__JustMyCode_Default`. - Add `/alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default` link option via ".drectve" section. This is to prevent failure in case `__CheckForDebuggerJustMyCode` is not provided during linking. Implementation: All the instrumentations are implemented in an IR codegen pass. The pass is placed immediately before CodeGenPrepare pass. This is to not interfere with mid-end optimizations and make the instrumentation target-independent (I'm still working on an ELF port in a separate patch). Reviewed By: hans Differential Revision: https://reviews.llvm.org/D118428
This commit is contained in:
parent
b96106af3f
commit
bd3a1de683
@ -80,6 +80,12 @@ Attribute Changes in Clang
|
|||||||
Windows Support
|
Windows Support
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
- Add support for MSVC-compatible ``/JMC``/``/JMC-`` flag in clang-cl (supports
|
||||||
|
X86/X64/ARM/ARM64). ``/JMC`` could only be used when ``/Zi`` or ``/Z7`` is
|
||||||
|
turned on. With this addition, clang-cl can be used in Visual Studio for the
|
||||||
|
JustMyCode feature. Note, you may need to manually add ``/JMC`` as additional
|
||||||
|
compile options in the Visual Studio since it currently assumes clang-cl does not support ``/JMC``.
|
||||||
|
|
||||||
C Language Changes in Clang
|
C Language Changes in Clang
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
@ -144,6 +144,7 @@ VALUE_CODEGENOPT(PatchableFunctionEntryOffset , 32, 0)
|
|||||||
CODEGENOPT(HotPatch, 1, 0) ///< Supports the Microsoft /HOTPATCH flag and
|
CODEGENOPT(HotPatch, 1, 0) ///< Supports the Microsoft /HOTPATCH flag and
|
||||||
///< generates a 'patchable-function' attribute.
|
///< generates a 'patchable-function' attribute.
|
||||||
|
|
||||||
|
CODEGENOPT(JMCInstrument, 1, 0) ///< Set when -fjmc is enabled.
|
||||||
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
|
CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled.
|
||||||
CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled.
|
CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled.
|
||||||
CODEGENOPT(MNopMCount , 1, 0) ///< Set when -mnop-mcount is enabled.
|
CODEGENOPT(MNopMCount , 1, 0) ///< Set when -mnop-mcount is enabled.
|
||||||
|
@ -633,4 +633,8 @@ def err_drv_invalid_or_unsupported_offload_target : Error<
|
|||||||
"invalid or unsupported offload target: '%0'">;
|
"invalid or unsupported offload target: '%0'">;
|
||||||
def err_drv_cuda_offload_only_emit_bc : Error<
|
def err_drv_cuda_offload_only_emit_bc : Error<
|
||||||
"CUDA offload target is supported only along with --emit-llvm">;
|
"CUDA offload target is supported only along with --emit-llvm">;
|
||||||
|
|
||||||
|
def warn_drv_jmc_requires_debuginfo : Warning<
|
||||||
|
"/JMC requires debug info. Use '/Zi', '/Z7' or other debug options; option ignored">,
|
||||||
|
InGroup<OptionIgnored>;
|
||||||
}
|
}
|
||||||
|
@ -1446,6 +1446,9 @@ def fno_elide_type : Flag<["-"], "fno-elide-type">, Group<f_Group>,
|
|||||||
HelpText<"Do not elide types when printing diagnostics">,
|
HelpText<"Do not elide types when printing diagnostics">,
|
||||||
MarshallingInfoNegativeFlag<DiagnosticOpts<"ElideType">>;
|
MarshallingInfoNegativeFlag<DiagnosticOpts<"ElideType">>;
|
||||||
def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
|
def feliminate_unused_debug_symbols : Flag<["-"], "feliminate-unused-debug-symbols">, Group<f_Group>;
|
||||||
|
def fjmc : Flag<["-"], "fjmc">, Group<f_Group>,Flags<[CC1Option]>,
|
||||||
|
HelpText<"Enable just-my-code debugging">,
|
||||||
|
MarshallingInfoFlag<CodeGenOpts<"JMCInstrument">>;
|
||||||
defm eliminate_unused_debug_types : OptOutCC1FFlag<"eliminate-unused-debug-types",
|
defm eliminate_unused_debug_types : OptOutCC1FFlag<"eliminate-unused-debug-types",
|
||||||
"Do not emit ", "Emit ", " debug info for defined but unused types">;
|
"Do not emit ", "Emit ", " debug info for defined but unused types">;
|
||||||
def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
|
def femit_all_decls : Flag<["-"], "femit-all-decls">, Group<f_Group>, Flags<[CC1Option]>,
|
||||||
@ -6361,6 +6364,10 @@ def _SLASH_GX_ : CLFlag<"GX-">,
|
|||||||
def _SLASH_imsvc : CLJoinedOrSeparate<"imsvc">,
|
def _SLASH_imsvc : CLJoinedOrSeparate<"imsvc">,
|
||||||
HelpText<"Add <dir> to system include search path, as if in %INCLUDE%">,
|
HelpText<"Add <dir> to system include search path, as if in %INCLUDE%">,
|
||||||
MetaVarName<"<dir>">;
|
MetaVarName<"<dir>">;
|
||||||
|
def _SLASH_JMC : CLFlag<"JMC">,
|
||||||
|
HelpText<"Enable just-my-code debugging">;
|
||||||
|
def _SLASH_JMC_ : CLFlag<"JMC-">,
|
||||||
|
HelpText<"Disable just-my-code debugging (default)">;
|
||||||
def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
|
def _SLASH_LD : CLFlag<"LD">, HelpText<"Create DLL">;
|
||||||
def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
|
def _SLASH_LDd : CLFlag<"LDd">, HelpText<"Create debug DLL">;
|
||||||
def _SLASH_link : CLRemainingArgsJoined<"link">,
|
def _SLASH_link : CLRemainingArgsJoined<"link">,
|
||||||
@ -6461,7 +6468,6 @@ def _SLASH_errorReport : CLIgnoredJoined<"errorReport">;
|
|||||||
def _SLASH_FC : CLIgnoredFlag<"FC">;
|
def _SLASH_FC : CLIgnoredFlag<"FC">;
|
||||||
def _SLASH_Fd : CLIgnoredJoined<"Fd">;
|
def _SLASH_Fd : CLIgnoredJoined<"Fd">;
|
||||||
def _SLASH_FS : CLIgnoredFlag<"FS">;
|
def _SLASH_FS : CLIgnoredFlag<"FS">;
|
||||||
def _SLASH_JMC : CLIgnoredFlag<"JMC">;
|
|
||||||
def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
|
def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
|
||||||
def _SLASH_nologo : CLIgnoredFlag<"nologo">;
|
def _SLASH_nologo : CLIgnoredFlag<"nologo">;
|
||||||
def _SLASH_RTC : CLIgnoredJoined<"RTC">;
|
def _SLASH_RTC : CLIgnoredJoined<"RTC">;
|
||||||
|
@ -606,6 +606,10 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
|
|||||||
Options.EnableAIXExtendedAltivecABI = CodeGenOpts.EnableAIXExtendedAltivecABI;
|
Options.EnableAIXExtendedAltivecABI = CodeGenOpts.EnableAIXExtendedAltivecABI;
|
||||||
Options.XRayOmitFunctionIndex = CodeGenOpts.XRayOmitFunctionIndex;
|
Options.XRayOmitFunctionIndex = CodeGenOpts.XRayOmitFunctionIndex;
|
||||||
Options.LoopAlignment = CodeGenOpts.LoopAlignment;
|
Options.LoopAlignment = CodeGenOpts.LoopAlignment;
|
||||||
|
Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf;
|
||||||
|
Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug;
|
||||||
|
Options.Hotpatch = CodeGenOpts.HotPatch;
|
||||||
|
Options.JMCInstrument = CodeGenOpts.JMCInstrument;
|
||||||
|
|
||||||
switch (CodeGenOpts.getSwiftAsyncFramePointer()) {
|
switch (CodeGenOpts.getSwiftAsyncFramePointer()) {
|
||||||
case CodeGenOptions::SwiftAsyncFramePointerKind::Auto:
|
case CodeGenOptions::SwiftAsyncFramePointerKind::Auto:
|
||||||
@ -644,9 +648,6 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
|
|||||||
Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
|
Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
|
||||||
Options.MCOptions.Argv0 = CodeGenOpts.Argv0;
|
Options.MCOptions.Argv0 = CodeGenOpts.Argv0;
|
||||||
Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs;
|
Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs;
|
||||||
Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf;
|
|
||||||
Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug;
|
|
||||||
Options.Hotpatch = CodeGenOpts.HotPatch;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7489,6 +7489,16 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Driver &D = getToolChain().getDriver();
|
const Driver &D = getToolChain().getDriver();
|
||||||
|
|
||||||
|
// This controls whether or not we perform JustMyCode instrumentation.
|
||||||
|
if (Args.hasFlag(options::OPT__SLASH_JMC, options::OPT__SLASH_JMC_,
|
||||||
|
/*Default=*/false)) {
|
||||||
|
if (*EmitCodeView && *DebugInfoKind >= codegenoptions::DebugInfoConstructor)
|
||||||
|
CmdArgs.push_back("-fjmc");
|
||||||
|
else
|
||||||
|
D.Diag(clang::diag::warn_drv_jmc_requires_debuginfo);
|
||||||
|
}
|
||||||
|
|
||||||
EHFlags EH = parseClangCLEHFlags(D, Args);
|
EHFlags EH = parseClangCLEHFlags(D, Args);
|
||||||
if (!isNVPTX && (EH.Synch || EH.Asynch)) {
|
if (!isNVPTX && (EH.Synch || EH.Asynch)) {
|
||||||
if (types::isCXX(InputType))
|
if (types::isCXX(InputType))
|
||||||
|
@ -486,7 +486,6 @@
|
|||||||
// RUN: /GZ \
|
// RUN: /GZ \
|
||||||
// RUN: /H \
|
// RUN: /H \
|
||||||
// RUN: /homeparams \
|
// RUN: /homeparams \
|
||||||
// RUN: /JMC \
|
|
||||||
// RUN: /kernel \
|
// RUN: /kernel \
|
||||||
// RUN: /LN \
|
// RUN: /LN \
|
||||||
// RUN: /MP \
|
// RUN: /MP \
|
||||||
@ -777,4 +776,14 @@
|
|||||||
// RUN: %clang_cl -target i686-pc-windows-msvc19.14.0 -### -- %s 2>&1 | FileCheck -check-prefix=TARGET %s
|
// RUN: %clang_cl -target i686-pc-windows-msvc19.14.0 -### -- %s 2>&1 | FileCheck -check-prefix=TARGET %s
|
||||||
// TARGET: "-triple" "i686-pc-windows-msvc19.14.0"
|
// TARGET: "-triple" "i686-pc-windows-msvc19.14.0"
|
||||||
|
|
||||||
|
// RUN: %clang_cl /JMC /c -### -- %s 2>&1 | FileCheck %s --check-prefix JMCWARN
|
||||||
|
// JMCWARN: /JMC requires debug info. Use '/Zi', '/Z7' or other debug options; option ignored
|
||||||
|
|
||||||
|
// RUN: %clang_cl /JMC /c -### -- %s 2>&1 | FileCheck %s --check-prefix NOJMC
|
||||||
|
// RUN: %clang_cl /JMC /Z7 /JMC- /c -### -- %s 2>&1 | FileCheck %s --check-prefix NOJMC
|
||||||
|
// NOJMC-NOT: -fjmc
|
||||||
|
|
||||||
|
// RUN: %clang_cl /JMC /Z7 /c -### -- %s 2>&1 | FileCheck %s --check-prefix JMC
|
||||||
|
// JMC: -fjmc
|
||||||
|
|
||||||
void f(void) { }
|
void f(void) { }
|
||||||
|
@ -142,6 +142,8 @@ bool getDebugStrictDwarf();
|
|||||||
|
|
||||||
unsigned getAlignLoops();
|
unsigned getAlignLoops();
|
||||||
|
|
||||||
|
bool getJMCInstrument();
|
||||||
|
|
||||||
/// Create this object with static storage to register codegen-related command
|
/// Create this object with static storage to register codegen-related command
|
||||||
/// line options.
|
/// line options.
|
||||||
struct RegisterCodeGenFlags {
|
struct RegisterCodeGenFlags {
|
||||||
|
@ -554,6 +554,9 @@ namespace llvm {
|
|||||||
/// When learning an eviction policy, extract score(reward) information,
|
/// When learning an eviction policy, extract score(reward) information,
|
||||||
/// otherwise this does nothing
|
/// otherwise this does nothing
|
||||||
FunctionPass *createRegAllocScoringPass();
|
FunctionPass *createRegAllocScoringPass();
|
||||||
|
|
||||||
|
/// JMC instrument pass.
|
||||||
|
ModulePass *createJMCInstrumenterPass();
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -215,6 +215,7 @@ void initializeInterleavedAccessPass(PassRegistry&);
|
|||||||
void initializeInterleavedLoadCombinePass(PassRegistry &);
|
void initializeInterleavedLoadCombinePass(PassRegistry &);
|
||||||
void initializeInternalizeLegacyPassPass(PassRegistry&);
|
void initializeInternalizeLegacyPassPass(PassRegistry&);
|
||||||
void initializeIntervalPartitionPass(PassRegistry&);
|
void initializeIntervalPartitionPass(PassRegistry&);
|
||||||
|
void initializeJMCInstrumenterPass(PassRegistry&);
|
||||||
void initializeJumpThreadingPass(PassRegistry&);
|
void initializeJumpThreadingPass(PassRegistry&);
|
||||||
void initializeLCSSAVerificationPassPass(PassRegistry&);
|
void initializeLCSSAVerificationPassPass(PassRegistry&);
|
||||||
void initializeLCSSAWrapperPassPass(PassRegistry&);
|
void initializeLCSSAWrapperPassPass(PassRegistry&);
|
||||||
|
@ -123,6 +123,7 @@ namespace {
|
|||||||
(void) llvm::createInstSimplifyLegacyPass();
|
(void) llvm::createInstSimplifyLegacyPass();
|
||||||
(void) llvm::createInstructionCombiningPass();
|
(void) llvm::createInstructionCombiningPass();
|
||||||
(void) llvm::createInternalizePass();
|
(void) llvm::createInternalizePass();
|
||||||
|
(void) llvm::createJMCInstrumenterPass();
|
||||||
(void) llvm::createLCSSAPass();
|
(void) llvm::createLCSSAPass();
|
||||||
(void) llvm::createLegacyDivergenceAnalysisPass();
|
(void) llvm::createLegacyDivergenceAnalysisPass();
|
||||||
(void) llvm::createLICMPass();
|
(void) llvm::createLICMPass();
|
||||||
|
@ -142,7 +142,7 @@ namespace llvm {
|
|||||||
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
|
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
|
||||||
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
|
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
|
||||||
XRayOmitFunctionIndex(false), DebugStrictDwarf(false),
|
XRayOmitFunctionIndex(false), DebugStrictDwarf(false),
|
||||||
Hotpatch(false), PPCGenScalarMASSEntries(false),
|
Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false),
|
||||||
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
|
FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {}
|
||||||
|
|
||||||
/// DisableFramePointerElim - This returns true if frame pointer elimination
|
/// DisableFramePointerElim - This returns true if frame pointer elimination
|
||||||
@ -348,6 +348,9 @@ namespace llvm {
|
|||||||
/// Enables scalar MASS conversions
|
/// Enables scalar MASS conversions
|
||||||
unsigned PPCGenScalarMASSEntries : 1;
|
unsigned PPCGenScalarMASSEntries : 1;
|
||||||
|
|
||||||
|
/// Enable JustMyCode instrumentation.
|
||||||
|
unsigned JMCInstrument : 1;
|
||||||
|
|
||||||
/// Name of the stack usage file (i.e., .su file) if user passes
|
/// Name of the stack usage file (i.e., .su file) if user passes
|
||||||
/// -fstack-usage. If empty, it can be implied that -fstack-usage is not
|
/// -fstack-usage. If empty, it can be implied that -fstack-usage is not
|
||||||
/// passed on the command line.
|
/// passed on the command line.
|
||||||
|
@ -75,6 +75,7 @@ add_llvm_component_library(LLVMCodeGen
|
|||||||
InterleavedAccessPass.cpp
|
InterleavedAccessPass.cpp
|
||||||
InterleavedLoadCombinePass.cpp
|
InterleavedLoadCombinePass.cpp
|
||||||
IntrinsicLowering.cpp
|
IntrinsicLowering.cpp
|
||||||
|
JMCInstrumenter.cpp
|
||||||
LatencyPriorityQueue.cpp
|
LatencyPriorityQueue.cpp
|
||||||
LazyMachineBlockFrequencyInfo.cpp
|
LazyMachineBlockFrequencyInfo.cpp
|
||||||
LexicalScopes.cpp
|
LexicalScopes.cpp
|
||||||
|
@ -50,6 +50,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
|
|||||||
initializeIndirectBrExpandPassPass(Registry);
|
initializeIndirectBrExpandPassPass(Registry);
|
||||||
initializeInterleavedLoadCombinePass(Registry);
|
initializeInterleavedLoadCombinePass(Registry);
|
||||||
initializeInterleavedAccessPass(Registry);
|
initializeInterleavedAccessPass(Registry);
|
||||||
|
initializeJMCInstrumenterPass(Registry);
|
||||||
initializeLiveDebugValuesPass(Registry);
|
initializeLiveDebugValuesPass(Registry);
|
||||||
initializeLiveDebugVariablesPass(Registry);
|
initializeLiveDebugVariablesPass(Registry);
|
||||||
initializeLiveIntervalsPass(Registry);
|
initializeLiveIntervalsPass(Registry);
|
||||||
|
@ -95,6 +95,7 @@ CGOPT(bool, ForceDwarfFrameSection)
|
|||||||
CGOPT(bool, XRayOmitFunctionIndex)
|
CGOPT(bool, XRayOmitFunctionIndex)
|
||||||
CGOPT(bool, DebugStrictDwarf)
|
CGOPT(bool, DebugStrictDwarf)
|
||||||
CGOPT(unsigned, AlignLoops)
|
CGOPT(unsigned, AlignLoops)
|
||||||
|
CGOPT(bool, JMCInstrument)
|
||||||
|
|
||||||
codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
|
codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
|
||||||
#define CGBINDOPT(NAME) \
|
#define CGBINDOPT(NAME) \
|
||||||
@ -464,6 +465,12 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
|
|||||||
cl::desc("Default alignment for loops"));
|
cl::desc("Default alignment for loops"));
|
||||||
CGBINDOPT(AlignLoops);
|
CGBINDOPT(AlignLoops);
|
||||||
|
|
||||||
|
static cl::opt<bool> JMCInstrument(
|
||||||
|
"enable-jmc-instrument",
|
||||||
|
cl::desc("Instrument functions with a call to __CheckForDebuggerJustMyCode"),
|
||||||
|
cl::init(false));
|
||||||
|
CGBINDOPT(JMCInstrument);
|
||||||
|
|
||||||
#undef CGBINDOPT
|
#undef CGBINDOPT
|
||||||
|
|
||||||
mc::RegisterMCTargetOptionsFlags();
|
mc::RegisterMCTargetOptionsFlags();
|
||||||
@ -539,6 +546,7 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
|
|||||||
Options.XRayOmitFunctionIndex = getXRayOmitFunctionIndex();
|
Options.XRayOmitFunctionIndex = getXRayOmitFunctionIndex();
|
||||||
Options.DebugStrictDwarf = getDebugStrictDwarf();
|
Options.DebugStrictDwarf = getDebugStrictDwarf();
|
||||||
Options.LoopAlignment = getAlignLoops();
|
Options.LoopAlignment = getAlignLoops();
|
||||||
|
Options.JMCInstrument = getJMCInstrument();
|
||||||
|
|
||||||
Options.MCOptions = mc::InitMCTargetOptionsFromFlags();
|
Options.MCOptions = mc::InitMCTargetOptionsFromFlags();
|
||||||
|
|
||||||
|
207
llvm/lib/CodeGen/JMCInstrumenter.cpp
Normal file
207
llvm/lib/CodeGen/JMCInstrumenter.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
//===- JMCInstrumenter.cpp - JMC Instrumentation --------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// JMCInstrumenter pass:
|
||||||
|
// - add "/alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default" to
|
||||||
|
// "llvm.linker.options"
|
||||||
|
// - create the dummy COMDAT function __JustMyCode_Default
|
||||||
|
// - instrument each function with a call to __CheckForDebuggerJustMyCode. The
|
||||||
|
// sole argument should be defined in .msvcjmc. Each flag is 1 byte initilized
|
||||||
|
// to 1.
|
||||||
|
// - (TODO) currently targeting MSVC, adds ELF debuggers support
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
#include "llvm/CodeGen/Passes.h"
|
||||||
|
#include "llvm/IR/DIBuilder.h"
|
||||||
|
#include "llvm/IR/DebugInfoMetadata.h"
|
||||||
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/IR/Instructions.h"
|
||||||
|
#include "llvm/IR/LLVMContext.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/IR/Type.h"
|
||||||
|
#include "llvm/InitializePasses.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "llvm/Support/DJB.h"
|
||||||
|
#include "llvm/Support/Path.h"
|
||||||
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "jmc-instrument"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct JMCInstrumenter : public ModulePass {
|
||||||
|
static char ID;
|
||||||
|
JMCInstrumenter() : ModulePass(ID) {
|
||||||
|
initializeJMCInstrumenterPass(*PassRegistry::getPassRegistry());
|
||||||
|
}
|
||||||
|
bool runOnModule(Module &M) override;
|
||||||
|
};
|
||||||
|
char JMCInstrumenter::ID = 0;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
INITIALIZE_PASS(
|
||||||
|
JMCInstrumenter, DEBUG_TYPE,
|
||||||
|
"Instrument function entry with call to __CheckForDebuggerJustMyCode",
|
||||||
|
false, false)
|
||||||
|
|
||||||
|
ModulePass *llvm::createJMCInstrumenterPass() { return new JMCInstrumenter(); }
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char CheckFunctionName[] = "__CheckForDebuggerJustMyCode";
|
||||||
|
|
||||||
|
std::string getFlagName(DISubprogram &SP, bool UseX86FastCall) {
|
||||||
|
// Best effort path normalization. This is to guarantee an unique flag symbol
|
||||||
|
// is produced for the same directory. Some builds may want to use relative
|
||||||
|
// paths, or paths with a specific prefix (see the -fdebug-compilation-dir
|
||||||
|
// flag), so only hash paths in debuginfo. Don't expand them to absolute
|
||||||
|
// paths.
|
||||||
|
SmallString<256> FilePath(SP.getDirectory());
|
||||||
|
sys::path::append(FilePath, SP.getFilename());
|
||||||
|
sys::path::native(FilePath);
|
||||||
|
sys::path::remove_dots(FilePath, /*remove_dot_dot=*/true);
|
||||||
|
|
||||||
|
// The naming convention for the flag name is __<hash>_<file name> with '.' in
|
||||||
|
// <file name> replaced with '@'. For example C:\file.any.c would have a flag
|
||||||
|
// __D032E919_file@any@c. The naming convention match MSVC's format however
|
||||||
|
// the match is not required to make JMC work. The hashing function used here
|
||||||
|
// is different from MSVC's.
|
||||||
|
|
||||||
|
std::string Suffix;
|
||||||
|
for (auto C : sys::path::filename(FilePath))
|
||||||
|
Suffix.push_back(C == '.' ? '@' : C);
|
||||||
|
|
||||||
|
sys::path::remove_filename(FilePath);
|
||||||
|
return (UseX86FastCall ? "_" : "__") +
|
||||||
|
utohexstr(djbHash(FilePath), /*LowerCase=*/false,
|
||||||
|
/*Width=*/8) +
|
||||||
|
"_" + Suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachDebugInfo(GlobalVariable &GV, DISubprogram &SP) {
|
||||||
|
Module &M = *GV.getParent();
|
||||||
|
DICompileUnit *CU = SP.getUnit();
|
||||||
|
assert(CU);
|
||||||
|
DIBuilder DB(M, false, CU);
|
||||||
|
|
||||||
|
auto *DType =
|
||||||
|
DB.createBasicType("unsigned char", 8, dwarf::DW_ATE_unsigned_char,
|
||||||
|
llvm::DINode::FlagArtificial);
|
||||||
|
|
||||||
|
auto *DGVE = DB.createGlobalVariableExpression(
|
||||||
|
CU, GV.getName(), /*LinkageName=*/StringRef(), SP.getFile(),
|
||||||
|
/*LineNo=*/0, DType, /*IsLocalToUnit=*/true, /*IsDefined=*/true);
|
||||||
|
GV.addMetadata(LLVMContext::MD_dbg, *DGVE);
|
||||||
|
DB.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionType *getCheckFunctionType(LLVMContext &Ctx) {
|
||||||
|
Type *VoidTy = Type::getVoidTy(Ctx);
|
||||||
|
PointerType *VoidPtrTy = Type::getInt8PtrTy(Ctx);
|
||||||
|
return FunctionType::get(VoidTy, VoidPtrTy, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createDefaultCheckFunction(Module &M, bool UseX86FastCall) {
|
||||||
|
LLVMContext &Ctx = M.getContext();
|
||||||
|
const char *DefaultCheckFunctionName =
|
||||||
|
UseX86FastCall ? "_JustMyCode_Default" : "__JustMyCode_Default";
|
||||||
|
// Create the function.
|
||||||
|
Function *DefaultCheckFunc =
|
||||||
|
Function::Create(getCheckFunctionType(Ctx), GlobalValue::ExternalLinkage,
|
||||||
|
DefaultCheckFunctionName, &M);
|
||||||
|
DefaultCheckFunc->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||||
|
DefaultCheckFunc->addParamAttr(0, Attribute::NoUndef);
|
||||||
|
if (UseX86FastCall)
|
||||||
|
DefaultCheckFunc->addParamAttr(0, Attribute::InReg);
|
||||||
|
appendToUsed(M, {DefaultCheckFunc});
|
||||||
|
Comdat *C = M.getOrInsertComdat(DefaultCheckFunctionName);
|
||||||
|
C->setSelectionKind(Comdat::Any);
|
||||||
|
DefaultCheckFunc->setComdat(C);
|
||||||
|
BasicBlock *EntryBB = BasicBlock::Create(Ctx, "", DefaultCheckFunc);
|
||||||
|
ReturnInst::Create(Ctx, EntryBB);
|
||||||
|
|
||||||
|
// Add a linker option /alternatename to set the default implementation for
|
||||||
|
// the check function.
|
||||||
|
// https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024
|
||||||
|
std::string AltOption = std::string("/alternatename:") + CheckFunctionName +
|
||||||
|
"=" + DefaultCheckFunctionName;
|
||||||
|
llvm::Metadata *Ops[] = {llvm::MDString::get(Ctx, AltOption)};
|
||||||
|
MDTuple *N = MDNode::get(Ctx, Ops);
|
||||||
|
M.getOrInsertNamedMetadata("llvm.linker.options")->addOperand(N);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool JMCInstrumenter::runOnModule(Module &M) {
|
||||||
|
bool Changed = false;
|
||||||
|
LLVMContext &Ctx = M.getContext();
|
||||||
|
Triple ModuleTriple(M.getTargetTriple());
|
||||||
|
bool UseX86FastCall =
|
||||||
|
ModuleTriple.isOSWindows() && ModuleTriple.getArch() == Triple::x86;
|
||||||
|
|
||||||
|
Function *CheckFunction = nullptr;
|
||||||
|
DenseMap<DISubprogram *, Constant *> SavedFlags(8);
|
||||||
|
for (auto &F : M) {
|
||||||
|
if (F.isDeclaration())
|
||||||
|
continue;
|
||||||
|
auto *SP = F.getSubprogram();
|
||||||
|
if (!SP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Constant *&Flag = SavedFlags[SP];
|
||||||
|
if (!Flag) {
|
||||||
|
std::string FlagName = getFlagName(*SP, UseX86FastCall);
|
||||||
|
IntegerType *FlagTy = Type::getInt8Ty(Ctx);
|
||||||
|
Flag = M.getOrInsertGlobal(FlagName, FlagTy, [&] {
|
||||||
|
// FIXME: Put the GV in comdat and have linkonce_odr linkage to save
|
||||||
|
// .msvcjmc section space? maybe not worth it.
|
||||||
|
GlobalVariable *GV = new GlobalVariable(
|
||||||
|
M, FlagTy, /*isConstant=*/false, GlobalValue::InternalLinkage,
|
||||||
|
ConstantInt::get(FlagTy, 1), FlagName);
|
||||||
|
GV->setSection(".msvcjmc");
|
||||||
|
GV->setAlignment(Align(1));
|
||||||
|
GV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||||
|
attachDebugInfo(*GV, *SP);
|
||||||
|
return GV;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckFunction) {
|
||||||
|
assert(!M.getFunction(CheckFunctionName) &&
|
||||||
|
"JMC instrument more than once?");
|
||||||
|
CheckFunction = cast<Function>(
|
||||||
|
M.getOrInsertFunction(CheckFunctionName, getCheckFunctionType(Ctx))
|
||||||
|
.getCallee());
|
||||||
|
CheckFunction->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||||
|
CheckFunction->addParamAttr(0, Attribute::NoUndef);
|
||||||
|
if (UseX86FastCall) {
|
||||||
|
CheckFunction->setCallingConv(CallingConv::X86_FastCall);
|
||||||
|
CheckFunction->addParamAttr(0, Attribute::InReg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: it would be nice to make CI scheduling boundary, although in
|
||||||
|
// practice it does not matter much.
|
||||||
|
auto *CI = CallInst::Create(CheckFunction, {Flag}, "",
|
||||||
|
&*F.begin()->getFirstInsertionPt());
|
||||||
|
CI->addParamAttr(0, Attribute::NoUndef);
|
||||||
|
if (UseX86FastCall) {
|
||||||
|
CI->setCallingConv(CallingConv::X86_FastCall);
|
||||||
|
CI->addParamAttr(0, Attribute::InReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Changed = true;
|
||||||
|
}
|
||||||
|
if (!Changed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
createDefaultCheckFunction(M, UseX86FastCall);
|
||||||
|
return true;
|
||||||
|
}
|
@ -574,6 +574,9 @@ void AArch64PassConfig::addIRPasses() {
|
|||||||
// Add Control Flow Guard checks.
|
// Add Control Flow Guard checks.
|
||||||
if (TM->getTargetTriple().isOSWindows())
|
if (TM->getTargetTriple().isOSWindows())
|
||||||
addPass(createCFGuardCheckPass());
|
addPass(createCFGuardCheckPass());
|
||||||
|
|
||||||
|
if (TM->Options.JMCInstrument)
|
||||||
|
addPass(createJMCInstrumenterPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass Pipeline Configuration
|
// Pass Pipeline Configuration
|
||||||
|
@ -434,6 +434,9 @@ void ARMPassConfig::addIRPasses() {
|
|||||||
// Add Control Flow Guard checks.
|
// Add Control Flow Guard checks.
|
||||||
if (TM->getTargetTriple().isOSWindows())
|
if (TM->getTargetTriple().isOSWindows())
|
||||||
addPass(createCFGuardCheckPass());
|
addPass(createCFGuardCheckPass());
|
||||||
|
|
||||||
|
if (TM->Options.JMCInstrument)
|
||||||
|
addPass(createJMCInstrumenterPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMPassConfig::addCodeGenPrepare() {
|
void ARMPassConfig::addCodeGenPrepare() {
|
||||||
|
@ -441,6 +441,9 @@ void X86PassConfig::addIRPasses() {
|
|||||||
addPass(createCFGuardCheckPass());
|
addPass(createCFGuardCheckPass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TM->Options.JMCInstrument)
|
||||||
|
addPass(createJMCInstrumenterPass());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X86PassConfig::addInstSelector() {
|
bool X86PassConfig::addInstSelector() {
|
||||||
|
53
llvm/test/Instrumentation/JustMyCode/jmc-instrument-x86.ll
Normal file
53
llvm/test/Instrumentation/JustMyCode/jmc-instrument-x86.ll
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
; RUN: opt -jmc-instrument -S < %s | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: $_JustMyCode_Default = comdat any
|
||||||
|
|
||||||
|
; CHECK: @"_A85D9D03_x@c" = internal unnamed_addr global i8 1, section ".msvcjmc", align 1, !dbg !0
|
||||||
|
; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void (i8*)* @_JustMyCode_Default to i8*)], section "llvm.metadata"
|
||||||
|
|
||||||
|
; CHECK: define void @w1() #0 !dbg !10 {
|
||||||
|
; CHECK: call x86_fastcallcc void @__CheckForDebuggerJustMyCode(i8* inreg noundef @"_A85D9D03_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: declare x86_fastcallcc void @__CheckForDebuggerJustMyCode(i8* inreg noundef) unnamed_addr
|
||||||
|
|
||||||
|
; CHECK: define void @_JustMyCode_Default(i8* inreg noundef %0) unnamed_addr comdat {
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
|
||||||
|
; CHECK: !1 = distinct !DIGlobalVariable(name: "_A85D9D03_x@c", scope: !2, file: !3, type: !5, isLocal: true, isDefinition: true)
|
||||||
|
; CHECK: !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
; CHECK: !3 = !DIFile(filename: "./b/./../b/x.c", directory: "C:\\\\a\\\\")
|
||||||
|
; CHECK: !4 = !{!0}
|
||||||
|
; CHECK: !5 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char, flags: DIFlagArtificial)
|
||||||
|
; CHECK: !6 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
; CHECK: !7 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
; CHECK: !8 = !{!"clang"}
|
||||||
|
; CHECK: !9 = !{!"/alternatename:__CheckForDebuggerJustMyCode=_JustMyCode_Default"}
|
||||||
|
; CHECK: !10 = distinct !DISubprogram(name: "w1", scope: !3, file: !3, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !13)
|
||||||
|
; CHECK: !11 = !DISubroutineType(types: !12)
|
||||||
|
|
||||||
|
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32-a:0:32-S32"
|
||||||
|
target triple = "i386-pc-windows-msvc"
|
||||||
|
|
||||||
|
define void @w1() #0 !dbg !10 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!7, !8}
|
||||||
|
!llvm.ident = !{!9}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "./b/./../b/x.c", directory: "C:\\\\a\\\\")
|
||||||
|
!7 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
!8 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!9 = !{!"clang"}
|
||||||
|
!10 = distinct !DISubprogram(name: "w1", scope: !1, file: !1, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!31 = !DISubroutineType(types: !32)
|
||||||
|
!32 = !{null}
|
||||||
|
!33 = !{}
|
120
llvm/test/Instrumentation/JustMyCode/jmc-instrument.ll
Normal file
120
llvm/test/Instrumentation/JustMyCode/jmc-instrument.ll
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
; RUN: opt -jmc-instrument -mtriple=x86_64-pc-windows-msvc -S < %s | FileCheck %s
|
||||||
|
; RUN: opt -jmc-instrument -mtriple=aarch64-pc-windows-msvc -S < %s | FileCheck %s
|
||||||
|
; RUN: opt -jmc-instrument -mtriple=arm-pc-windows-msvc -S < %s | FileCheck %s
|
||||||
|
|
||||||
|
; CHECK: $__JustMyCode_Default = comdat any
|
||||||
|
|
||||||
|
; CHECK: @"__7DF23CF5_x@c" = internal unnamed_addr global i8 1, section ".msvcjmc", align 1, !dbg !0
|
||||||
|
; CHECK: @"__A85D9D03_x@c" = internal unnamed_addr global i8 1, section ".msvcjmc", align 1, !dbg !5
|
||||||
|
; CHECK: @llvm.used = appending global [1 x i8*] [i8* bitcast (void (i8*)* @__JustMyCode_Default to i8*)], section "llvm.metadata"
|
||||||
|
|
||||||
|
; CHECK: define void @l1() !dbg !13 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__7DF23CF5_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: define void @l2() !dbg !17 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__7DF23CF5_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: define void @w1() !dbg !19 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__A85D9D03_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: define void @w2() !dbg !20 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__A85D9D03_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: define void @w3() !dbg !22 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__A85D9D03_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: define void @w4() !dbg !24 {
|
||||||
|
; CHECK: call void @__CheckForDebuggerJustMyCode(i8* noundef @"__A85D9D03_x@c")
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: declare void @__CheckForDebuggerJustMyCode(i8* noundef) unnamed_addr
|
||||||
|
|
||||||
|
; CHECK: define void @__JustMyCode_Default(i8* noundef %0) unnamed_addr comdat {
|
||||||
|
; CHECK: ret void
|
||||||
|
; CHECK: }
|
||||||
|
|
||||||
|
; CHECK: !llvm.linker.options = !{!12}
|
||||||
|
|
||||||
|
; CHECK: !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
|
||||||
|
; CHECK: !1 = distinct !DIGlobalVariable(name: "__7DF23CF5_x@c", scope: !2, file: !3, type: !8, isLocal: true, isDefinition: true)
|
||||||
|
; CHECK: !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
; CHECK: !3 = !DIFile(filename: "a/x.c", directory: "/tmp")
|
||||||
|
; CHECK: !4 = !{!0, !5}
|
||||||
|
; CHECK: !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
|
||||||
|
; CHECK: !6 = distinct !DIGlobalVariable(name: "__A85D9D03_x@c", scope: !2, file: !7, type: !8, isLocal: true, isDefinition: true)
|
||||||
|
; CHECK: !7 = !DIFile(filename: "./x.c", directory: "C:\\\\a\\\\b\\\\")
|
||||||
|
; CHECK: !8 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char, flags: DIFlagArtificial)
|
||||||
|
; CHECK: !9 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
; CHECK: !10 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
; CHECK: !11 = !{!"clang"}
|
||||||
|
; CHECK: !12 = !{!"/alternatename:__CheckForDebuggerJustMyCode=__JustMyCode_Default"}
|
||||||
|
; CHECK: !13 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !14 = !DISubroutineType(types: !15)
|
||||||
|
; CHECK: !15 = !{null}
|
||||||
|
; CHECK: !16 = !{}
|
||||||
|
; CHECK: !17 = distinct !DISubprogram(name: "f", scope: !18, file: !18, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !18 = !DIFile(filename: "x.c", directory: "/tmp/a")
|
||||||
|
; CHECK: !19 = distinct !DISubprogram(name: "f", scope: !7, file: !7, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !20 = distinct !DISubprogram(name: "f", scope: !21, file: !21, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !21 = !DIFile(filename: "./b\\x.c", directory: "C:\\\\a\\\\")
|
||||||
|
; CHECK: !22 = distinct !DISubprogram(name: "f", scope: !23, file: !23, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !23 = !DIFile(filename: "./b/x.c", directory: "C:\\\\a\\\\")
|
||||||
|
; CHECK: !24 = distinct !DISubprogram(name: "f", scope: !25, file: !25, line: 1, type: !14, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !16)
|
||||||
|
; CHECK: !25 = !DIFile(filename: "./b/./../b/x.c", directory: "C:\\\\a")
|
||||||
|
|
||||||
|
; All use the same flag
|
||||||
|
define void @l1() !dbg !10 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @l2() !dbg !11 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; All use the same flag
|
||||||
|
define void @w1() !dbg !12 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @w2() !dbg !13 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @w3() !dbg !14 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
define void @w4() !dbg !15 {
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
!llvm.dbg.cu = !{!0}
|
||||||
|
!llvm.module.flags = !{!7, !8}
|
||||||
|
!llvm.ident = !{!9}
|
||||||
|
|
||||||
|
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
|
||||||
|
!1 = !DIFile(filename: "a/x.c", directory: "/tmp")
|
||||||
|
!2 = !DIFile(filename: "x.c", directory: "/tmp/a")
|
||||||
|
!3 = !DIFile(filename: "./x.c", directory: "C:\\\\a\\\\b\\\\")
|
||||||
|
!4 = !DIFile(filename: "./b\\x.c", directory: "C:\\\\a\\\\")
|
||||||
|
!5 = !DIFile(filename: "./b/x.c", directory: "C:\\\\a\\\\")
|
||||||
|
!6 = !DIFile(filename: "./b/./../b/x.c", directory: "C:\\\\a")
|
||||||
|
!7 = !{i32 2, !"CodeView", i32 1}
|
||||||
|
!8 = !{i32 2, !"Debug Info Version", i32 3}
|
||||||
|
!9 = !{!"clang"}
|
||||||
|
!10 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!11 = distinct !DISubprogram(name: "f", scope: !2, file: !2, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!12 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!13 = distinct !DISubprogram(name: "f", scope: !4, file: !4, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!14 = distinct !DISubprogram(name: "f", scope: !5, file: !5, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!15 = distinct !DISubprogram(name: "f", scope: !6, file: !6, line: 1, type: !31, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !33)
|
||||||
|
!31 = !DISubroutineType(types: !32)
|
||||||
|
!32 = !{null}
|
||||||
|
!33 = !{}
|
@ -498,7 +498,8 @@ static bool shouldPinPassToLegacyPM(StringRef Pass) {
|
|||||||
"generic-to-nvvm", "expandmemcmp",
|
"generic-to-nvvm", "expandmemcmp",
|
||||||
"loop-reduce", "lower-amx-type",
|
"loop-reduce", "lower-amx-type",
|
||||||
"pre-amx-config", "lower-amx-intrinsics",
|
"pre-amx-config", "lower-amx-intrinsics",
|
||||||
"polyhedral-info", "replace-with-veclib"};
|
"polyhedral-info", "replace-with-veclib",
|
||||||
|
"jmc-instrument"};
|
||||||
for (const auto &P : PassNamePrefix)
|
for (const auto &P : PassNamePrefix)
|
||||||
if (Pass.startswith(P))
|
if (Pass.startswith(P))
|
||||||
return true;
|
return true;
|
||||||
@ -572,6 +573,7 @@ int main(int argc, char **argv) {
|
|||||||
initializeHardwareLoopsPass(Registry);
|
initializeHardwareLoopsPass(Registry);
|
||||||
initializeTypePromotionPass(Registry);
|
initializeTypePromotionPass(Registry);
|
||||||
initializeReplaceWithVeclibLegacyPass(Registry);
|
initializeReplaceWithVeclibLegacyPass(Registry);
|
||||||
|
initializeJMCInstrumenterPass(Registry);
|
||||||
|
|
||||||
#ifdef BUILD_EXAMPLES
|
#ifdef BUILD_EXAMPLES
|
||||||
initializeExampleIRTransforms(Registry);
|
initializeExampleIRTransforms(Registry);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user