How to avoid constant propagation into functions?

Mason slash.tmp@free.fr
Wed Dec 7 13:06:00 GMT 2016


On 07/12/2016 13:35, Georg-Johann Lay wrote:

> On 07.12.2016 13:14, Segher Boessenkool wrote:
> 
>> On Wed, Dec 07, 2016 at 12:40:34PM +0100, Georg-Johann Lay wrote:
>>> ...to be more specific, attached is a C test case.
>>>
>>> Function mod_mul is noinline + noclone, and is called with
>>> n=317.  mod_mul itself does not use "317" anywhere.
>>>
>>> Yet when compiling with
>>>
>>> $ gcc mod.c -Os -save-temps -dp
>>>
>>> $ gcc --version
>>> gcc (GCC) 7.0.0 20161202 (experimental) [trunk revision 227650]
>>>
>>> and reading asm, there is:
>>>
>>> mod_mul:
>>> .LFB1:
>>> 	.cfi_startproc
>>> 	cmpl	$316, %edx	# 9	*cmpsi_1/1	[length = 6]
>>> 	pushq	%rbx	# 84	*pushdi2_rex64/1	[length = 1]
>>> 	.cfi_def_cfa_offset 16
>>> 	.cfi_offset 3, -16
>>> 	movl	%esi, %ebx	# 3	*movsi_internal/1	[length = 2]
>>> 	movl	%edx, %esi	# 4	*movsi_internal/1	[length = 2]
>>> 	jbe	.L2	# 10	*jcc_1	[length = 2]
>>> 	movl	$1, %edx	# 12	*movsi_internal/1	[length = 5]
>>> 	movl	$317, %edi	# 14	*movsi_internal/1	[length = 5]
>>> 	call	mod_mul	# 15	*call_value	[length = 5]
>>>
>>> So the constant 317 made its way into the code of mod_mul (insn 14),
>>> and insn 9 also uses this value.
>>>
>>> From my understanding "noclone" should avoid any such propagations?
>>
>> noclone prevents cloning the function, and it indeed has not been cloned.
>>
>> Because the function is static, GCC knows all callers, and it determines
>> all callers have n=317, so it optimises with that knowledge.
> 
> I understand this.  What I am after is a means to get a generated
> code that matches the source, no matter what context.
> 
> Imagine you called that function from assembler, then the code
> would crash.  And yes, when I am adding some other usage of
> mod_mul or let escape its address, then the propagation is not
> performed.

I must be missing something.

If a function is static, then you expressly told the compiler
"this function will not be called from anywhere else" thus
allowing the compiler to enable all kinds of optimizations,
such as constant propagation.

If a function might be called from another "module" (be it C,
assembly, etc) then it *cannot* be static.

> For example, this might have impact on writing test for GCC:
> 
> When I am writing a test with noinline + noclone then my
> expectation is that no such propagation happens, because
> otherwise a test might turn trivial...

Then put the function in its own compilation unit, and don't
make it static? What am I missing?

$ gcc -S -std=c99 -Os -fverbose-asm modx.c

mod_mul:
.LFB12:
	.cfi_startproc
	pushq	%rbp	#
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movl	%esi, %ebp	# a, a
	movl	%edx, %esi	# b,
	pushq	%rbx	#
	.cfi_def_cfa_offset 24
	.cfi_offset 3, -24
	movl	%edi, %ebx	# n, n
	pushq	%rcx	#
	.cfi_def_cfa_offset 32
	call	mod_norm	#
	xorl	%edx, %edx	# ab
.L2:
	testb	$1, %bpl	#, a
	je	.L3	#,
	addl	%eax, %edx	# b, ab
	movl	%edx, %ecx	# ab, tmp68
	subl	%ebx, %ecx	# n, tmp68
	cmpl	%ebx, %edx	# n, ab
	cmovnb	%ecx, %edx	# tmp68,, ab
.L3:
	cmpl	$1, %ebp	#, a
	jbe	.L9	#,
	addl	%eax, %eax	# b
	shrl	%ebp	# a
	movl	%eax, %ecx	# b, tmp69
	subl	%ebx, %ecx	# n, tmp69
	cmpl	%ebx, %eax	# n, b
	cmovnb	%ecx, %eax	# tmp69,, b
	jmp	.L2	#
.L9:
	movl	%edx, %eax	# ab,
	popq	%rdx	#
	.cfi_def_cfa_offset 24
	popq	%rbx	#
	.cfi_def_cfa_offset 16
	popq	%rbp	#
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc


Regards.



More information about the Gcc-help mailing list