diff options
Diffstat (limited to 'tools/perf/util/c++/clang.cpp')
-rw-r--r-- | tools/perf/util/c++/clang.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp new file mode 100644 index 000000000000..1e974152cac2 --- /dev/null +++ b/tools/perf/util/c++/clang.cpp | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * llvm C frontend for perf. Support dynamically compile C file | ||
3 | * | ||
4 | * Inspired by clang example code: | ||
5 | * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp | ||
6 | * | ||
7 | * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com> | ||
8 | * Copyright (C) 2016 Huawei Inc. | ||
9 | */ | ||
10 | |||
11 | #include "clang/CodeGen/CodeGenAction.h" | ||
12 | #include "clang/Frontend/CompilerInvocation.h" | ||
13 | #include "clang/Frontend/CompilerInstance.h" | ||
14 | #include "clang/Frontend/TextDiagnosticPrinter.h" | ||
15 | #include "clang/Tooling/Tooling.h" | ||
16 | #include "llvm/IR/LegacyPassManager.h" | ||
17 | #include "llvm/IR/Module.h" | ||
18 | #include "llvm/Option/Option.h" | ||
19 | #include "llvm/Support/FileSystem.h" | ||
20 | #include "llvm/Support/ManagedStatic.h" | ||
21 | #include "llvm/Support/TargetRegistry.h" | ||
22 | #include "llvm/Support/TargetSelect.h" | ||
23 | #include "llvm/Target/TargetMachine.h" | ||
24 | #include "llvm/Target/TargetOptions.h" | ||
25 | #include <memory> | ||
26 | |||
27 | #include "clang.h" | ||
28 | #include "clang-c.h" | ||
29 | |||
30 | namespace perf { | ||
31 | |||
32 | static std::unique_ptr<llvm::LLVMContext> LLVMCtx; | ||
33 | |||
34 | using namespace clang; | ||
35 | |||
36 | static CompilerInvocation * | ||
37 | createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path, | ||
38 | DiagnosticsEngine& Diags) | ||
39 | { | ||
40 | llvm::opt::ArgStringList CCArgs { | ||
41 | "-cc1", | ||
42 | "-triple", "bpf-pc-linux", | ||
43 | "-fsyntax-only", | ||
44 | "-ferror-limit", "19", | ||
45 | "-fmessage-length", "127", | ||
46 | "-O2", | ||
47 | "-nostdsysteminc", | ||
48 | "-nobuiltininc", | ||
49 | "-vectorize-loops", | ||
50 | "-vectorize-slp", | ||
51 | "-Wno-unused-value", | ||
52 | "-Wno-pointer-sign", | ||
53 | "-x", "c"}; | ||
54 | |||
55 | CCArgs.append(CFlags.begin(), CFlags.end()); | ||
56 | CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs); | ||
57 | |||
58 | FrontendOptions& Opts = CI->getFrontendOpts(); | ||
59 | Opts.Inputs.clear(); | ||
60 | Opts.Inputs.emplace_back(Path, IK_C); | ||
61 | return CI; | ||
62 | } | ||
63 | |||
64 | static std::unique_ptr<llvm::Module> | ||
65 | getModuleFromSource(llvm::opt::ArgStringList CFlags, | ||
66 | StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS) | ||
67 | { | ||
68 | CompilerInstance Clang; | ||
69 | Clang.createDiagnostics(); | ||
70 | |||
71 | Clang.setVirtualFileSystem(&*VFS); | ||
72 | |||
73 | IntrusiveRefCntPtr<CompilerInvocation> CI = | ||
74 | createCompilerInvocation(std::move(CFlags), Path, | ||
75 | Clang.getDiagnostics()); | ||
76 | Clang.setInvocation(&*CI); | ||
77 | |||
78 | std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx)); | ||
79 | if (!Clang.ExecuteAction(*Act)) | ||
80 | return std::unique_ptr<llvm::Module>(nullptr); | ||
81 | |||
82 | return Act->takeModule(); | ||
83 | } | ||
84 | |||
85 | std::unique_ptr<llvm::Module> | ||
86 | getModuleFromSource(llvm::opt::ArgStringList CFlags, | ||
87 | StringRef Name, StringRef Content) | ||
88 | { | ||
89 | using namespace vfs; | ||
90 | |||
91 | llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS( | ||
92 | new OverlayFileSystem(getRealFileSystem())); | ||
93 | llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS( | ||
94 | new InMemoryFileSystem(true)); | ||
95 | |||
96 | /* | ||
97 | * pushOverlay helps setting working dir for MemFS. Must call | ||
98 | * before addFile. | ||
99 | */ | ||
100 | OverlayFS->pushOverlay(MemFS); | ||
101 | MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content)); | ||
102 | |||
103 | return getModuleFromSource(std::move(CFlags), Name, OverlayFS); | ||
104 | } | ||
105 | |||
106 | std::unique_ptr<llvm::Module> | ||
107 | getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path) | ||
108 | { | ||
109 | IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem()); | ||
110 | return getModuleFromSource(std::move(CFlags), Path, VFS); | ||
111 | } | ||
112 | |||
113 | std::unique_ptr<llvm::SmallVectorImpl<char>> | ||
114 | getBPFObjectFromModule(llvm::Module *Module) | ||
115 | { | ||
116 | using namespace llvm; | ||
117 | |||
118 | std::string TargetTriple("bpf-pc-linux"); | ||
119 | std::string Error; | ||
120 | const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error); | ||
121 | if (!Target) { | ||
122 | llvm::errs() << Error; | ||
123 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr); | ||
124 | } | ||
125 | |||
126 | llvm::TargetOptions Opt; | ||
127 | TargetMachine *TargetMachine = | ||
128 | Target->createTargetMachine(TargetTriple, | ||
129 | "generic", "", | ||
130 | Opt, Reloc::Static); | ||
131 | |||
132 | Module->setDataLayout(TargetMachine->createDataLayout()); | ||
133 | Module->setTargetTriple(TargetTriple); | ||
134 | |||
135 | std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>()); | ||
136 | raw_svector_ostream ostream(*Buffer); | ||
137 | |||
138 | legacy::PassManager PM; | ||
139 | if (TargetMachine->addPassesToEmitFile(PM, ostream, | ||
140 | TargetMachine::CGFT_ObjectFile)) { | ||
141 | llvm::errs() << "TargetMachine can't emit a file of this type\n"; | ||
142 | return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);; | ||
143 | } | ||
144 | PM.run(*Module); | ||
145 | |||
146 | return std::move(Buffer); | ||
147 | } | ||
148 | |||
149 | } | ||
150 | |||
151 | extern "C" { | ||
152 | void perf_clang__init(void) | ||
153 | { | ||
154 | perf::LLVMCtx.reset(new llvm::LLVMContext()); | ||
155 | LLVMInitializeBPFTargetInfo(); | ||
156 | LLVMInitializeBPFTarget(); | ||
157 | LLVMInitializeBPFTargetMC(); | ||
158 | LLVMInitializeBPFAsmPrinter(); | ||
159 | } | ||
160 | |||
161 | void perf_clang__cleanup(void) | ||
162 | { | ||
163 | perf::LLVMCtx.reset(nullptr); | ||
164 | llvm::llvm_shutdown(); | ||
165 | } | ||
166 | |||
167 | int perf_clang__compile_bpf(const char *filename, | ||
168 | void **p_obj_buf, | ||
169 | size_t *p_obj_buf_sz) | ||
170 | { | ||
171 | using namespace perf; | ||
172 | |||
173 | if (!p_obj_buf || !p_obj_buf_sz) | ||
174 | return -EINVAL; | ||
175 | |||
176 | llvm::opt::ArgStringList CFlags; | ||
177 | auto M = getModuleFromSource(std::move(CFlags), filename); | ||
178 | if (!M) | ||
179 | return -EINVAL; | ||
180 | auto O = getBPFObjectFromModule(&*M); | ||
181 | if (!O) | ||
182 | return -EINVAL; | ||
183 | |||
184 | size_t size = O->size_in_bytes(); | ||
185 | void *buffer; | ||
186 | |||
187 | buffer = malloc(size); | ||
188 | if (!buffer) | ||
189 | return -ENOMEM; | ||
190 | memcpy(buffer, O->data(), size); | ||
191 | *p_obj_buf = buffer; | ||
192 | *p_obj_buf_sz = size; | ||
193 | return 0; | ||
194 | } | ||
195 | } | ||