[IPOL discuss] Fast DCT using FFTW3

Pascal Monasse monasse at imagine.enpc.fr
Tue Feb 28 23:52:17 CET 2012


Hi Miguel,

Yes, your example works according to your analysis, but only because your 
function f is simple enough and the compiler can inline it instead of doing a 
function call. But I think if f is complex enough, even it has no side effect 
(no printf, independent of any global variable), the compiler would not be 
able to inline it and it would still be called 3 times, even though the result 
is the same at each call.

Best,
Pascal

On Tuesday, February 28, 2012 10:57:36 PM Miguel Colom wrote:
> Hi Pascal,
> 
> > Hi Miguel,
> > 
> >> It even analyzes the numerical expressions and tries to compute it the
> >> shorter and faster way.
> >> For example, if y = f(y) + 2*f(y) + 3*f(y), it doesn't call f(y) three
> >> times.
> > 
> > I doubt that the compiler would dare such an aggressive optimization. f
> > may
> > have side effects that the compiler is not able to analyze, therefore it
> > may
> > think it is safer to call f(y) three times...
> 
> GCC is really smart doing optimizations. Of course, it can be configured
> with the -O flag to set the level of optimization.
> 
> To prove it, I wrote this small program:
> 
> #include <stdio.h>
> 
> int f(int x) {
>   return x*x*x;
> }
> 
> int main(int argc, char *argv[]) {
>  int result;
>  int x = 23;
> 
>  result = 2*f(x) + 3*f(x) + 4*f(x);
> 
>  printf("The result is %d\n", result);
>  return 0;
> }
> 
> That is, f(x) is the x^3 function and then the program just computes
> 2*f(x) + 3*f(x) + 4*f(x) and prints the result.
> 
> If no optimization is set, the intermediate assembly GCC produces is the
> following:
> 
> ------------------------------------
> 	.file	"main.c"
> 	.text
> 	.globl	f
> 	.type	f, @function
> f:
> .LFB0:
> 	.cfi_startproc
> 	pushl	%ebp
> 	.cfi_def_cfa_offset 8
> 	.cfi_offset 5, -8
> 	movl	%esp, %ebp
> 	.cfi_def_cfa_register 5
> 	movl	8(%ebp), %eax
> 	imull	8(%ebp), %eax
> 	imull	8(%ebp), %eax
> 	popl	%ebp
> 	.cfi_def_cfa 4, 4
> 	.cfi_restore 5
> 	ret
> 	.cfi_endproc
> .LFE0:
> 	.size	f, .-f
> 	.section	.rodata
> .LC0:
> 	.string	"The result is %d\n"
> 	.text
> 	.globl	main
> 	.type	main, @function
> main:
> .LFB1:
> 	.cfi_startproc
> 	pushl	%ebp
> 	.cfi_def_cfa_offset 8
> 	.cfi_offset 5, -8
> 	movl	%esp, %ebp
> 	.cfi_def_cfa_register 5
> 	pushl	%ebx
> 	andl	$-16, %esp
> 	subl	$32, %esp
> 	movl	$23, 24(%esp)
> 	movl	24(%esp), %eax
> 	movl	%eax, (%esp)
> 	.cfi_offset 3, -12
> 	call	f
> 	leal	(%eax,%eax), %ebx
> 	movl	24(%esp), %eax
> 	movl	%eax, (%esp)
> 	call	f
> 	movl	%eax, %edx
> 	movl	%edx, %eax
> 	addl	%eax, %eax
> 	addl	%edx, %eax
> 	addl	%eax, %ebx
> 	movl	24(%esp), %eax
> 	movl	%eax, (%esp)
> 	call	f
> 	sall	$2, %eax
> 	addl	%ebx, %eax
> 	movl	%eax, 28(%esp)
> 	movl	$.LC0, %eax
> 	movl	28(%esp), %edx
> 	movl	%edx, 4(%esp)
> 	movl	%eax, (%esp)
> 	call	printf
> 	movl	$0, %eax
> 	movl	-4(%ebp), %ebx
> 	leave
> 	.cfi_restore 5
> 	.cfi_def_cfa 4, 4
> 	.cfi_restore 3
> 	ret
> 	.cfi_endproc
> .LFE1:
> 	.size	main, .-main
> 	.ident	"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
> 	.section	.note.GNU-stack,"", at progbits
> ------------------------------------
> The compiler defines the function f and then calls it three times.
> 
> 
> Nevertheless, if we compile it with "gcc -O99 -S main.c" the output is the
> following:
> ------------------------------------
> 	.file	"main.c"
> 	.text
> 	.p2align 4,,15
> 	.globl	f
> 	.type	f, @function
> f:
> .LFB22:
> 	.cfi_startproc
> 	movl	4(%esp), %edx
> 	movl	%edx, %eax
> 	imull	%edx, %eax
> 	imull	%edx, %eax
> 	ret
> 	.cfi_endproc
> .LFE22:
> 	.size	f, .-f
> 	.section	.rodata.str1.1,"aMS", at progbits,1
> .LC0:
> 	.string	"The result is %d\n"
> 	.section	.text.startup,"ax", at progbits
> 	.p2align 4,,15
> 	.globl	main
> 	.type	main, @function
> main:
> .LFB23:
> 	.cfi_startproc
> 	pushl	%ebp
> 	.cfi_def_cfa_offset 8
> 	.cfi_offset 5, -8
> 	movl	%esp, %ebp
> 	.cfi_def_cfa_register 5
> 	andl	$-16, %esp
> 	subl	$16, %esp
> 	movl	$109503, 8(%esp)
> 	movl	$.LC0, 4(%esp)
> 	movl	$1, (%esp)
> 	call	__printf_chk
> 	xorl	%eax, %eax
> 	leave
> 	.cfi_restore 5
> 	.cfi_def_cfa 4, 4
> 	ret
> 	.cfi_endproc
> .LFE23:
> 	.size	main, .-main
> 	.ident	"GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
> 	.section	.note.GNU-stack,"", at progbits
> ------------------------------------
> 
> The difference is clear: now the function f is NEVER called.
> The compiler analyzes the expression, computes the result at compile-time
> if it's possible and substitutes the call f(x) with its result (109503)
> with the instruction "movl	$109503, 8(%esp)"
> 
> However, if the compiler detects that the function does something else
> that the program needs, the function is called three times.
> 
> int f(int x) {
>   printf("Do something\n");
>   return x*x*x;
> }
> 
> Best,
> Miguel
> 
> 
> _______________________________________________
> discuss mailing list
> discuss at list.ipol.im
> http://tools.ipol.im/mailman/listinfo/discuss
-- 
Pascal Monasse
IMAGINE, Ecole des Ponts ParisTech
Tel: 01 64 15 21 76


More information about the discuss mailing list