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

2023-10-27 23:44

本文主要是介绍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下的子语句。

实际运行花括号插件

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

sudo docker exec -it ubuntu2204_clang15Compile bash

弹出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: 对每个被直接编译的源文件中单语句加花括号

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

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

brc_build1_plugin.sh

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

brc_build2_directly.sh

  • 步骤3: 验证
//编写c语言源文件 hello.c,内容如下:
#include <stdio.h>
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;
}
/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

加完花括号的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=$1find /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禁止显示执行的命令
}
findBrcCommentThenSave BrcThen
findBrcCommentThenSave BrcSw
findBrcCommentThenSave BrcElse
findBrcCommentThenSave BrcFor
findBrcCommentThenSave BrcForRange
findBrcCommentThenSave BrcWhl
findBrcCommentThenSave BrcSw

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

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
'''

各种语句加了花括号的,有多少含有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
'''

实现

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 CACHESTRING "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

这篇关于clang-前端插件-给各种无花括号的“块”加花括号-基于llvm15--clang-plugin-add-brace的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/289231

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

HTML提交表单给python

python 代码 from flask import Flask, request, render_template, redirect, url_forapp = Flask(__name__)@app.route('/')def form():# 渲染表单页面return render_template('./index.html')@app.route('/submit_form',

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,