Skip to content

Commit a9f6555

Browse files
committedMar 4, 2016
Refactor gold-plugin codegen to prepare for ThinLTO threads (NFC)
This is the NFC part remaining from D15390, which refactors the current codegen() into a CodeGen class with various modular methods and other helper functions that will be used by the follow-on ThinLTO piece. llvm-svn: 262721
1 parent 1ea51d2 commit a9f6555

File tree

1 file changed

+181
-92
lines changed

1 file changed

+181
-92
lines changed
 

‎llvm/tools/gold/gold-plugin.cpp

+181-92
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ static std::list<claimed_file> Modules;
112112
static StringMap<ResolutionInfo> ResInfo;
113113
static std::vector<std::string> Cleanup;
114114
static llvm::TargetOptions TargetOpts;
115+
static std::string DefaultTriple = sys::getDefaultTargetTriple();
115116

116117
namespace options {
117118
enum OutputType {
@@ -123,7 +124,10 @@ namespace options {
123124
static bool generate_api_file = false;
124125
static OutputType TheOutputType = OT_NORMAL;
125126
static unsigned OptLevel = 2;
126-
static unsigned Parallelism = 1;
127+
// Default parallelism of 0 used to indicate that user did not specify.
128+
// Actual parallelism default value depends on implementation.
129+
// Currently, code generation defaults to no parallelism.
130+
static unsigned Parallelism = 0;
127131
#ifdef NDEBUG
128132
static bool DisableVerify = true;
129133
#else
@@ -568,8 +572,8 @@ static void freeSymName(ld_plugin_symbol &Sym) {
568572
Sym.comdat_key = nullptr;
569573
}
570574

571-
static std::unique_ptr<FunctionInfoIndex>
572-
getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
575+
/// Helper to get a file's symbols and a view into it via gold callbacks.
576+
static const void *getSymbolsAndView(claimed_file &F) {
573577
ld_plugin_status status = get_symbols(F.handle, F.syms.size(), &F.syms[0]);
574578
if (status == LDPS_NO_SYMS)
575579
return nullptr;
@@ -581,6 +585,13 @@ getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
581585
if (get_view(F.handle, &View) != LDPS_OK)
582586
message(LDPL_FATAL, "Failed to get a view of file");
583587

588+
return View;
589+
}
590+
591+
static std::unique_ptr<FunctionInfoIndex>
592+
getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
593+
const void *View = getSymbolsAndView(F);
594+
584595
MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
585596
Info.name);
586597

@@ -603,22 +614,10 @@ getFunctionIndexForFile(claimed_file &F, ld_plugin_input_file &Info) {
603614
}
604615

605616
static std::unique_ptr<Module>
606-
getModuleForFile(LLVMContext &Context, claimed_file &F,
617+
getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
607618
ld_plugin_input_file &Info, raw_fd_ostream *ApiFile,
608619
StringSet<> &Internalize, StringSet<> &Maybe,
609620
std::vector<GlobalValue *> &Keep) {
610-
611-
ld_plugin_status status = get_symbols(F.handle, F.syms.size(), F.syms.data());
612-
if (status == LDPS_NO_SYMS)
613-
return nullptr;
614-
615-
if (status != LDPS_OK)
616-
message(LDPL_FATAL, "Failed to get symbol information");
617-
618-
const void *View;
619-
if (get_view(F.handle, &View) != LDPS_OK)
620-
message(LDPL_FATAL, "Failed to get a view of file");
621-
622621
MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
623622
Info.name);
624623
ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
@@ -745,26 +744,6 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
745744
return Obj.takeModule();
746745
}
747746

748-
static void runLTOPasses(Module &M, TargetMachine &TM) {
749-
M.setDataLayout(TM.createDataLayout());
750-
751-
legacy::PassManager passes;
752-
passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
753-
754-
PassManagerBuilder PMB;
755-
PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
756-
PMB.Inliner = createFunctionInliningPass();
757-
// Unconditionally verify input since it is not verified before this
758-
// point and has unknown origin.
759-
PMB.VerifyInput = true;
760-
PMB.VerifyOutput = !options::DisableVerify;
761-
PMB.LoopVectorize = true;
762-
PMB.SLPVectorize = true;
763-
PMB.OptLevel = options::OptLevel;
764-
PMB.populateLTOPassManager(passes);
765-
passes.run(M);
766-
}
767-
768747
static void saveBCFile(StringRef Path, Module &M) {
769748
std::error_code EC;
770749
raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
@@ -773,24 +752,56 @@ static void saveBCFile(StringRef Path, Module &M) {
773752
WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ false);
774753
}
775754

776-
static void codegen(std::unique_ptr<Module> M) {
777-
const std::string &TripleStr = M->getTargetTriple();
778-
Triple TheTriple(TripleStr);
755+
static void recordFile(std::string Filename, bool TempOutFile) {
756+
if (add_input_file(Filename.c_str()) != LDPS_OK)
757+
message(LDPL_FATAL,
758+
"Unable to add .o file to the link. File left behind in: %s",
759+
Filename.c_str());
760+
if (TempOutFile)
761+
Cleanup.push_back(Filename.c_str());
762+
}
779763

780-
std::string ErrMsg;
781-
const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
782-
if (!TheTarget)
783-
message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
764+
namespace {
765+
/// Class to manage optimization and code generation for a module.
766+
class CodeGen {
767+
/// The module for which this will generate code.
768+
std::unique_ptr<llvm::Module> M;
769+
770+
/// The target machine for generating code for this module.
771+
std::unique_ptr<TargetMachine> TM;
772+
773+
public:
774+
/// Constructor used by full LTO.
775+
CodeGen(std::unique_ptr<llvm::Module> M) : M(std::move(M)) {
776+
initTargetMachine();
777+
}
784778

785-
if (unsigned NumOpts = options::extra.size())
786-
cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
779+
/// Invoke LTO passes and the code generator for the module.
780+
void runAll();
781+
782+
private:
783+
/// Create a target machine for the module. Must be unique for each
784+
/// module/task.
785+
void initTargetMachine();
786+
787+
/// Run all LTO passes on the module.
788+
void runLTOPasses();
789+
790+
/// Sets up output files necessary to perform optional multi-threaded
791+
/// split code generation, and invokes the code generation implementation.
792+
void runSplitCodeGen();
793+
};
794+
}
787795

796+
static SubtargetFeatures getFeatures(Triple &TheTriple) {
788797
SubtargetFeatures Features;
789798
Features.getDefaultSubtargetFeatures(TheTriple);
790799
for (const std::string &A : MAttrs)
791800
Features.AddFeature(A);
801+
return Features;
802+
}
792803

793-
TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
804+
static CodeGenOpt::Level getCGOptLevel() {
794805
CodeGenOpt::Level CGOptLevel;
795806
switch (options::OptLevel) {
796807
case 0:
@@ -806,62 +817,146 @@ static void codegen(std::unique_ptr<Module> M) {
806817
CGOptLevel = CodeGenOpt::Aggressive;
807818
break;
808819
}
809-
std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
820+
return CGOptLevel;
821+
}
822+
823+
void CodeGen::initTargetMachine() {
824+
const std::string &TripleStr = M->getTargetTriple();
825+
Triple TheTriple(TripleStr);
826+
827+
std::string ErrMsg;
828+
const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
829+
if (!TheTarget)
830+
message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
831+
832+
SubtargetFeatures Features = getFeatures(TheTriple);
833+
TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
834+
CodeGenOpt::Level CGOptLevel = getCGOptLevel();
835+
836+
TM.reset(TheTarget->createTargetMachine(
810837
TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
811838
CodeModel::Default, CGOptLevel));
839+
}
812840

813-
runLTOPasses(*M, *TM);
841+
void CodeGen::runLTOPasses() {
842+
M->setDataLayout(TM->createDataLayout());
814843

815-
if (options::TheOutputType == options::OT_SAVE_TEMPS)
816-
saveBCFile(output_name + ".opt.bc", *M);
844+
legacy::PassManager passes;
845+
passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
846+
847+
PassManagerBuilder PMB;
848+
PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
849+
PMB.Inliner = createFunctionInliningPass();
850+
// Unconditionally verify input since it is not verified before this
851+
// point and has unknown origin.
852+
PMB.VerifyInput = true;
853+
PMB.VerifyOutput = !options::DisableVerify;
854+
PMB.LoopVectorize = true;
855+
PMB.SLPVectorize = true;
856+
PMB.OptLevel = options::OptLevel;
857+
PMB.populateLTOPassManager(passes);
858+
passes.run(*M);
859+
}
860+
861+
/// Open a file and return the new file descriptor given a base input
862+
/// file name, a flag indicating whether a temp file should be generated,
863+
/// and an optional task id. The new filename generated is
864+
/// returned in \p NewFilename.
865+
static int openOutputFile(SmallString<128> InFilename, bool TempOutFile,
866+
SmallString<128> &NewFilename, int TaskID = -1) {
867+
int FD;
868+
if (TempOutFile) {
869+
std::error_code EC =
870+
sys::fs::createTemporaryFile("lto-llvm", "o", FD, NewFilename);
871+
if (EC)
872+
message(LDPL_FATAL, "Could not create temporary file: %s",
873+
EC.message().c_str());
874+
} else {
875+
NewFilename = InFilename;
876+
if (TaskID >= 0)
877+
NewFilename += utostr(TaskID);
878+
std::error_code EC =
879+
sys::fs::openFileForWrite(NewFilename, FD, sys::fs::F_None);
880+
if (EC)
881+
message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
882+
}
883+
return FD;
884+
}
885+
886+
void CodeGen::runSplitCodeGen() {
887+
const std::string &TripleStr = M->getTargetTriple();
888+
Triple TheTriple(TripleStr);
889+
890+
SubtargetFeatures Features = getFeatures(TheTriple);
891+
892+
TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
893+
CodeGenOpt::Level CGOptLevel = getCGOptLevel();
817894

818895
SmallString<128> Filename;
896+
// Note that openOutputFile will append a unique ID for each task
819897
if (!options::obj_path.empty())
820898
Filename = options::obj_path;
821899
else if (options::TheOutputType == options::OT_SAVE_TEMPS)
822900
Filename = output_name + ".o";
823901

824-
std::vector<SmallString<128>> Filenames(options::Parallelism);
902+
// Note that the default parallelism is 1 instead of the
903+
// hardware_concurrency, as there are behavioral differences between
904+
// parallelism levels (e.g. symbol ordering will be different, and some uses
905+
// of inline asm currently have issues with parallelism >1).
906+
unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1;
907+
908+
std::vector<SmallString<128>> Filenames(MaxThreads);
825909
bool TempOutFile = Filename.empty();
826910
{
827-
// Open a file descriptor for each backend thread. This is done in a block
911+
// Open a file descriptor for each backend task. This is done in a block
828912
// so that the output file descriptors are closed before gold opens them.
829913
std::list<llvm::raw_fd_ostream> OSs;
830-
std::vector<llvm::raw_pwrite_stream *> OSPtrs(options::Parallelism);
831-
for (unsigned I = 0; I != options::Parallelism; ++I) {
832-
int FD;
833-
if (TempOutFile) {
834-
std::error_code EC =
835-
sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filenames[I]);
836-
if (EC)
837-
message(LDPL_FATAL, "Could not create temporary file: %s",
838-
EC.message().c_str());
839-
} else {
840-
Filenames[I] = Filename;
841-
if (options::Parallelism != 1)
842-
Filenames[I] += utostr(I);
843-
std::error_code EC =
844-
sys::fs::openFileForWrite(Filenames[I], FD, sys::fs::F_None);
845-
if (EC)
846-
message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
847-
}
914+
std::vector<llvm::raw_pwrite_stream *> OSPtrs(MaxThreads);
915+
for (unsigned I = 0; I != MaxThreads; ++I) {
916+
int FD = openOutputFile(Filename, TempOutFile, Filenames[I], I);
848917
OSs.emplace_back(FD, true);
849918
OSPtrs[I] = &OSs.back();
850919
}
851920

852-
// Run backend threads.
921+
// Run backend tasks.
853922
splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(),
854923
Options, RelocationModel, CodeModel::Default, CGOptLevel);
855924
}
856925

857-
for (auto &Filename : Filenames) {
858-
if (add_input_file(Filename.c_str()) != LDPS_OK)
859-
message(LDPL_FATAL,
860-
"Unable to add .o file to the link. File left behind in: %s",
861-
Filename.c_str());
862-
if (TempOutFile)
863-
Cleanup.push_back(Filename.c_str());
926+
for (auto &Filename : Filenames)
927+
recordFile(Filename.c_str(), TempOutFile);
928+
}
929+
930+
void CodeGen::runAll() {
931+
runLTOPasses();
932+
933+
if (options::TheOutputType == options::OT_SAVE_TEMPS) {
934+
saveBCFile(output_name + ".opt.bc", *M);
864935
}
936+
937+
runSplitCodeGen();
938+
}
939+
940+
/// Links the module in \p View from file \p F into the combined module
941+
/// saved in the IRMover \p L. Returns true on error, false on success.
942+
static bool linkInModule(LLVMContext &Context, IRMover &L, claimed_file &F,
943+
const void *View, ld_plugin_input_file &File,
944+
raw_fd_ostream *ApiFile, StringSet<> &Internalize,
945+
StringSet<> &Maybe) {
946+
std::vector<GlobalValue *> Keep;
947+
std::unique_ptr<Module> M = getModuleForFile(Context, F, View, File, ApiFile,
948+
Internalize, Maybe, Keep);
949+
if (!M.get())
950+
return false;
951+
if (!options::triple.empty())
952+
M->setTargetTriple(options::triple.c_str());
953+
else if (M->getTargetTriple().empty()) {
954+
M->setTargetTriple(DefaultTriple);
955+
}
956+
957+
if (L.move(std::move(M), Keep, [](GlobalValue &, IRMover::ValueAdder) {}))
958+
return true;
959+
return false;
865960
}
866961

867962
/// gold informs us that all symbols have been read. At this point, we use
@@ -871,6 +966,9 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
871966
if (Modules.empty())
872967
return LDPS_OK;
873968

969+
if (unsigned NumOpts = options::extra.size())
970+
cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
971+
874972
// If we are doing ThinLTO compilation, simply build the combined
875973
// function index/summary and emit it. We don't need to parse the modules
876974
// and link them in this case.
@@ -907,23 +1005,13 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
9071005
std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
9081006
IRMover L(*Combined);
9091007

910-
std::string DefaultTriple = sys::getDefaultTargetTriple();
911-
9121008
StringSet<> Internalize;
9131009
StringSet<> Maybe;
9141010
for (claimed_file &F : Modules) {
9151011
PluginInputFile InputFile(F.handle);
916-
std::vector<GlobalValue *> Keep;
917-
std::unique_ptr<Module> M = getModuleForFile(
918-
Context, F, InputFile.file(), ApiFile, Internalize, Maybe, Keep);
919-
if (!M.get())
920-
continue;
921-
if (!options::triple.empty())
922-
M->setTargetTriple(options::triple.c_str());
923-
else if (M->getTargetTriple().empty())
924-
M->setTargetTriple(DefaultTriple);
925-
926-
if (L.move(std::move(M), Keep, [](GlobalValue &, IRMover::ValueAdder) {}))
1012+
const void *View = getSymbolsAndView(F);
1013+
if (linkInModule(Context, L, F, View, InputFile.file(), ApiFile,
1014+
Internalize, Maybe))
9271015
message(LDPL_FATAL, "Failed to link module");
9281016
}
9291017

@@ -956,7 +1044,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
9561044
return LDPS_OK;
9571045
}
9581046

959-
codegen(std::move(Combined));
1047+
CodeGen codeGen(std::move(Combined));
1048+
codeGen.runAll();
9601049

9611050
if (!options::extra_library_path.empty() &&
9621051
set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK)

0 commit comments

Comments
 (0)
Please sign in to comment.