• clang-前端插件-给各种无花括号的“块”加花括号-基于llvm15--clang-plugin-add-brace


    处理的语句

    case

    术语约定或备忘

    1. case起止范围: 从冒号到下一个’case’开头, 简称有: case内 、case内容
    2. Ast: Abstract syntax tree: 抽象语法树

    没插入花括号的case

    若case内, 以下任一条成立,则 跳过该case 即 不会对该case内容用花括号包裹.

    • 有#define、
    • 有#include、
    • 有直属变量声明、
    • 空case、
    • 有宏调用

    详述

    预处理回调收集#include指令、宏定义

    CollectIncMacro_PPCb:Collect Inlucde Macro PPCallbacks : 收集Inlucde和Macro的预处理回调

    收集 #include、 #define , 以判断case起止范围内 有无 #include、 #define

    遍历switch内某case起止范围内每条语句

    RangeHasMacroAstVst: Range Has Macro Call Ast Vistor: 给定范围有无宏调用Ast遍历器

    名义上遍历整个switch下的Stmt,实际遍历 给定范围内( 即 case起止范围 内) 的语句,进行以下计算:

    1. hasMacro: case起止范围 有无宏调用,
      从而帮助过滤掉 有宏调用 的case
    2. caseKSubStmtCnt:    case起止范围 语句个数(即 case子语句个数), 
      从而帮助 过滤掉 空case
    3. VarDeclDirectlyInCaseKCnt:   直接写在'case'内的变量声明语句个数,
      即 直属变量声明个数 
      从而 帮助过滤掉 有直属变量声明 的case。
      直接写在'case'内的变量声明语句个数,包括以下两种情况:
      3.1. 直接写在'case'内,其父亲是case语句的
      3.2. 直接写在'case'内, 但是其父亲是switch块的.  
        即 存在 在case内的语句 但却不属于该case  而是直接属于switch, 此现象,直接导致 case的子语句 是伪命题,
          才使得 RangeHasMacroAstVst 不可能 实现无遗漏地 遍历 case下的子语句 , 
            只能扩大遍历范围到整个switch 并只关注case起止范围内的语句 才能 实现无遗漏地、精准地 遍历 case下的子语句。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实际运行花括号插件

    到此 加花括号插件完工了,在llvm-project上正常运行:

    sudo docker exec -it ubuntu2204_clang15Compile bash
    
    • 1

    弹出docker实例ubuntu2204_clang15Compile的bash命令行,以下命令都在此命令行下执行

    cd /pubx/
    
    git clone https://gitcode.net/pubz/llvm-project/-/commits/brc-dev-no_tick
    #即 https://gitcode.net/pubz/llvm-project/-/commit/bee38a325d0957a28b4d06cb4be3c251d143cdf0
    #克隆仓库llvm-project后目录结构如下: /pubx/llvm-project/.git/config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 步骤1: 对每个被直接编译的源文件中单语句加花括号

    对llvm-project的每个源文件的编译过程应用插件libBrcPlugin.so 以 对 该源文件中单语句加花括号

    source /pubx/llvm-project/doc_clang15_build/brc_build1_plugin.sh
    
    • 1

    brc_build1_plugin.sh

    • 步骤2: 对加了花括号后的llvm-project再次做正常的普通编译
    source /pubx/llvm-project/doc_clang15_build/brc_build2_directly.sh
    
    • 1

    brc_build2_directly.sh

    • 步骤3: 验证
    //编写c语言源文件 hello.c,内容如下:
    #include 
    int main(int argc, char** argv){
       
      int a,b;
      printf("a,b:");
      scanf("%d,%d",&a,&b);
      int sum=a+b, diff=a-b, div=a/b, mod=a%b;
      printf("sum=%d,diff=%d,div=%d,mod=%d\n",sum,diff,div,mod);
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    /pubx/build-llvm15/bin/clang-15  hello.c  -o hello.app
    ./hello.app
    a,b:45,21
    sum=66,diff=24,div=2,mod=3
    
    • 1
    • 2
    • 3
    • 4

    加完花括号的llvm-project源码编译出的编译器clang-15 对 hello.c 实施编译, 编译出二进制文件 hello.app,

    而该二进制文件 hello.app 正常运行

    由此说明 ,花括号加的位置基本正确。

    #统计

    find /pubx/llvm-project/ -not -path '*/.git/*' -type f  \( -name "*.cpp" -or -name "*.c"  \)   | xargs -I% grep -Hn    BrcXxx    % > /pubx/BrcXxx.log
    
    #把上一条bash命令抽成bash函数
    findBrcCommentThenSave() {
       
      set -x #bash启用显示执行的命令
      keyword=$1
      find /pubx/llvm-project/ -not -path '*/.git/*' -type f \( -name "*.cpp" -or -name "*.c" \) | xargs -I% grep -Hn "$keyword" % |tee  /pubx/"${keyword}.log"
      set +x #bash禁止显示执行的命令
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    findBrcCommentThenSave BrcThen
    findBrcCommentThenSave BrcSw
    findBrcCommentThenSave BrcElse
    findBrcCommentThenSave BrcFor
    findBrcCommentThenSave BrcForRange
    findBrcCommentThenSave BrcWhl
    findBrcCommentThenSave BrcSw
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    各种语句分别加了多少花括号

    ls -S /pubx/Brc* | xargs -I% sh -c  'wc -l %; ' 
    
    '''
    93201 /pubx/BrcThen.log
    29832 /pubx/BrcSw.log
    5539 /pubx/BrcElse.log
    3603 /pubx/BrcFor.log
    2187 /pubx/BrcForRange.log
    663 /pubx/BrcWhl.log
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    各种语句加了花括号的,有多少含有return

    这些单语句return,由于没有被花括号包裹,才没有被t_clock_tick插入栈变量释放语句。
    而tick插件栈变量分配、释放不平衡,具体为 栈变量共24万、最终残留2万没释放。 此不平衡是 由于 这些大约5万个单return语句没释放栈变量 导致的吗?
    如下所示,被BrcPlugin插入花括号的语句中 大约5万个含有return.

    ls -S /pubx/Brc* | xargs -I% sh -c  'echo -n "%    "; grep return % |wc -l '
    
    '''
    /pubx/BrcThen.log    50438
    /pubx/BrcSw.log    2681
    /pubx/BrcElse.log    815
    /pubx/BrcFor.log    6
    /pubx/BrcForRange.log    4
    /pubx/BrcWhl.log    2
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实现

    CMakeLists.txt

    cmake_minimum_required(VERSION 3.13.4)
    
    set(LIBFMT_DIR "/pubx/fmt/")
    #set(LIBFMT_STATIC /pubx/fmt/include)
    set(LIBFMT_INCLUDE "${LIBFMT_DIR}/include/")
    #set(LIBFMT_STATIC /pubx/fmt/build/libfmt.a)
    set(LIBFMT_STATIC "${LIBFMT_DIR}/build/libfmt.a")
    
    include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/include")
    include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/base_home/include/")
    
    if (NOT EXISTS "${LIBFMT_STATIC}")
      MESSAGE(FATAL_ERROR "libfmt静态库${LIBFMT_STATIC} 不存在,请参照 build-libfmt.sh 构建libfmt静态库")
    endif()
    
    if (NOT EXISTS "${LIBFMT_INCLUDE}")
      MESSAGE(FATAL_ERROR "libfmt头文件目录${LIBFMT_INCLUDE} 不存在,请参照 build-libfmt.sh 构建libfmt静态库")
    endif()
    
    #===============================================================================
    # 0. GET CLANG INSTALLATION DIR
    #修改默认编译器
    set(CT_Clang_INSTALL_DIR "/llvm_release_home/clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4")
    set(CMAKE_VERBOSE_MAKEFILE ON)
    set(CURSES_LIBRARY "/lib64/libncurses.so.6")
    set(CURSES_INCLUDE_PATH "/usr/include/")
    set(CMAKE_EXPORT_COMPILE_COMMANDS True)
    #编译器还是使用自带的gcc, 否则 调试时 没有 libstdc++  的调试信息,导致std::string在gdb中不显示,参考:https://stackoverflow.com/questions/58356385/python-exception-class-gdb-error-there-is-no-member-named-m-dataplus-whe/58356946#58356946
    #   gdb显示std::string时报错: There is no member named _M_dataplus。 因此gdb不显示std::string的值.
    #set(CMAKE_C_COMPILER "/llvm_release_home/clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4/bin/clang")
    #set(CMAKE_CXX_COMPILER "/llvm_release_home/clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4/bin/clang++")
    set(LLVM_DIR "/llvm_release_home/clang+llvm-15.0.0-x86_64-linux-gnu-rhel-8.4")
    #set(xxx "")
    
    project(clang-brc)
    #project放到默认编译器定义之后,否则cmake会死循环
    
    
    set(CT_LLVM_INCLUDE_DIR "${CT_Clang_INSTALL_DIR}/include/llvm")
    
    set(CT_LLVM_CMAKE_FILE "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/ClangConfig.cmake")
    
    # http://llvm.org/docs/CMake.html#embedding-llvm-in-your-project
    list(APPEND CMAKE_PREFIX_PATH "${CT_Clang_INSTALL_DIR}/lib/cmake/clang/")
    
    find_package(Clang REQUIRED CONFIG)
    
    # Sanity check. As Clang does not expose e.g. `CLANG_VERSION_MAJOR` through
    # AddClang.cmake, we have to use LLVM_VERSION_MAJOR instead.
    # TODO: Revisit when next version is released.
    if(NOT "15" VERSION_EQUAL "${LLVM_VERSION_MAJOR}")
      message(FATAL_ERROR "Found LLVM ${LLVM_VERSION_MAJOR}, but need LLVM 15")
    endif()
    
    message(STATUS "Found Clang ${LLVM_PACKAGE_VERSION}")
    message(STATUS "Using ClangConfig.cmake in: ${CT_Clang_INSTALL_DIR}")
    
    message("CLANG STATUS:
      Includes (clang)    ${
       CLANG_INCLUDE_DIRS}
      Includes (llvm)     ${
       LLVM_INCLUDE_DIRS}"
    )
    
    # Set the LLVM and Clang header and library paths
    include_directories(SYSTEM "${LLVM_INCLUDE_DIRS};${CLANG_INCLUDE_DIRS}")
    
    #===============================================================================
    # 3. CLANG-brc BUILD CONFIGURATION
    #===============================================================================
    # Use the same C++ standard as LLVM does
    set(CMAKE_CXX_STANDARD 17 CACHE STRING "")
    
    # Build type
    if(NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE Debug CACHE
          STRING "Build type (default Debug):" FORCE)
    endif()
    
    # Compiler flags
    set(CMAKE_CXX_FLAGS "${
       CMAKE_CXX_FLAGS} -Wall\
        -fdiagnostics-color=always")
    
    # LLVM/Clang is normally built without RTTI. Be consistent with that.
    if(NOT LLVM_ENABLE_RTTI)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
    endif()
    
    # -fvisibility-inlines-hidden is set when building LLVM and on Darwin warnings
    # are triggered if llvm-tutor is built without this flag (though otherwise it
    # builds fine). For consistency, add it here too.
    include(CheckCXXCompilerFlag)
    check_cxx_compiler_flag("-fvisibility-inlines-hidden"
      SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
  • 相关阅读:
    第八章 接口
    【如何去掉Unity点击运行时,Photon的警告弹窗】
    C#datagridview专题
    网站白屏优化
    支持券商的量化接口怎么使用python来执行交易过程?
    【TcaplusDB知识库】TcaplusDB OMS业务人员权限介绍
    开源协议说明LGPL
    Python数据分析与机器学习46-时间序列案例
    3、自然语言和单词的分布式表示(下)
    微信小程序获取用户头像调整
  • 原文地址:https://blog.csdn.net/hfcaoguilin/article/details/134085020