clang 编译器下的inline探索

橙三吉。 提交于 2019-12-04 03:59:29

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会做优化,所以在代码准备阶段我也适当的调整了代码的复杂度,避免了不同级别的优化选项产生的汇编代码是一样的,导致分析的结果不准确。

分析

接下来就是分析步骤了,借住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也会被内嵌到调用的地方,而唯一不会生效的只有递归调用的方法了。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!