Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make GCC evaluate functions at compile time?

I am thinking about the following problem: I want to program a microcontroller (let's say an AVR mega type) with a program that uses some sort of look-up tables.

The first attempt would be to locate the table in a separate file and create it using any other scripting language/program/.... In this case there is quite some effort in creating the necessary source files for C.

My thought was now to use the preprocessor and compiler to handle things. I tried to implement this with a table of sine values (just as an example):

#include <avr/io.h>
#include <math.h>

#define S1(i,n) ((uint8_t) sin(M_PI*(i)/n*255))
#define S4(i,n) S1(i,n), S1(i+1,n), S1(i+2,n), S1(i+3,n)

uint8_t lut[] = {S4(0,4)};

void main()
{
    uint8_t val, i;

    for(i=0; i<4; i++)
    {
        val = lut[i];
    }
}

If I compile this code I get warnings about the sin function. Further in the assembly there is nothing in the section .data. If I just remove the sin in the third line I get the data in the assembly. Clearly all information are available at compile time.

Can you tell me if there is a way to achieve what I intent: The compiler calculates as many values as offline possible? Or is the best way to go using an external script/program/... to calculate the table entries and add these to a separate file that will just be #included?

like image 629
Christian Wolf Avatar asked Jan 22 '15 16:01

Christian Wolf


People also ask

What is compile time evaluation?

In computing, compile-time function execution (or compile time function evaluation, or general constant expressions) is the ability of a compiler, that would normally compile a function to machine code and execute it at run time, to execute the function at compile time.

Can we define a macro at compile time?

You can define any macro on the compiler command line with -D. Use that to specify the model or variant you want, and based on that, #ifdefs in the code enable the other relevant macros.

In which the response to a function is determined at the compile time?

In static polymorphism, the response to a function is determined at the compile time. In dynamic polymorphism, it is decided at run-time.

What is gcc optimization flags?

Turning on optimization flags makes the compiler attempt to improve the performance and/or code size at the expense of compilation time and possibly the ability to debug the program. The compiler performs optimization based on the knowledge it has of the program.


2 Answers

The general problem here is that sin call makes this initialization de facto illegal, according to rules of C language, as it's not constant expression per se and you're initializing array of static storage duration, which requires that. This also explains why your array is not in .data section.

C11 (N1570) §6.6/2,3 Constant expressions (emphasis mine)

A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.

Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.115)

However as by @ShafikYaghmour's comment GCC will replace sin function call with its built-in counterpart (unless -fno-builtin option is present), that is likely to be treated as constant expression. According to 6.57 Other Built-in Functions Provided by GCC:

GCC includes built-in versions of many of the functions in the standard C library. The versions prefixed with __builtin_ are always treated as having the same meaning as the C library function even if you specify the -fno-builtin option.

like image 162
Grzegorz Szpetkowski Avatar answered Oct 11 '22 01:10

Grzegorz Szpetkowski


What you are trying is not part of the C language. In situations like this, I have written code following this pattern:

#if GENERATE_SOURCECODE
int main (void)
{
    ... Code that uses printf to write C code to stdout
}
#else
    // Source code generated by the code above
    ... Here I paste in what the code above generated

    // The rest of the program
#endif

Every time you need to change it, you run the code with GENERATE_SOURCECODE defined, and paste in the output. Works well if your code is self contained and the generated output only ever changes if the code generating it changes.

like image 36
gnasher729 Avatar answered Oct 11 '22 01:10

gnasher729