文档章节

clang 编译器下的inline探索

aron1992
 aron1992
发布于 11/09 18:36
字数 1044
阅读 16
收藏 0

clang 编译器下的inline探索

今天看到一篇文章说到inline内联函数的介绍文章,里面提到内联函数的作用以及适用场景,刚好最近看了clang编译器的一些资料,正好发了点时间探索下

这篇文章的介绍如下 内联函数(https://www.cnblogs.com/spock12345/p/11551147.html) inline函数的作用:不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处,适用于功能简单,规模较小又使用频繁的函数。

准备

代码

使用的示例代码如下,我这里把文件命名为a.c

#include <stdio.h>

int inlinecalc(int a, int b, int fac);
int inline_loopFunc();
void inline_recCallFunc(int count);

inline int inline_loopFunc(){
	//实现
	int count = 1000;
	for (int i = 0; i < count; ++i)
	{
		printf("%d\n", i);
	}
	return 0;
}

inline void inline_recCallFunc(int count){
	if (count > 0) {
		inline_recCallFunc(count-1);
	}
	printf("%d\n", count);
}

int recCallFunc(){
	inline_recCallFunc(10);
	return 0;
}

int loopFunc(){
	inline_loopFunc();
	return 0;
}

inline int inlinecalc(int a, int b, int fac) {
	if (fac > 2)
	{
		return a * 2 + b;
	}
	return a + b;
}

int calc(int a, int b, int fac) {
	int tmp = inlinecalc(a, b, fac);
	return tmp * 1.2 / fac;
}

int main(int argc, char const *argv[])
{
	int res = inlinecalc(111, 222, argc);
	printf("result = %d\n", res);

	loopFunc();

	recCallFunc();

	return 0;
}

clang的优化级别

这个知识点也先介绍下,clang编译器有多个优化选项,不同的优化选项下生成的汇编代码是不一样的,在Xcode中的配置是如下的,使用clang命令行工具对应的则是-O0-O1-O2等不同的优化选项,后面会使用到。因为clang会做优化,所以在代码准备阶段我也适当的调整了代码的复杂度,避免了不同级别的优化选项产生的汇编代码是一样的,导致分析的结果不准确。

image-20191109170129182

分析

接下来就是分析步骤了,借住clang的命令行工具,clang可以把源文件转换为汇编代码

clang a.c -O0 -S -o -
  • -O0 表示优化级别,上面有介绍过了
  • -S 表示生成汇编代码
  • -o - 表示把结果输出到控制台

O0/O1级别

	.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	movl	%edi, %eax
	movl	$111, %edi
	movl	$222, %esi
	movl	%eax, %edx
	callq	_inlinecalc
	movl	%eax, %ecx
	leaq	L_.str.1(%rip), %rdi
	xorl	%eax, %eax
	movl	%ecx, %esi
	callq	_printf
	callq	_loopFunc
	callq	_recCallFunc
	xorl	%eax, %eax
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function

这个级别做了很少的优化,源码中的三个inline方法都是当做方法调用,没有嵌入到调用的地方

O2级别

	.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	cmpl	$2, %edi
	setg	%cl
	movl	$111, %esi
	shll	%cl, %esi
	addl	$222, %esi
	leaq	L_.str.1(%rip), %rdi
	xorl	%eax, %eax
	callq	_printf
	callq	_loopFunc
	movl	$10, %edi
	callq	_inline_recCallFunc
	xorl	%eax, %eax
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function

O1级别中可以看到有两点的变化

  • _inlinecalc方法的调用已经没有了,被嵌入到了调用的地方了,对应的代码是从 cmpl $2, %edicallq _printf 结束

O3级别

	.globl	_main                   ## -- Begin function main
	.p2align	4, 0x90
_main:                                  ## @main
	.cfi_startproc
## %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	pushq	%r14
	pushq	%rbx
	.cfi_offset %rbx, -32
	.cfi_offset %r14, -24
	cmpl	$2, %edi
	setg	%cl
	movl	$111, %esi
	shll	%cl, %esi
	addl	$222, %esi
	leaq	L_.str.1(%rip), %rdi
	xorl	%eax, %eax
	callq	_printf
	leaq	L_.str(%rip), %r14
	xorl	%ebx, %ebx
	.p2align	4, 0x90
LBB6_1:                                 ## =>This Inner Loop Header: Depth=1
	xorl	%eax, %eax
	movq	%r14, %rdi
	movl	%ebx, %esi
	callq	_printf
	incl	%ebx
	cmpl	$1000, %ebx             ## imm = 0x3E8
	jne	LBB6_1
## %bb.2:
	movl	$10, %edi
	callq	_inline_recCallFunc
	xorl	%eax, %eax
	popq	%rbx
	popq	%r14
	popq	%rbp
	retq
	.cfi_endproc
                                        ## -- End function

这个级别包含中有for循环的内联方法也被嵌入到了调用的地方,inline也是生效的,另外根据我自己的验证,包含有switch语句的inline也会被内嵌到调用的地方,而唯一不会生效的只有递归调用的方法了。

© 著作权归作者所有

aron1992

aron1992

粉丝 65
博文 93
码字总数 168392
作品 0
厦门
程序员
私信 提问
关于Nebula3工程的几个编译选项

研究一下人家是怎么通过编译选项来优化性能的 DEBUG: C++/Code Generation/Enable String Pooling: Yes (/GF) 该选项使编译器能够为执行过程中程序映像和内存中的相同字符串创建单个副本,从...

长平狐
2012/11/12
89
0
c语言中的的内联(inline)函数

c语言中的的内联(inline)函数 发表于 2011 年 01 月 26 日 由 admin c/c++中的inline,使用在函数声明处,表示程序员请求编译器在此函数的被调用处将此函数实现插入,而不是像普通函数那样生...

长平狐
2012/09/03
311
0
C++中的 .h 和 .cpp 区别详解

在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析。于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念。 对于以C起步,C#作为“母语...

刘小米_思聪
2014/09/18
2.4K
0
C++17 标准正式发布:开发者可更简单地编写和维护代码

昨日,ISO C++ 委员会正式发布了 C++ 17 标准,正式名称为 ISO/IEC 14882:2017。 基于 C++ 11,C++ 17 旨在使 C++ 成为一个不那么臃肿复杂的编程语言,以简化该语言的日常使用,使开发者可以...

局长
2017/12/06
9.9K
43
《深度探索C++对象模型》读书笔记(2)。

default constructor仅在编译器需要它时,才会被合成出来。 通常来说,由编译器合成出来的default constructor是没啥用的(trivial),但有以下几种例外: (1)带有“Default Constructor”...

长平狐
2012/10/08
637
0

没有更多内容

加载失败,请刷新页面

加载更多

Kafka实战(五) - 核心API及适用场景全面解析

1 四个核心API ● Producer API 允许一个应用程序发布一串流式的数据到一个或者多个Kafka topic。 ● Consumer API 允许一个应用程序订阅一个或多个topic ,并且对发布给他们的流式数据进行处...

JavaEdge
56分钟前
9
0
实现线程的第三种方式——Callable & Future

Callable Runnable 封装一个异步运行的任务, 可以把它想象成为一个没有参数和返回值的异步方 法。Callable 与 Runnable 类似, 但是有返回值。Callable 接口是一个参数化的类型, 只有一 个...

ytuan996
今天
11
0
OSChina 周六乱弹 —— 不要摁F了!

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 : 朴树写的词曲都给人一种莫名的失落感,不过这首歌他自己却没有唱,换成赵传这种高音阶嘶喊的确很好,低沉但却有力,老男人的呐喊...

小小编辑
今天
12
0
Android Binder机制 - interface_cast和asBinder讲解

研究Android底层代码时,尤其是Binder跨进程通信时,经常会发现interface_cast和asBinder,很容易被这两个函数绕晕,下面来讲解一下: interface_cast 下面根据下述ICameraClient例子进行分析...

天王盖地虎626
昨天
13
0
计算机实现原理专题--存储器的实现(二)

计算机实现原理专题--存储器的实现(一)中描述了一种可以记住输入端变化的装置。现需要对其功能进行扩充,我们将上面的开关定义为置位,下面的开关定义为复位,然后需要增加一个保持位,当保...

FAT_mt
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部