gcc optimizations: how to deal with macro expantion in strncmp & other functions - gcc

Take this sample code:
#include <string.h>
#define STRcommaLEN(str) (str), (sizeof(str)-1)
int main() {
const char * b = "string2";
const char * c = "string3";
strncmp(b, STRcommaLEN(c));
}
If you don't use optimizations in GCC, all is fine, but if you add -O1 and above, as in gcc -E -std=gnu99 -Wall -Wextra -c -I/usr/local/include -O1 sample.c, strncmp becomes a macro, and in preprocessing stage STRcommaLen is not expanded. In fact in resulting "code" strncmp's arguments are completely stripped.
I know if I add #define NEWstrncmp(a, b) strncmp (a, b) and use it instead, the problem goes away. However, mapping your own functions to every standard function that may become a macro doesn't seem like a great solution.
I tried finding the specific optimization that is responsible for it and failed. In fact if I replace -O1 with all the flags that it enables according to man gcc, the problem goes away. My conclusion is that -O1 adds some optimizations that are not controlled by flags and this is one of them.
How would you deal with this issue in a generic way? There may be some macro magic I am not familiar with or compiler flags I haven't looked at? We have many macros and a substantial code base - this code is just written to demonstrate one example.
Btw, GCC version/platform is gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5).
Thanks,
Alen

You correctly noted that
in preprocessing stage STRcommaLen is not expanded
- more precisely, not before the strncmp macro gets expanded. This inevitably leads to an error you probably overlooked or forgot to mention:
sample.c:7:30: error: macro "strncmp" requires 3 arguments, but only 2 given
Your conclusion
that -O1 adds some optimizations that are not controlled by flags and
this is one of them
is also right - this is controlled by the macro __OPTIMIZE__ which apparently gets set by -O1.
If I'd do something like that (which I probably wouldn't, in respect of the pitfall you demonstrated by using sizeof a char *), I'd still choose
mapping your own functions to every standard function that may become
a macro
- but rather like
#include <string.h>
#define STRNCMP(s1, s2) strncmp(s1, s2, sizeof(s2)-1)
int main()
{
const char b[] = "string2";
const char c[] = "string3";
STRNCMP(b, c);
}

Related

GCC: __atomic_always_lock_free compiles with -O3, but not with -O0

Sample code:
int *s;
int foo(void)
{
return 4;
}
int bar(void)
{
return __atomic_always_lock_free(foo(), s);
}
Invocations:
$ gcc t0.c -O3 -c
<nothing>
$ gcc t0.c -O0 -c
t0.c:10:10: error: non-constant argument 1 to '__atomic_always_lock_free'
Any ideas?
Relevant: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html.
This doesn't seem surprising. The documentation you linked says that "size must resolve to a compile-time constant" and so it's to be expected that you might get an error when passing foo(). However, it's typical that if GCC is able to determine the value of an expression at compile time, then it will treat it as a compile-time constant, even if it doesn't meet the language's basic definition of a constant expression. This may be considered an extension and is explicitly allowed by the C17 standard at 6.6p10.
The optimization level is relevant to what the compiler tries in attempting to evaluate an expression at compile time. With optimizations off, it does little more than the basic constant folding that the standard requires (e.g. 2*4). With optimizations on, you get the benefit of its full constant propagation pass, as well as function inlining.
So in essence, under -O0, the compiler doesn't notice that foo() always returns the same value, because you've disabled the optimizations that would allow it to reach that conclusion. With -O3 it does and so it accepts it as a constant.

How to find hanging LLVM optimization pass?

I've written an LLVM pass that replaces a few store instructions with calls to a function that perform some book-keeping, and then performs the store in a special way. It works fine when I compile with -O0, but I can only guarantee the functionality of my pass when using -O3. When I compile with -O3(or -O1/-O2), it completes my pass successfully, and then hangs in some later optimization stage. Is there a way to discover which optimization pass is hanging / why?
Just so I don't have to provide it later, here is my code and my compile line.
clang++-5.0 -std=c++11 -Xclang -load -Xclang ../../plugin/build/mylib.so single_param.cc -c -I ../../libs/ -S -emit-llvm -O3
The problem is not in code generation because I'm only generating bitcode. I noticed that stores in -O3 (without my pass) include alias information, and I thought that since I'm deleting these instructions, some later optimization using this alias information might encounter some trouble, so I turned off most of the alias analysis using -fno-strict-aliasing
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
void __attribute__((noinline)) f(int *n){
*n = *n + 1;
}
int main(){
int a = 4;
f(&a);
return a;
}
The way I was able to find the pass that was stalling was by turning remarks on with
-Rpass=.* -Rpass-missed=.* -Rpass-analysis=.*
I found that the only optimization pass giving remarks was tail call optimization, so I turned it off. I later found the problem with my code, but this is how I found the problem I was causing.

Linking gnu libraries c++ and fortran

I have spent the day searching for an answer to what should be a simple problem. I am building a c++ program to call a fairly large amount of existing fortran. I started by changing the fortran main to a subroutine and then called it with a simple c++ main. My steps look like:
gfortran -c f1.f90 f2.f90 ......
g++ -c mn.cpp
gfortran -lstdc++ -o prog.exe mn.o f1.o ....
mn.cpp started out looking like the code below, and the above steps do work ok. I get a host of linker errors if I try to link with:
g++ -lgfortran (this never works!)
Next, I tried to instantiate a simple array class (remove the 2 commented lines). This produced linker errors concerning gxx_personality_seh0, vtable, and operator new.I get similar errors if I just create an array of doubles with new (remove comment), and if I remove the call to the fortran program completely (still linking with gfortran). Obviously, -lstdc++ does not bring in all the libraries needed. Which libraries are needed and how can I get it to link them?
I am using Windows 7 with Cygwin. The libraries it links are in ...lib/x86_64-pc-cygwin/4.9.3. I can post the linker output if it would be helpful.
mn.cpp which works (code commented out) is below:
#include <string.h>
#include <stdlib.h>
//#include "array.h"
extern "C" {
void mnf90_(const char*,int);
}
int main(int argc, char* argv[]){
// Array2D A; // first derivative
static const char *feos = "d/fld9x.dat";
int npoint = 20;
// double *xc = new double[npoint];
mnf90_(feos,strlen(feos));
}

gcc warning flag for bogus comparison

I am searching for the right warning flag to use with gcc to detect something like:
#include <stdlib.h>
#include <stdio.h>
int main()
{
const size_t n = (size_t)-1;
for( unsigned int i = 0; i < n; ++i ) /* use `unsigned char` if you want */
{
printf( "%d\n", i );
}
return 0;
}
I tried:
$ gcc -Wsign-conversion -Wconversion -pedantic -Wsign-compare -W -Wall -Wextra -std=c99 t.c
What happened is that I have been modifying an existing code, that uses unsigned int for memory block size. The code starting failing with larger file. So I need to check I did not miss any remaining left over.
EDIT:
Just discovered -Wtype-limits but again this is not working for me
You are asking the compiler to detect that the condition is always true at run-time. This is barely within its possibilities in this case, because the reason it is always true is that one side is constant and the other is limited by the unsigned int type. I am glad that you found a g++ flag that did it, but if the value of variable n was provided in a different file, or not typed as const, for instance, the compiler may be unable to detect that the condition remains true.
You may also consider using a static analyzer that spends more time than a compiler on the detection of what may and may not happen at run-time. One open-source C analyzer is Frama-C:
In the screenshot, the statements in red have been detected as unreachable.
The open-source version only works well if the programs makes limited use of library functions, but even so, it can extract information that does not appear in g++'s warnings.
Ok, found out the trick, you need to use the c++ compiler instead:
$ g++ -Wextra t.c
t.c: In function ‘int main()’:
t.c:6: warning: comparison is always true due to limited range of data type
with:
$ g++ --version
g++ (Debian 4.4.5-8) 4.4.5
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

strdup error on g++ with c++0x

I have some C++0x code. I was able to reproduce it below. The code below works fine without -std=c++0x however i need it for my real code.
How do i include strdup in C++0x? with gcc 4.5.2
note i am using mingw. i tried including cstdlib, cstring, string.h and tried using std::. No luck.
>g++ -std=c++0x a.cpp
a.cpp: In function 'int main()':
a.cpp:4:11: error: 'strdup' was not declared in this scope
code:
#include <string.h>
int main()
{
strdup("");
return 0;
}
-std=gnu++0x (instead of -std=c++0x) does the trick for me; -D_GNU_SOURCE didn't work (I tried with a cross-compiler, but perhaps it works with other kinds of g++).
It appears that the default (no -std=... passed) is "GNU C++" and not "strict standard C++", so the flag for "don't change anything except for upgrading to C++11" is -std=gnu++0x, not -std=c++0x; the latter means "upgrade to C++11 and be stricter than by default".
strdup may not be included in the library you are linking against (you mentioned mingw). I'm not sure if it's in c++0x or not; I know it's not in earlier versions of C/C++ standards.
It's a very simple function, and you could just include it in your program (though it's not legal to call it simply "strdup" since all names beginning with "str" and a lowercase letter are reserved for implementation extensions.)
char *my_strdup(const char *str) {
size_t len = strlen(str);
char *x = (char *)malloc(len+1); /* 1 for the null terminator */
if(!x) return NULL; /* malloc could not allocate memory */
memcpy(x,str,len+1); /* copy the string into the new buffer */
return x;
}
This page explains that strdup is conforming, among others, to the POSIX and BSD standards, and that GNU extensions implement it. Maybe if you compile your code with "-D_GNU_SOURCE" it works?
EDIT: just to expand a bit, you probably do not need anything else than including cstring on a POSIX system. But you are using GCC on Windows, which is not POSIX, so you need the extra definition to enable strdup.
add this preprocessor "_CRT_NONSTDC_NO_DEPRECATE" to Project Properties->C/C++ Build->GCC C++ Compiler->Preprocessor->Tool Settings
Don't forget to check Preprocessor Only(-E)
This worked for me on windows mingw32.

Resources