zoukankan      html  css  js  c++  java
  • 编译器 llvm clang 源码转换示例

    编译器  llvm  clang  源码转换示例 

    从git获取llvm项目的源码方式:

    git clone https://github.com/llvm/llvm-project.git

    下载源码后,进入llvm-project目录包括如下内容:

     

     llvm-project/llvm目录包括如下内容:

     

      CLANG实战

    实战 利用Clang制作自己的编译器 source-to-source 源代码转换

    参考:

    https://github.com/Ewenwan/llvm-clang-samples/blob/master/src_clang/tooling_sample.cpp

    void foo(int* a, int *b) {

      if (a[0] > 1)

      {

        b[0] = 2;

      }

    }

    void bar(float x, float y); // just a declaration

    自动添加 添加注释

    // Begin function foo returning void

    void foo(int* a, int *b) {

      if (a[0] > 1) // the 'if' part

      {

        b[0] = 2;

      }

    }

    // End function foo

    void bar(float x, float y); // just a declaration

    LLVM实战

    函数签名

    C语言中的函数签名由以下几部分组成:

    • 返回类型
    • 函数名
    • 参数个数及参数类型

    比如

    int add(int a, int b) {
        return a + b;
    }

    这段C程序代码中的add函数的函数签名就是int add(int, int)

    待处理的C程序代码

    #include <stdio.h>
    #include <stdlib.h>
     
    void keep() {
        printf("\n");
    }
     
    int add(int a, int b) {
        return a + b;
    }
     
    int* getArr(int n) {
        return (int*)malloc(sizeof(int) * n);
    }
     
    int main(int argc, char** argv) {
        return 0;
    }

    项目运行结果是

     

     在待处理的代码中定义了包括main函数在内的四个函数,但是最终结果却是六个函数,这是因为调用了C标准库中的printf函数和malloc函数,编译器在预处理阶段将这两个函数的声明加入到了代码中。

    另外一个值得关注之处是,与C语言中intchar等类型不同,打印出来的函数签名中的类型是i32i8,这其实是因为我们首先需要把待处理的C程序代码转换为LLVM IR字节码,然后才会用自定义LLVM项目对其进行处理,打印出来的类型其实是LLVM IR的类型,除此之外,long对应i64float对应f32double对应f64,不过LLVM IR void和指针两种类型还是与C语言相同的。

    函数签名

    C语言中的函数签名由以下几部分组成:

    返回类型 函数名 (参数个数及参数类型)

    // 本程序 输入 llvm IR文件 输出 IR中的函数签名
    // 输入的IR文件 可以由clang编译得到
    // 例如 clang -emit-llvm -c test.c -o test.bc // test.c为测试程序
    // 本程序编译命令
    // clang++ $(llvm-config --cxxflags --ldflags --libs) main.cpp -o main
    // 运行程序
    // ./main test.bc
     
    // 引入相关LLVM头文件
    #include <llvm/IR/LLVMContext.h>
    #include <llvm/IR/Function.h>
    #include <llvm/IR/Module.h>
    #include <llvm/IRReader/IRReader.h>
    #include <llvm/Support/SourceMgr.h>
    #include <llvm/Support/CommandLine.h>
     
    using namespace llvm;
     
    // LLVM上下文全局变量
    static ManagedStatic<LLVMContext> GlobalContext;
     
    // 命令行位置参数全局变量, 这个参数的含义是需要处理的LLVM IR字节码的文件名
    static cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<filename>.bc"), cl::Required);
     
    int main(int argc, char **argv) {
        // 诊断实例
        SMDiagnostic Err;
        // 格式化命令行参数,
        cl::ParseCommandLineOptions(argc, argv);
        // 读取并格式化LLVM IR字节码文件, 返回LLVM Module(Module是LLVM IR的顶级容器)
        std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, *GlobalContext);
        // 错误处理
        if (!M) {
            Err.print(argv[0], errs());
            return 1;
        }
        // 遍历Module中的每一个Function
        for (Function &F:*M) { // c++ 语法 范围for F是 IR模块中的每一个函数的引用
            // 过滤掉那些以llvm.开头的无关函数
            if (!F.isIntrinsic()) {
                // 打印函数返回类型
                outs() << *(F.getReturnType());
                // 打印函数名
                outs() << ' ' << F.getName() << '('; // 函数名有可能和c文件里的不同(加了一些属性描述)
                // 遍历函数的每一个参数
                for (Function::arg_iterator it = F.arg_begin(), ie = F.arg_end(); it != ie; it++) {
                    // 打印参数类型
                    outs() << *(it->getType());
                    if (it != ie - 1) {
                        outs() << ", ";
                    }
                }
                outs() << ")\n";
            }
        }
    }

    项目编译运行

    在编译项目之前,需要确认一下编译运行环境 :

    Ÿ   操作系统:Ubuntu 18.04 64位

    Ÿ   LLVM版本:9.0.0

    Ÿ   待处理的C程序代码文件:test.c

    Ÿ   项目代码文件:main.cpp

    然后获取待处理的C程序代码的LLVM IR字节码

    clang -emit-llvm -c test.c -o test.bc

    再编译项目代码

    clang++ $(llvm-config --cxxflags --ldflags --libs) main.cpp -o main

    最后运行得到上文图示的结果

    ./main test.bc

     

    参考链接:

    https://www.freesion.com/article/3548547366/

    https://www.freesion.com/article/4240352588/

    https://zhuanlan.zhihu.com/p/102270840

    https://github.com/Ewenwan/llvm-clang-samples/blob/master/src_clang/tooling_sample.cpp

     

    人工智能芯片与自动驾驶
  • 相关阅读:
    HBase 在HDFS上的物理目录结构
    Hbase-site.xml
    hbase-default.xml(Hbase 默认参数翻译)
    flink-conf.yaml
    Spark Standalone spark-default.conf
    Spark Standalone spark-env.sh
    windows linux 文件编码转换
    Hbase G1 gc 调优最终参数
    python
    python
  • 原文地址:https://www.cnblogs.com/wujianming-110117/p/15754883.html
Copyright © 2011-2022 走看看