Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why calls when jmps would suffice?

Tags:

c

x86

gcc

assembly

I have two files:

#include <stdio.h>

static inline void print0() { printf("Zero"); }
static inline void print1() { printf("One"); }
static inline void print2() { printf("Two"); }
static inline void print3() { printf("Three"); }
static inline void print4() { printf("Four"); }

int main()
{
    unsigned int input;
    scanf("%u", &input);

    switch (input)
    {
        case 0: print0(); break;
        case 1: print1(); break;
        case 2: print2(); break;
        case 3: print3(); break;
        case 4: print4(); break;
    }
    return 0;
}

and

#include <stdio.h>

static inline void print0() { printf("Zero"); }
static inline void print1() { printf("One"); }
static inline void print2() { printf("Two"); }
static inline void print3() { printf("Three"); }
static inline void print4() { printf("Four"); }

int main()
{
    unsigned int input;
    scanf("%u", &input);

    static void (*jt[])() = { print0, print1, print2, print3, print4 };
    jt[input]();
    return 0;
}

I expected them to be compiled to almost identical assembly code. In both cases jump tables are generated, but the calls in the first file are represented by jmp, while the calls in the second one by call. Why doesn't compiler optimise calls? Is is possible to hint gcc that I would like to see jmps instead of calls?

Compiled with gcc -Wall -Winline -O3 -S -masm=intel, GCC version 4.6.2. GCC 4.8.0 produces slightly less code, but the problem still persists.

UPD: Defining jt as const void (* const jt[])() = { print0, print1, print2, print3, print4 }; and making the functions static const inline didn't help: http://ideone.com/97SU0

like image 659
Joulukuusi Avatar asked May 15 '12 13:05

Joulukuusi


2 Answers

Compiler writers have a lot of work to do. Obviously they prioritize the work that has the biggest and fastest payoff.

Switch statements are common in all kinds of code, so any optimizations performed on them will have an effect on lots of programs.

This code

jt[input](); 

is a lot less common, and therefore a lot longer down on the compiler designers' TODO-list. Perhaps they haven't (yet) found it worth the effort to try to optimize it? Will that win them any known benchmarks? Or improve some widely used codebase?

like image 191
Bo Persson Avatar answered Oct 06 '22 10:10

Bo Persson


Because the array of function pointers is mutable. The compiler has decided it can't assume the pointers won't be changed. You might find the assembly different for C++, and/or make jt const.

like image 5
Matt Joiner Avatar answered Oct 06 '22 10:10

Matt Joiner