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