Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0
  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/Basic/Version.h"
 13#include "clang/CodeGen/CodeGenAction.h"
 14#include "clang/Frontend/CompilerInvocation.h"
 15#include "clang/Frontend/CompilerInstance.h"
 16#include "clang/Frontend/TextDiagnosticPrinter.h"
 17#include "clang/Tooling/Tooling.h"
 18#include "llvm/IR/LegacyPassManager.h"
 19#include "llvm/IR/Module.h"
 20#include "llvm/Option/Option.h"
 21#include "llvm/Support/FileSystem.h"
 22#include "llvm/Support/ManagedStatic.h"
 23#include "llvm/Support/TargetRegistry.h"
 24#include "llvm/Support/TargetSelect.h"
 25#include "llvm/Target/TargetMachine.h"
 26#include "llvm/Target/TargetOptions.h"
 27#include <memory>
 28
 29#include "clang.h"
 30#include "clang-c.h"
 31
 32namespace perf {
 33
 34static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
 35
 36using namespace clang;
 37
 38static CompilerInvocation *
 39createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
 40			 DiagnosticsEngine& Diags)
 41{
 42	llvm::opt::ArgStringList CCArgs {
 43		"-cc1",
 44		"-triple", "bpf-pc-linux",
 45		"-fsyntax-only",
 46		"-ferror-limit", "19",
 47		"-fmessage-length", "127",
 48		"-O2",
 49		"-nostdsysteminc",
 50		"-nobuiltininc",
 51		"-vectorize-loops",
 52		"-vectorize-slp",
 53		"-Wno-unused-value",
 54		"-Wno-pointer-sign",
 55		"-x", "c"};
 56
 57	CCArgs.append(CFlags.begin(), CFlags.end());
 58	CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs);
 59
 60	FrontendOptions& Opts = CI->getFrontendOpts();
 61	Opts.Inputs.clear();
 62	Opts.Inputs.emplace_back(Path,
 63			FrontendOptions::getInputKindForExtension("c"));
 64	return CI;
 65}
 66
 67static std::unique_ptr<llvm::Module>
 68getModuleFromSource(llvm::opt::ArgStringList CFlags,
 69		    StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS)
 70{
 71	CompilerInstance Clang;
 72	Clang.createDiagnostics();
 73
 74	Clang.setVirtualFileSystem(&*VFS);
 75
 76#if CLANG_VERSION_MAJOR < 4
 77	IntrusiveRefCntPtr<CompilerInvocation> CI =
 78		createCompilerInvocation(std::move(CFlags), Path,
 79					 Clang.getDiagnostics());
 80	Clang.setInvocation(&*CI);
 81#else
 82	std::shared_ptr<CompilerInvocation> CI(
 83		createCompilerInvocation(std::move(CFlags), Path,
 84					 Clang.getDiagnostics()));
 85	Clang.setInvocation(CI);
 86#endif
 87
 88	std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
 89	if (!Clang.ExecuteAction(*Act))
 90		return std::unique_ptr<llvm::Module>(nullptr);
 91
 92	return Act->takeModule();
 93}
 94
 95std::unique_ptr<llvm::Module>
 96getModuleFromSource(llvm::opt::ArgStringList CFlags,
 97		    StringRef Name, StringRef Content)
 98{
 99	using namespace vfs;
100
101	llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS(
102			new OverlayFileSystem(getRealFileSystem()));
103	llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS(
104			new InMemoryFileSystem(true));
105
106	/*
107	 * pushOverlay helps setting working dir for MemFS. Must call
108	 * before addFile.
109	 */
110	OverlayFS->pushOverlay(MemFS);
111	MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
112
113	return getModuleFromSource(std::move(CFlags), Name, OverlayFS);
114}
115
116std::unique_ptr<llvm::Module>
117getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
118{
119	IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem());
120	return getModuleFromSource(std::move(CFlags), Path, VFS);
121}
122
123std::unique_ptr<llvm::SmallVectorImpl<char>>
124getBPFObjectFromModule(llvm::Module *Module)
125{
126	using namespace llvm;
127
128	std::string TargetTriple("bpf-pc-linux");
129	std::string Error;
130	const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
131	if (!Target) {
132		llvm::errs() << Error;
133		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
134	}
135
136	llvm::TargetOptions Opt;
137	TargetMachine *TargetMachine =
138		Target->createTargetMachine(TargetTriple,
139					    "generic", "",
140					    Opt, Reloc::Static);
141
142	Module->setDataLayout(TargetMachine->createDataLayout());
143	Module->setTargetTriple(TargetTriple);
144
145	std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
146	raw_svector_ostream ostream(*Buffer);
147
148	legacy::PassManager PM;
149	bool NotAdded;
150#if CLANG_VERSION_MAJOR < 7
151	NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream,
152						      TargetMachine::CGFT_ObjectFile);
153#else
154	NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, nullptr,
155						      TargetMachine::CGFT_ObjectFile);
156#endif
157	if (NotAdded) {
158		llvm::errs() << "TargetMachine can't emit a file of this type\n";
159		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
160	}
161	PM.run(*Module);
162
163	return Buffer;
164}
165
166}
167
168extern "C" {
169void perf_clang__init(void)
170{
171	perf::LLVMCtx.reset(new llvm::LLVMContext());
172	LLVMInitializeBPFTargetInfo();
173	LLVMInitializeBPFTarget();
174	LLVMInitializeBPFTargetMC();
175	LLVMInitializeBPFAsmPrinter();
176}
177
178void perf_clang__cleanup(void)
179{
180	perf::LLVMCtx.reset(nullptr);
181	llvm::llvm_shutdown();
182}
183
184int perf_clang__compile_bpf(const char *filename,
185			    void **p_obj_buf,
186			    size_t *p_obj_buf_sz)
187{
188	using namespace perf;
189
190	if (!p_obj_buf || !p_obj_buf_sz)
191		return -EINVAL;
192
193	llvm::opt::ArgStringList CFlags;
194	auto M = getModuleFromSource(std::move(CFlags), filename);
195	if (!M)
196		return  -EINVAL;
197	auto O = getBPFObjectFromModule(&*M);
198	if (!O)
199		return -EINVAL;
200
201	size_t size = O->size_in_bytes();
202	void *buffer;
203
204	buffer = malloc(size);
205	if (!buffer)
206		return -ENOMEM;
207	memcpy(buffer, O->data(), size);
208	*p_obj_buf = buffer;
209	*p_obj_buf_sz = size;
210	return 0;
211}
212}