-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[CodeGen] Support start/stop in CodeGenPassBuilder #70912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,7 @@ | |
#include "llvm/CodeGen/ShadowStackGCLowering.h" | ||
#include "llvm/CodeGen/SjLjEHPrepare.h" | ||
#include "llvm/CodeGen/StackProtector.h" | ||
#include "llvm/CodeGen/TargetPassConfig.h" | ||
#include "llvm/CodeGen/UnreachableBlockElim.h" | ||
#include "llvm/CodeGen/WasmEHPrepare.h" | ||
#include "llvm/CodeGen/WinEHPrepare.h" | ||
|
@@ -175,73 +176,80 @@ template <typename DerivedT> class CodeGenPassBuilder { | |
// Function object to maintain state while adding codegen IR passes. | ||
class AddIRPass { | ||
public: | ||
AddIRPass(ModulePassManager &MPM) : MPM(MPM) {} | ||
AddIRPass(ModulePassManager &MPM, const DerivedT &PB) : MPM(MPM), PB(PB) {} | ||
~AddIRPass() { | ||
if (!FPM.isEmpty()) | ||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); | ||
} | ||
|
||
template <typename PassT> void operator()(PassT &&Pass) { | ||
template <typename PassT> | ||
void operator()(PassT &&Pass, StringRef Name = PassT::name()) { | ||
static_assert((is_detected<is_function_pass_t, PassT>::value || | ||
is_detected<is_module_pass_t, PassT>::value) && | ||
"Only module pass and function pass are supported."); | ||
|
||
if (!PB.runBeforeAdding(Name)) | ||
return; | ||
|
||
// Add Function Pass | ||
if constexpr (is_detected<is_function_pass_t, PassT>::value) { | ||
FPM.addPass(std::forward<PassT>(Pass)); | ||
|
||
for (auto &C : PB.AfterCallbacks) | ||
C(Name); | ||
} else { | ||
// Add Module Pass | ||
if (!FPM.isEmpty()) { | ||
MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); | ||
FPM = FunctionPassManager(); | ||
} | ||
|
||
MPM.addPass(std::forward<PassT>(Pass)); | ||
|
||
for (auto &C : PB.AfterCallbacks) | ||
C(Name); | ||
} | ||
} | ||
|
||
private: | ||
ModulePassManager &MPM; | ||
FunctionPassManager FPM; | ||
const DerivedT &PB; | ||
}; | ||
|
||
// Function object to maintain state while adding codegen machine passes. | ||
class AddMachinePass { | ||
public: | ||
AddMachinePass(MachineFunctionPassManager &PM) : PM(PM) {} | ||
AddMachinePass(MachineFunctionPassManager &PM, const DerivedT &PB) | ||
: PM(PM), PB(PB) {} | ||
|
||
template <typename PassT> void operator()(PassT &&Pass) { | ||
static_assert( | ||
is_detected<has_key_t, PassT>::value, | ||
"Machine function pass must define a static member variable `Key`."); | ||
for (auto &C : BeforeCallbacks) | ||
if (!C(&PassT::Key)) | ||
return; | ||
|
||
if (!PB.runBeforeAdding(PassT::name())) | ||
return; | ||
|
||
PM.addPass(std::forward<PassT>(Pass)); | ||
for (auto &C : AfterCallbacks) | ||
C(&PassT::Key); | ||
|
||
for (auto &C : PB.AfterCallbacks) | ||
C(PassT::name()); | ||
} | ||
|
||
template <typename PassT> void insertPass(MachinePassKey *ID, PassT Pass) { | ||
AfterCallbacks.emplace_back( | ||
PB.AfterCallbacks.emplace_back( | ||
[this, ID, Pass = std::move(Pass)](MachinePassKey *PassID) { | ||
if (PassID == ID) | ||
this->PM.addPass(std::move(Pass)); | ||
}); | ||
} | ||
|
||
void disablePass(MachinePassKey *ID) { | ||
BeforeCallbacks.emplace_back( | ||
[ID](MachinePassKey *PassID) { return PassID != ID; }); | ||
} | ||
|
||
MachineFunctionPassManager releasePM() { return std::move(PM); } | ||
|
||
private: | ||
MachineFunctionPassManager &PM; | ||
SmallVector<llvm::unique_function<bool(MachinePassKey *)>, 4> | ||
BeforeCallbacks; | ||
SmallVector<llvm::unique_function<void(MachinePassKey *)>, 4> | ||
AfterCallbacks; | ||
const DerivedT &PB; | ||
}; | ||
|
||
LLVMTargetMachine &TM; | ||
|
@@ -469,20 +477,43 @@ template <typename DerivedT> class CodeGenPassBuilder { | |
const DerivedT &derived() const { | ||
return static_cast<const DerivedT &>(*this); | ||
} | ||
|
||
bool runBeforeAdding(StringRef Name) const { | ||
bool ShouldAdd = true; | ||
for (auto &C : BeforeCallbacks) | ||
ShouldAdd &= C(Name); | ||
return ShouldAdd; | ||
} | ||
|
||
void setStartStopPasses(const TargetPassConfig::StartStopInfo &Info) const; | ||
|
||
Error verifyStartStop(const TargetPassConfig::StartStopInfo &Info) const; | ||
|
||
mutable SmallVector<llvm::unique_function<bool(StringRef)>, 4> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it seems nicer to keep this in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently IR passes and machine function passes are handled by different classes, and |
||
BeforeCallbacks; | ||
mutable SmallVector<llvm::unique_function<void(StringRef)>, 4> AfterCallbacks; | ||
|
||
/// Helper variable for `-start-before/-start-after/-stop-before/-stop-after` | ||
mutable bool Started = true; | ||
mutable bool Stopped = true; | ||
}; | ||
|
||
template <typename Derived> | ||
Error CodeGenPassBuilder<Derived>::buildPipeline( | ||
ModulePassManager &MPM, MachineFunctionPassManager &MFPM, | ||
raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, | ||
CodeGenFileType FileType) const { | ||
AddIRPass addIRPass(MPM); | ||
auto StartStopInfo = TargetPassConfig::getStartStopInfo(*PIC); | ||
if (!StartStopInfo) | ||
return StartStopInfo.takeError(); | ||
setStartStopPasses(*StartStopInfo); | ||
AddIRPass addIRPass(MPM, derived()); | ||
// `ProfileSummaryInfo` is always valid. | ||
addIRPass(RequireAnalysisPass<ProfileSummaryAnalysis, Module>()); | ||
addIRPass(RequireAnalysisPass<CollectorMetadataAnalysis, Module>()); | ||
addISelPasses(addIRPass); | ||
|
||
AddMachinePass addPass(MFPM); | ||
AddMachinePass addPass(MFPM, derived()); | ||
if (auto Err = addCoreISelPasses(addPass)) | ||
return std::move(Err); | ||
|
||
|
@@ -495,6 +526,68 @@ Error CodeGenPassBuilder<Derived>::buildPipeline( | |
}); | ||
|
||
addPass(FreeMachineFunctionPass()); | ||
return verifyStartStop(*StartStopInfo); | ||
} | ||
|
||
template <typename Derived> | ||
void CodeGenPassBuilder<Derived>::setStartStopPasses( | ||
const TargetPassConfig::StartStopInfo &Info) const { | ||
if (!Info.StartPass.empty()) { | ||
Started = false; | ||
BeforeCallbacks.emplace_back([this, &Info, AfterFlag = Info.StartAfter, | ||
Count = 0u](StringRef ClassName) mutable { | ||
if (Count == Info.StartInstanceNum) { | ||
if (AfterFlag) { | ||
AfterFlag = false; | ||
Started = true; | ||
} | ||
return Started; | ||
} | ||
|
||
auto PassName = PIC->getPassNameForClassName(ClassName); | ||
if (Info.StartPass == PassName && ++Count == Info.StartInstanceNum) | ||
Started = !Info.StartAfter; | ||
|
||
return Started; | ||
}); | ||
} | ||
|
||
if (!Info.StopPass.empty()) { | ||
Stopped = false; | ||
BeforeCallbacks.emplace_back([this, &Info, AfterFlag = Info.StopAfter, | ||
Count = 0u](StringRef ClassName) mutable { | ||
if (Count == Info.StopInstanceNum) { | ||
if (AfterFlag) { | ||
AfterFlag = false; | ||
Stopped = true; | ||
} | ||
return !Stopped; | ||
} | ||
|
||
auto PassName = PIC->getPassNameForClassName(ClassName); | ||
if (Info.StopPass == PassName && ++Count == Info.StopInstanceNum) | ||
Stopped = !Info.StopAfter; | ||
return !Stopped; | ||
}); | ||
} | ||
} | ||
|
||
template <typename Derived> | ||
Error CodeGenPassBuilder<Derived>::verifyStartStop( | ||
const TargetPassConfig::StartStopInfo &Info) const { | ||
if (Started && Stopped) | ||
return Error::success(); | ||
|
||
if (!Started) | ||
return make_error<StringError>( | ||
"Can't find start pass \"" + | ||
PIC->getPassNameForClassName(Info.StartPass) + "\".", | ||
std::make_error_code(std::errc::invalid_argument)); | ||
if (!Stopped) | ||
return make_error<StringError>( | ||
"Can't find stop pass \"" + | ||
PIC->getPassNameForClassName(Info.StopPass) + "\".", | ||
std::make_error_code(std::errc::invalid_argument)); | ||
return Error::success(); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated, and I think I mentioned this before, but I'd like to see if we can come up with a nicer way of doing this, perhaps with something like
PassBuilder
extension points (e.g.PassBuilder::registerPeepholeEPCallback()
). it seems in line with various per-target TargetMachines adding their own passes anyway. do you know if we could potentially replaceinsertPass()
with the various TargetMachines simply adding passes in the right place, or are the passes they add too ad hoc?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently AMDGPU, Hexagon, PowerPC and RISCV uses
insertPass
to adjust the regalloc pipeline, we need add extension points afterPHIElimination
,TwoAddressInstruction
,MachineScheduler
,RenameIndependentSubregs
,LiveVariables
andDetectDeadLanes
. They inject passes between these passes directly and only happens in regalloc pipeline.