1 // SPDX-License-Identifier: GPL-2.0
3 * llvm C frontend for perf. Support dynamically compile C file
5 * Inspired by clang example code:
6 * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp
8 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
9 * Copyright (C) 2016 Huawei Inc.
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"
17 #include "llvm/IR/LegacyPassManager.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/Option/Option.h"
20 #include "llvm/Support/FileSystem.h"
21 #include "llvm/Support/ManagedStatic.h"
22 #include "llvm/Support/TargetRegistry.h"
23 #include "llvm/Support/TargetSelect.h"
24 #include "llvm/Target/TargetMachine.h"
25 #include "llvm/Target/TargetOptions.h"
33 static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
35 using namespace clang;
37 static CompilerInvocation *
38 createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
39 DiagnosticsEngine& Diags)
41 llvm::opt::ArgStringList CCArgs {
43 "-triple", "bpf-pc-linux",
45 "-ferror-limit", "19",
46 "-fmessage-length", "127",
56 CCArgs.append(CFlags.begin(), CFlags.end());
57 CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs);
59 FrontendOptions& Opts = CI->getFrontendOpts();
61 Opts.Inputs.emplace_back(Path, IK_C);
65 static std::unique_ptr<llvm::Module>
66 getModuleFromSource(llvm::opt::ArgStringList CFlags,
67 StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS)
69 CompilerInstance Clang;
70 Clang.createDiagnostics();
72 Clang.setVirtualFileSystem(&*VFS);
74 IntrusiveRefCntPtr<CompilerInvocation> CI =
75 createCompilerInvocation(std::move(CFlags), Path,
76 Clang.getDiagnostics());
77 Clang.setInvocation(&*CI);
79 std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
80 if (!Clang.ExecuteAction(*Act))
81 return std::unique_ptr<llvm::Module>(nullptr);
83 return Act->takeModule();
86 std::unique_ptr<llvm::Module>
87 getModuleFromSource(llvm::opt::ArgStringList CFlags,
88 StringRef Name, StringRef Content)
92 llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS(
93 new OverlayFileSystem(getRealFileSystem()));
94 llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS(
95 new InMemoryFileSystem(true));
98 * pushOverlay helps setting working dir for MemFS. Must call
101 OverlayFS->pushOverlay(MemFS);
102 MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
104 return getModuleFromSource(std::move(CFlags), Name, OverlayFS);
107 std::unique_ptr<llvm::Module>
108 getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
110 IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem());
111 return getModuleFromSource(std::move(CFlags), Path, VFS);
114 std::unique_ptr<llvm::SmallVectorImpl<char>>
115 getBPFObjectFromModule(llvm::Module *Module)
117 using namespace llvm;
119 std::string TargetTriple("bpf-pc-linux");
121 const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
123 llvm::errs() << Error;
124 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
127 llvm::TargetOptions Opt;
128 TargetMachine *TargetMachine =
129 Target->createTargetMachine(TargetTriple,
133 Module->setDataLayout(TargetMachine->createDataLayout());
134 Module->setTargetTriple(TargetTriple);
136 std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
137 raw_svector_ostream ostream(*Buffer);
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);;
147 return std::move(Buffer);
153 void perf_clang__init(void)
155 perf::LLVMCtx.reset(new llvm::LLVMContext());
156 LLVMInitializeBPFTargetInfo();
157 LLVMInitializeBPFTarget();
158 LLVMInitializeBPFTargetMC();
159 LLVMInitializeBPFAsmPrinter();
162 void perf_clang__cleanup(void)
164 perf::LLVMCtx.reset(nullptr);
165 llvm::llvm_shutdown();
168 int perf_clang__compile_bpf(const char *filename,
170 size_t *p_obj_buf_sz)
172 using namespace perf;
174 if (!p_obj_buf || !p_obj_buf_sz)
177 llvm::opt::ArgStringList CFlags;
178 auto M = getModuleFromSource(std::move(CFlags), filename);
181 auto O = getBPFObjectFromModule(&*M);
185 size_t size = O->size_in_bytes();
188 buffer = malloc(size);
191 memcpy(buffer, O->data(), size);
193 *p_obj_buf_sz = size;