lkml.org 
[lkml]   [2016]   [Nov]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 14/34] perf clang: Add builtin clang support ant test case
    Date
    Add basic clang support in clang.cpp and test__clang() testcase. The
    first testcase checks if builtin clang is able to generate LLVM IR.

    tests/clang.c is a proxy. Real testcase resides in
    utils/c++/clang-test.cpp in c++ and exports C interface to perf test
    subsystem.

    Test result:

    $ perf test -v clang
    51: Test builtin clang support :
    51.1: Test builtin clang compile C source to IR :
    --- start ---
    test child forked, pid 13215
    test child finished with 0
    ---- end ----
    Test builtin clang support subtest 0: Ok

    Signed-off-by: Wang Nan <wangnan0@huawei.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: Alexei Starovoitov <ast@fb.com>
    Cc: He Kuang <hekuang@huawei.com>
    Cc: Jiri Olsa <jolsa@kernel.org>
    Cc: Zefan Li <lizefan@huawei.com>
    Cc: pi3orama@163.com
    ---
    tools/perf/tests/Build | 1 +
    tools/perf/tests/builtin-test.c | 9 ++++
    tools/perf/tests/clang.c | 42 +++++++++++++++++
    tools/perf/tests/tests.h | 3 ++
    tools/perf/util/Build | 2 +
    tools/perf/util/c++/Build | 2 +
    tools/perf/util/c++/clang-c.h | 16 +++++++
    tools/perf/util/c++/clang-test.cpp | 31 ++++++++++++
    tools/perf/util/c++/clang.cpp | 96 ++++++++++++++++++++++++++++++++++++++
    tools/perf/util/c++/clang.h | 16 +++++++
    10 files changed, 218 insertions(+)
    create mode 100644 tools/perf/tests/clang.c
    create mode 100644 tools/perf/util/c++/Build
    create mode 100644 tools/perf/util/c++/clang-c.h
    create mode 100644 tools/perf/util/c++/clang-test.cpp
    create mode 100644 tools/perf/util/c++/clang.cpp
    create mode 100644 tools/perf/util/c++/clang.h

    diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
    index af3ec94..6676c2d 100644
    --- a/tools/perf/tests/Build
    +++ b/tools/perf/tests/Build
    @@ -43,6 +43,7 @@ perf-y += sdt.o
    perf-y += is_printable_array.o
    perf-y += bitmap.o
    perf-y += perf-hooks.o
    +perf-y += clang.o

    $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
    $(call rule_mkdir)
    diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
    index dab83f7..33aaa52 100644
    --- a/tools/perf/tests/builtin-test.c
    +++ b/tools/perf/tests/builtin-test.c
    @@ -234,6 +234,15 @@ static struct test generic_tests[] = {
    .func = test__perf_hooks,
    },
    {
    + .desc = "Test builtin clang support",
    + .func = test__clang,
    + .subtest = {
    + .skip_if_fail = true,
    + .get_nr = test__clang_subtest_get_nr,
    + .get_desc = test__clang_subtest_get_desc,
    + }
    + },
    + {
    .func = NULL,
    },
    };
    diff --git a/tools/perf/tests/clang.c b/tools/perf/tests/clang.c
    new file mode 100644
    index 0000000..57ee160
    --- /dev/null
    +++ b/tools/perf/tests/clang.c
    @@ -0,0 +1,42 @@
    +#include "tests.h"
    +#include "debug.h"
    +#include "util.h"
    +#include "c++/clang-c.h"
    +
    +static struct {
    + int (*func)(void);
    + const char *desc;
    +} clang_testcase_table[] = {
    +#ifdef HAVE_LIBCLANGLLVM_SUPPORT
    + {
    + .func = test__clang_to_IR,
    + .desc = "Test builtin clang compile C source to IR",
    + },
    +#endif
    +};
    +
    +int test__clang_subtest_get_nr(void)
    +{
    + return (int)ARRAY_SIZE(clang_testcase_table);
    +}
    +
    +const char *test__clang_subtest_get_desc(int i)
    +{
    + if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table))
    + return NULL;
    + return clang_testcase_table[i].desc;
    +}
    +
    +#ifndef HAVE_LIBCLANGLLVM_SUPPORT
    +int test__clang(int i __maybe_unused)
    +{
    + return TEST_SKIP;
    +}
    +#else
    +int test__clang(int i __maybe_unused)
    +{
    + if (i < 0 || i >= (int)ARRAY_SIZE(clang_testcase_table))
    + return TEST_FAIL;
    + return clang_testcase_table[i].func();
    +}
    +#endif
    diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
    index 3a1f98f..0d7b251 100644
    --- a/tools/perf/tests/tests.h
    +++ b/tools/perf/tests/tests.h
    @@ -92,6 +92,9 @@ int test__sdt_event(int subtest);
    int test__is_printable_array(int subtest);
    int test__bitmap_print(int subtest);
    int test__perf_hooks(int subtest);
    +int test__clang(int subtest);
    +const char *test__clang_subtest_get_desc(int subtest);
    +int test__clang_subtest_get_nr(void);

    #if defined(__arm__) || defined(__aarch64__)
    #ifdef HAVE_DWARF_UNWIND_SUPPORT
    diff --git a/tools/perf/util/Build b/tools/perf/util/Build
    index b2a47aa..743a889 100644
    --- a/tools/perf/util/Build
    +++ b/tools/perf/util/Build
    @@ -125,6 +125,8 @@ endif

    libperf-y += perf-hooks.o

    +libperf-$(CONFIG_CXX) += c++/
    +
    CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
    # avoid compiler warnings in 32-bit mode
    CFLAGS_genelf_debug.o += -Wno-packed
    diff --git a/tools/perf/util/c++/Build b/tools/perf/util/c++/Build
    new file mode 100644
    index 0000000..988fef1
    --- /dev/null
    +++ b/tools/perf/util/c++/Build
    @@ -0,0 +1,2 @@
    +libperf-$(CONFIG_CLANGLLVM) += clang.o
    +libperf-$(CONFIG_CLANGLLVM) += clang-test.o
    diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h
    new file mode 100644
    index 0000000..dcde4b5
    --- /dev/null
    +++ b/tools/perf/util/c++/clang-c.h
    @@ -0,0 +1,16 @@
    +#ifndef PERF_UTIL_CLANG_C_H
    +#define PERF_UTIL_CLANG_C_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +extern void perf_clang__init(void);
    +extern void perf_clang__cleanup(void);
    +
    +extern int test__clang_to_IR(void);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +#endif
    diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp
    new file mode 100644
    index 0000000..3da6bfa
    --- /dev/null
    +++ b/tools/perf/util/c++/clang-test.cpp
    @@ -0,0 +1,31 @@
    +#include "clang.h"
    +#include "clang-c.h"
    +#include "llvm/IR/Function.h"
    +#include "llvm/IR/LLVMContext.h"
    +
    +class perf_clang_scope {
    +public:
    + explicit perf_clang_scope() {perf_clang__init();}
    + ~perf_clang_scope() {perf_clang__cleanup();}
    +};
    +
    +extern "C" {
    +
    +int test__clang_to_IR(void)
    +{
    + perf_clang_scope _scope;
    +
    + std::unique_ptr<llvm::Module> M =
    + perf::getModuleFromSource("perf-test.c",
    + "int myfunc(void) {return 1;}");
    +
    + if (!M)
    + return -1;
    +
    + for (llvm::Function& F : *M)
    + if (F.getName() == "myfunc")
    + return 0;
    + return -1;
    +}
    +
    +}
    diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp
    new file mode 100644
    index 0000000..c17b117
    --- /dev/null
    +++ b/tools/perf/util/c++/clang.cpp
    @@ -0,0 +1,96 @@
    +/*
    + * llvm C frontend for perf. Support dynamically compile C file
    + *
    + * Inspired by clang example code:
    + * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp
    + *
    + * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
    + * Copyright (C) 2016 Huawei Inc.
    + */
    +
    +#include "clang/CodeGen/CodeGenAction.h"
    +#include "clang/Frontend/CompilerInvocation.h"
    +#include "clang/Frontend/CompilerInstance.h"
    +#include "clang/Frontend/TextDiagnosticPrinter.h"
    +#include "clang/Tooling/Tooling.h"
    +#include "llvm/IR/Module.h"
    +#include "llvm/Option/Option.h"
    +#include "llvm/Support/ManagedStatic.h"
    +#include <memory>
    +
    +#include "clang.h"
    +#include "clang-c.h"
    +
    +namespace perf {
    +
    +static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
    +
    +using namespace clang;
    +
    +static vfs::InMemoryFileSystem *
    +buildVFS(StringRef& Name, StringRef& Content)
    +{
    + vfs::InMemoryFileSystem *VFS = new vfs::InMemoryFileSystem(true);
    + VFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
    + return VFS;
    +}
    +
    +static CompilerInvocation *
    +createCompilerInvocation(StringRef& Path, DiagnosticsEngine& Diags)
    +{
    + llvm::opt::ArgStringList CCArgs {
    + "-cc1",
    + "-triple", "bpf-pc-linux",
    + "-fsyntax-only",
    + "-ferror-limit", "19",
    + "-fmessage-length", "127",
    + "-O2",
    + "-nostdsysteminc",
    + "-nobuiltininc",
    + "-vectorize-loops",
    + "-vectorize-slp",
    + "-Wno-unused-value",
    + "-Wno-pointer-sign",
    + "-x", "c"};
    + CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs);
    +
    + FrontendOptions& Opts = CI->getFrontendOpts();
    + Opts.Inputs.clear();
    + Opts.Inputs.emplace_back(Path, IK_C);
    + return CI;
    +}
    +
    +std::unique_ptr<llvm::Module>
    +getModuleFromSource(StringRef Name, StringRef Content)
    +{
    + CompilerInstance Clang;
    + Clang.createDiagnostics();
    +
    + IntrusiveRefCntPtr<vfs::FileSystem> VFS = buildVFS(Name, Content);
    + Clang.setVirtualFileSystem(&*VFS);
    +
    + IntrusiveRefCntPtr<CompilerInvocation> CI =
    + createCompilerInvocation(Name, Clang.getDiagnostics());
    + Clang.setInvocation(&*CI);
    +
    + std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
    + if (!Clang.ExecuteAction(*Act))
    + return std::unique_ptr<llvm::Module>(nullptr);
    +
    + return Act->takeModule();
    +}
    +
    +}
    +
    +extern "C" {
    +void perf_clang__init(void)
    +{
    + perf::LLVMCtx.reset(new llvm::LLVMContext());
    +}
    +
    +void perf_clang__cleanup(void)
    +{
    + perf::LLVMCtx.reset(nullptr);
    + llvm::llvm_shutdown();
    +}
    +}
    diff --git a/tools/perf/util/c++/clang.h b/tools/perf/util/c++/clang.h
    new file mode 100644
    index 0000000..f64483b
    --- /dev/null
    +++ b/tools/perf/util/c++/clang.h
    @@ -0,0 +1,16 @@
    +#ifndef PERF_UTIL_CLANG_H
    +#define PERF_UTIL_CLANG_H
    +
    +#include "llvm/ADT/StringRef.h"
    +#include "llvm/IR/LLVMContext.h"
    +#include "llvm/IR/Module.h"
    +#include <memory>
    +namespace perf {
    +
    +using namespace llvm;
    +
    +std::unique_ptr<Module>
    +getModuleFromSource(StringRef Name, StringRef Content);
    +
    +}
    +#endif
    --
    2.10.1
    \
     
     \ /
      Last update: 2016-11-15 05:14    [W:4.268 / U:0.108 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site