Inline function in other inline function in C - c

Will this code:
inline int funcA(int a) __attribute__((always_inline))
{
return a + 1;
}
inline int funcB(int b) __attribute__((always_inline))
{
return funcA(b + 2);
}
int main()
{
return funcB(3);
}
transformed to code like this?:
int main()
{
return ((3) + 2) + 1;
}
GCC, ARM (iPhone)

Inlining function calls is not something the language requires compilers to do. It's a quality of implementation issue (QoI). But any of GCC, MSVC and clang will do it. Of course, you have to enable optimization.
For instance
# clang++ -cc1 -emit-llvm -O2 -o - main.cpp
define i32 #main() nounwind readnone {
entry:
ret i32 6
}

There are no guarantees when using inline. It serves merely as a hint to the compiler (which in many (not all) cases have more heuristics and better understanding of the impact of inlining than the programmer).

Not necessarily. It depend's on the compiler and settings I guess. In fact in C++ for example it's not even guaranteed that this
inline int funcA(int a)
{
return a + 1;
}
int main()
{
return funcA(3);
}
will get transformed into this
int main()
{
return 3 + 1;
}
inline is just the hint for the compiler. The compiler can ignore it.

Related

Attribute for ignoring "too many arguments in call to 'func'"

I am creating a light test framework. For my local debugging in linux with gcc and clang, I do not get any complaints for mocking a function that has arguments, but mocking it with no arguments. eg.
add.c
int add(int a, int b) {
return a + b;
}
foo.c
#include "add.h"
int add_2(int a) {
return add(a, 2);
}
Now, in order to mock add. I simply created these macros.
testframework.h
#define DECLARE_MOCK(type, name) \
type __var_##name[255]; \
size_t __var_##name##_inc = 0; \
size_t __var_##name##_actual = 0; \
type name() { return (type)__var_##name[__var_##name##_inc++]; }
#define MOCK(name, value) __var_##name[__var_##name##_actual++] = value;
This works well on my linux machine. add(x,y) requires two arguments, but gcc or clang doesn't complain that the mock will essentially have no arguments passed to it, and works perfectly as a stand in. it's this line here type name() ...
Here is the usage. Notice I am mocking add.c capability in this test file.
#include "foo.h"
#include "testframework.h"
DECLARE_MOCK(int, add);
int main() {
DESCRIBE("things");
MOCK(add, 2);
SHOULDB("add", {
ASSERT(add(0, 2) == 2);
});
}
The issue comes in on gcc mac, which complains.
[INFO] CMD: gcc -Wall -Werror -std=c11 -O3 -o target/things tests/things.c obj/things/lib.o
tests/things.c:29:57: error: too many arguments in call to 'add' [-Werror]
SHOULDB("add", { ASSERT(add(0, 2) == 2); });
I would like to keep -Wall and -Werror, I was hoping there was an attribute I could add to the macro, which is the opposite of sentinel.

Why is no warning given for the wrong use of __attribute__((pure)) in GCC?

I am trying to understand pure functions, and have been reading through the Wikipedia article on that topic. I wrote the minimal sample program as follows:
#include <stdio.h>
static int a = 1;
static __attribute__((pure)) int pure_function(int x, int y)
{
return x + y;
}
static __attribute__((pure)) int impure_function(int x, int y)
{
a++;
return x + y;
}
int main(void)
{
printf("pure_function(0, 0) = %d\n", pure_function(0, 0));
printf("impure_function(0, 0) = %d\n", impure_function(0, 0));
return 0;
}
I compiled this program with gcc -O2 -Wall -Wextra, expecting that an error, or at least a warning, should have been issued for decorating impure_function() with __attribute__((pure)). However, I received no warnings or errors, and the program also ran without issues.
Isn't marking impure_function() with __attribute__((pure)) incorrect? If so, why does it compile without any errors or warnings, even with the -Wextra and -Wall flags?
Thanks in advance!
Doing this is incorrect and you are responsible for using the attribute correctly.
Look at this example:
static __attribute__((pure)) int impure_function(int x, int y)
{
extern int a;
a++;
return x + y;
}
void caller()
{
impure_function(1, 1);
}
Code generated by GCC (with -O1) for the function caller is:
caller():
ret
As you can see, the impure_function call was completely removed because compiler treats it as "pure".
GCC can mark the function as "pure" internally automatically if it sees its definition:
static __attribute__((noinline)) int pure_function(int x, int y)
{
return x + y;
}
void caller()
{
pure_function(1, 1);
}
Generated code:
caller():
ret
So there is no point in using this attribute on functions that are visible to the compiler. It is supposed to be used when definition is not available, for example when function is defined in another DLL. That means that when it is used in a proper place the compiler won't be able to perform a sanity check anyway. Implementing a warning thus is not very useful (although not meaningless).
I don't think there is anything stopping GCC developers from implementing such warning, except time that must be spend.
A pure function is a hint for the optimizing compiler. Probably, gcc don't care about pure functions when you pass just -O0 to it (the default optimizations). So if f is pure (and defined outside of your translation unit, e.g. in some outside library), the GCC compiler might optimize y = f(x) + f(x); into something like
{
int tmp = f(x); /// tmp is a fresh variable, not appearing elsewhere
y = tmp + tmp;
}
but if f is not pure (which is the usual case: think of f calling printf or malloc), such an optimization is forbidden.
Standard math functions like sin or sqrt are pure (except for IEEE rounding mode craziness, see http://floating-point-gui.de/ and Fluctuat for more), and they are complex enough to compute to make such optimizations worthwhile.
You might compile your code with gcc -O2 -Wall -fdump-tree-all to guess what is happening inside the compiler. You could add the -fverbose-asm -S flags to get a generated *.s assembler file.
You could also read the Bismon draft report (notably its section §1.4). It might give some intuitions related to your question.
In your particular case, I am guessing that gcc is inlining your calls; and then purity matters less.
If you have time to spend, you might consider writing your own GCC plugin to make such a warning. You'll spend months in writing it! These old slides might still be useful to you, even if the details are obsolete.
At the theoretical level, be aware of Rice's theorem. A consequence of it is that perfect optimization of pure functions is probably impossible.
Be aware of the GCC Resource Center, located in Bombay.

Why compiler is not able to optimize read from TLS?

Consider follwing header file, "tls.h":
#include <stdint.h>
// calling this function is expensive
uint64_t foo(uint64_t x);
extern __thread uint64_t cache;
static inline uint64_t
get(uint64_t x)
{
// if cache is not valid
if (cache == UINT64_MAX)
cache = foo(x);
return cache + x;
}
and source file "tls.c":
#include "tls.h"
__thread uint64_t cache = {0};
uint64_t foo(uint64_t x)
{
// imagine some calculations are performed here
return 0;
}
Below is example usage of get() function in "main.c":
#include "tls.h"
uint64_t t = 0;
int main()
{
uint64_t x = 0;
for(uint64_t i = 0; i < 1024UL * 1024 * 1024; i++){
t += get(i);
x++;
}
}
Presented files are compiled as following:
gcc -c -O3 tls.c
gcc -c -O3 main.c
gcc -O3 main.o tls.o
Examining the performance of loop in "main.c" revealed that compiler optimization is very poor. After disassembling the binary, it is clear that tls is being accessed in every iteration.
Execution time on my machine is 1.7s.
However, if I remove check for cache validity in get() method so that it looks like this:
static inline uint64_t
get(uint64_t x)
{
return cache + x;
}
the compiler is now able to create much faster code - it completely removes the loop and generates only only one "add" instruction. Execution time is ~0.02s.
Why the compiler is not able to optimize the first case? TLS variable cannot be changed by other threads so compiler should be able to optimize this, right?
Is there any other way I can optimize the get() function?

How to compile inline C function with literal attributes with GCC?

I have an inline function like this:
inline void func_1 (int a)
{
if(a==1)
{
other_func1();
}
else
{
other_func2();
}
}
and I use in the Main like this:
int main()
{
func1(1);
func1(42);
return 0;
}
I use GCC, I think, the compiled code look like this (in “source level”):
int main()
{
other_func1()
other_func2();
return 0;
}
Is it true or am I wrong?
Yes, in general gcc will optimise away dead code in inline functions when it can evaluate branches at compile-time. I use this construct a lot to allow optimised code to be generated for different use cases - somewhat like template instantiation in C++.

Clang splits function arguments

If you compile the following with "clang -S -emit-llvm struct.c"
struct _mystruct {
long long int a;
long long int b;
};
struct _mystruct foo(struct _mystruct s) {
s.a += 1;
return s;
}
int main(void) {
struct _mystruct s;
s.a = 8;
s.b = 9;
s = foo(s);
return s.a;
}
... you get (among other things):
define { i64, i64 } #foo(i64 %s.coerce0, i64 %s.coerce1) #0 {
Why does clang split the argument to foo in two? Is there any way I can prevent it from doing that? I want to be able to call it from other LLVM generated code that expects only one argument to foo.
Since LLVM has no way to represent it, Clang encodes the platform ABI this way. In this particular example, it's struct passing by-value which is extremely ABI specific. You will notice this if you provide different target triple to clang - you'll notice that the emitted code is different. I assume from the question this is run on a x64 machine where structs can be passed in registers.

Resources