Skip to content

Commit c382d03

Browse files
committedOct 8, 2019
[clang][ifs] Clang Interface Stubs ToolChain plumbing.
Second Landing Attempt: This patch enables end to end support for generating ELF interface stubs directly from clang. Now the following: clang -emit-interface-stubs -o libfoo.so a.cpp b.cpp c.cpp will product an ELF binary with visible symbols populated. Visibility attributes and -fvisibility can be used to control what gets populated. * Adding ToolChain support for clang Driver IFS Merge Phase * Implementing a default InterfaceStubs Merge clang Tool, used by ToolChain * Adds support for the clang Driver to involve llvm-ifs on ifs files. * Adds -emit-merged-ifs flag, to tell llvm-ifs to emit a merged ifs text file instead of the final object format (normally ELF) Differential Revision: https://reviews.llvm.org/D63978 llvm-svn: 374061
1 parent 08daf8c commit c382d03

32 files changed

+332
-111
lines changed
 

‎clang/include/clang/Driver/Action.h

+12
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class Action {
6565
BackendJobClass,
6666
AssembleJobClass,
6767
LinkJobClass,
68+
IfsMergeJobClass,
6869
LipoJobClass,
6970
DsymutilJobClass,
7071
VerifyDebugInfoJobClass,
@@ -485,6 +486,17 @@ class AssembleJobAction : public JobAction {
485486
}
486487
};
487488

489+
class IfsMergeJobAction : public JobAction {
490+
void anchor() override;
491+
492+
public:
493+
IfsMergeJobAction(ActionList &Inputs, types::ID Type);
494+
495+
static bool classof(const Action *A) {
496+
return A->getKind() == IfsMergeJobClass;
497+
}
498+
};
499+
488500
class LinkJobAction : public JobAction {
489501
void anchor() override;
490502

‎clang/include/clang/Driver/Options.td

+3
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,9 @@ def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group
633633
HelpText<"Use the LLVM representation for assembler and object files">;
634634
def emit_iterface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group<Action_Group>,
635635
HelpText<"Generate Inteface Stub Files.">;
636+
def emit_merged_ifs : Flag<["-"], "emit-merged-ifs">,
637+
Flags<[CC1Option]>, Group<Action_Group>,
638+
HelpText<"Generate Interface Stub Files, emit merged text not binary.">;
636639
def iterface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version=">, Flags<[CC1Option]>;
637640
def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
638641
def e : JoinedOrSeparate<["-"], "e">, Group<Link_Group>;

‎clang/include/clang/Driver/Phases.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ namespace phases {
2020
Compile,
2121
Backend,
2222
Assemble,
23-
Link
23+
Link,
24+
IfsMerge,
2425
};
2526

2627
enum {

‎clang/include/clang/Driver/ToolChain.h

+2
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,13 @@ class ToolChain {
136136
mutable std::unique_ptr<Tool> Clang;
137137
mutable std::unique_ptr<Tool> Assemble;
138138
mutable std::unique_ptr<Tool> Link;
139+
mutable std::unique_ptr<Tool> IfsMerge;
139140
mutable std::unique_ptr<Tool> OffloadBundler;
140141

141142
Tool *getClang() const;
142143
Tool *getAssemble() const;
143144
Tool *getLink() const;
145+
Tool *getIfsMerge() const;
144146
Tool *getClangAs() const;
145147
Tool *getOffloadBundler() const;
146148

‎clang/include/clang/Driver/Types.def

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases
8484

8585
// Misc.
8686
TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
87-
TYPE("ifs", IFS, INVALID, "ifs", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
87+
TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge)
88+
TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge)
8889
TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
8990
TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
9091
TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", phases::Compile, phases::Backend, phases::Assemble, phases::Link)

‎clang/lib/Driver/Action.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const char *Action::getClassName(ActionClass AC) {
3131
case CompileJobClass: return "compiler";
3232
case BackendJobClass: return "backend";
3333
case AssembleJobClass: return "assembler";
34+
case IfsMergeJobClass: return "interface-stub-merger";
3435
case LinkJobClass: return "linker";
3536
case LipoJobClass: return "lipo";
3637
case DsymutilJobClass: return "dsymutil";
@@ -357,6 +358,11 @@ void AssembleJobAction::anchor() {}
357358
AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
358359
: JobAction(AssembleJobClass, Input, OutputType) {}
359360

361+
void IfsMergeJobAction::anchor() {}
362+
363+
IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)
364+
: JobAction(IfsMergeJobClass, Inputs, Type) {}
365+
360366
void LinkJobAction::anchor() {}
361367

362368
LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)

‎clang/lib/Driver/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ add_clang_library(clangDriver
6666
ToolChains/WebAssembly.cpp
6767
ToolChains/XCore.cpp
6868
ToolChains/PPCLinux.cpp
69+
ToolChains/InterfaceStubs.cpp
6970
Types.cpp
7071
XRayArgs.cpp
7172

‎clang/lib/Driver/Driver.cpp

+29-7
Original file line numberDiff line numberDiff line change
@@ -274,32 +274,35 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
274274
(PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) {
275275
FinalPhase = phases::Preprocess;
276276

277-
// --precompile only runs up to precompilation.
277+
// --precompile only runs up to precompilation.
278278
} else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) {
279279
FinalPhase = phases::Precompile;
280280

281-
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
281+
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
282282
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
283283
(PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) ||
284284
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
285285
(PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) ||
286286
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
287287
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
288288
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
289-
(PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs)) ||
290289
(PhaseArg = DAL.getLastArg(options::OPT__analyze)) ||
291290
(PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
292291
FinalPhase = phases::Compile;
293292

294-
// -S only runs up to the backend.
293+
// clang interface stubs
294+
} else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs))) {
295+
FinalPhase = phases::IfsMerge;
296+
297+
// -S only runs up to the backend.
295298
} else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) {
296299
FinalPhase = phases::Backend;
297300

298-
// -c compilation only runs up to the assembler.
301+
// -c compilation only runs up to the assembler.
299302
} else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) {
300303
FinalPhase = phases::Assemble;
301304

302-
// Otherwise do everything.
305+
// Otherwise do everything.
303306
} else
304307
FinalPhase = phases::Link;
305308

@@ -3337,6 +3340,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
33373340
// Construct the actions to perform.
33383341
HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
33393342
ActionList LinkerInputs;
3343+
ActionList MergerInputs;
33403344

33413345
for (auto &I : Inputs) {
33423346
types::ID InputType = I.first;
@@ -3374,6 +3378,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
33743378
break;
33753379
}
33763380

3381+
// TODO: Consider removing this because the merged may not end up being
3382+
// the final Phase in the pipeline. Perhaps the merged could just merge
3383+
// and then pass an artifact of some sort to the Link Phase.
3384+
// Queue merger inputs.
3385+
if (Phase == phases::IfsMerge) {
3386+
assert(Phase == PL.back() && "merging must be final compilation step.");
3387+
MergerInputs.push_back(Current);
3388+
Current = nullptr;
3389+
break;
3390+
}
3391+
33773392
// Each precompiled header file after a module file action is a module
33783393
// header of that same module file, rather than being compiled to a
33793394
// separate PCH.
@@ -3423,6 +3438,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
34233438
Actions.push_back(LA);
34243439
}
34253440

3441+
// Add an interface stubs merge action if necessary.
3442+
if (!MergerInputs.empty())
3443+
Actions.push_back(
3444+
C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
3445+
34263446
// If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom
34273447
// Compile phase that prints out supported cpu models and quits.
34283448
if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) {
@@ -3459,6 +3479,8 @@ Action *Driver::ConstructPhaseAction(
34593479
switch (Phase) {
34603480
case phases::Link:
34613481
llvm_unreachable("link action invalid here.");
3482+
case phases::IfsMerge:
3483+
llvm_unreachable("ifsmerge action invalid here.");
34623484
case phases::Preprocess: {
34633485
types::ID OutputTy;
34643486
// -M and -MM specify the dependency file name by altering the output type,
@@ -3523,7 +3545,7 @@ Action *Driver::ConstructPhaseAction(
35233545
if (Args.hasArg(options::OPT_verify_pch))
35243546
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
35253547
if (Args.hasArg(options::OPT_emit_iterface_stubs))
3526-
return C.MakeAction<CompileJobAction>(Input, types::TY_IFS);
3548+
return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP);
35273549
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
35283550
}
35293551
case phases::Backend: {

‎clang/lib/Driver/Phases.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const char *phases::getPhaseName(ID Id) {
2020
case Backend: return "backend";
2121
case Assemble: return "assembler";
2222
case Link: return "linker";
23+
case IfsMerge: return "ifsmerger";
2324
}
2425

2526
llvm_unreachable("Invalid phase id.");

‎clang/lib/Driver/ToolChain.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "InputInfo.h"
1111
#include "ToolChains/Arch/ARM.h"
1212
#include "ToolChains/Clang.h"
13+
#include "ToolChains/InterfaceStubs.h"
1314
#include "clang/Basic/ObjCRuntime.h"
1415
#include "clang/Basic/Sanitizers.h"
1516
#include "clang/Config/config.h"
@@ -279,6 +280,12 @@ Tool *ToolChain::getLink() const {
279280
return Link.get();
280281
}
281282

283+
Tool *ToolChain::getIfsMerge() const {
284+
if (!IfsMerge)
285+
IfsMerge.reset(new tools::ifstool::Merger(*this));
286+
return IfsMerge.get();
287+
}
288+
282289
Tool *ToolChain::getOffloadBundler() const {
283290
if (!OffloadBundler)
284291
OffloadBundler.reset(new tools::OffloadBundler(*this));
@@ -290,6 +297,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
290297
case Action::AssembleJobClass:
291298
return getAssemble();
292299

300+
case Action::IfsMergeJobClass:
301+
return getIfsMerge();
302+
293303
case Action::LinkJobClass:
294304
return getLink();
295305

‎clang/lib/Driver/ToolChains/Clang.cpp

+4-21
Original file line numberDiff line numberDiff line change
@@ -3683,32 +3683,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
36833683
} else if (JA.getType() == types::TY_LLVM_BC ||
36843684
JA.getType() == types::TY_LTO_BC) {
36853685
CmdArgs.push_back("-emit-llvm-bc");
3686-
} else if (JA.getType() == types::TY_IFS) {
3686+
} else if (JA.getType() == types::TY_IFS ||
3687+
JA.getType() == types::TY_IFS_CPP) {
36873688
StringRef ArgStr =
36883689
Args.hasArg(options::OPT_iterface_stub_version_EQ)
36893690
? Args.getLastArgValue(options::OPT_iterface_stub_version_EQ)
3690-
: "";
3691-
StringRef StubFormat =
3692-
llvm::StringSwitch<StringRef>(ArgStr)
3693-
.Case("experimental-ifs-v1", "experimental-ifs-v1")
3694-
.Default("");
3695-
3696-
if (StubFormat.empty()) {
3697-
std::string ErrorMessage =
3698-
"Invalid interface stub format: " + ArgStr.str() +
3699-
((ArgStr == "experimental-yaml-elf-v1" ||
3700-
ArgStr == "experimental-tapi-elf-v1")
3701-
? " is deprecated."
3702-
: ".");
3703-
D.Diag(diag::err_drv_invalid_value)
3704-
<< "Must specify a valid interface stub format type, ie: "
3705-
"-interface-stub-version=experimental-ifs-v1"
3706-
<< ErrorMessage;
3707-
}
3708-
3691+
: "experimental-ifs-v1";
37093692
CmdArgs.push_back("-emit-interface-stubs");
37103693
CmdArgs.push_back(
3711-
Args.MakeArgString(Twine("-interface-stub-version=") + StubFormat));
3694+
Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str()));
37123695
} else if (JA.getType() == types::TY_PP_Asm) {
37133696
CmdArgs.push_back("-S");
37143697
} else if (JA.getType() == types::TY_AST) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "InterfaceStubs.h"
10+
#include "CommonArgs.h"
11+
#include "clang/Driver/Compilation.h"
12+
13+
namespace clang {
14+
namespace driver {
15+
namespace tools {
16+
namespace ifstool {
17+
void Merger::ConstructJob(Compilation &C, const JobAction &JA,
18+
const InputInfo &Output, const InputInfoList &Inputs,
19+
const llvm::opt::ArgList &Args,
20+
const char *LinkingOutput) const {
21+
std::string Merger = getToolChain().GetProgramPath(getShortName());
22+
llvm::opt::ArgStringList CmdArgs;
23+
CmdArgs.push_back("-action");
24+
CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs)
25+
? "write-ifs"
26+
: "write-bin");
27+
CmdArgs.push_back("-o");
28+
CmdArgs.push_back(Output.getFilename());
29+
for (const auto &Input : Inputs)
30+
CmdArgs.push_back(Input.getFilename());
31+
C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger),
32+
CmdArgs, Inputs));
33+
}
34+
} // namespace ifstool
35+
} // namespace tools
36+
} // namespace driver
37+
} // namespace clang
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H
10+
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H
11+
12+
#include "clang/Driver/Tool.h"
13+
#include "clang/Driver/ToolChain.h"
14+
15+
namespace clang {
16+
namespace driver {
17+
namespace tools {
18+
namespace ifstool {
19+
class LLVM_LIBRARY_VISIBILITY Merger : public Tool {
20+
public:
21+
Merger(const ToolChain &TC) : Tool("IFS::Merger", "llvm-ifs", TC) {}
22+
23+
bool hasIntegratedCPP() const override { return false; }
24+
bool isLinkJob() const override { return false; }
25+
26+
void ConstructJob(Compilation &C, const JobAction &JA,
27+
const InputInfo &Output, const InputInfoList &Inputs,
28+
const llvm::opt::ArgList &TCArgs,
29+
const char *LinkingOutput) const override;
30+
};
31+
} // end namespace ifstool
32+
} // end namespace tools
33+
} // end namespace driver
34+
} // end namespace clang
35+
36+
#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H

‎clang/lib/Driver/Types.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) {
269269
.Case("lib", TY_Object)
270270
.Case("mii", TY_PP_ObjCXX)
271271
.Case("obj", TY_Object)
272+
.Case("ifs", TY_IFS)
272273
.Case("pch", TY_PCH)
273274
.Case("pcm", TY_ModuleFile)
274275
.Case("c++m", TY_CXXModule)
@@ -319,6 +320,22 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver,
319320
llvm::copy_if(PhaseList, std::back_inserter(P),
320321
[](phases::ID Phase) { return Phase <= phases::Precompile; });
321322

323+
// Treat Interface Stubs like its own compilation mode.
324+
else if (DAL.getLastArg(options::OPT_emit_iterface_stubs)) {
325+
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList;
326+
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList;
327+
phases::ID LastPhase = phases::IfsMerge;
328+
if (Id != types::TY_IFS) {
329+
if (DAL.hasArg(options::OPT_c))
330+
LastPhase = phases::Compile;
331+
PL = IfsModePhaseList;
332+
types::getCompilationPhases(types::TY_IFS_CPP, PL);
333+
}
334+
llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) {
335+
return Phase <= LastPhase;
336+
});
337+
}
338+
322339
// -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
323340
else if (DAL.getLastArg(options::OPT_fsyntax_only) ||
324341
DAL.getLastArg(options::OPT_print_supported_cpus) ||
@@ -327,7 +344,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver,
327344
DAL.getLastArg(options::OPT_rewrite_objc) ||
328345
DAL.getLastArg(options::OPT_rewrite_legacy_objc) ||
329346
DAL.getLastArg(options::OPT__migrate) ||
330-
DAL.getLastArg(options::OPT_emit_iterface_stubs) ||
331347
DAL.getLastArg(options::OPT__analyze) ||
332348
DAL.getLastArg(options::OPT_emit_ast))
333349
llvm::copy_if(PhaseList, std::back_inserter(P),

0 commit comments

Comments
 (0)
Please sign in to comment.