Visda's Profile

  • Name: Visda Vokhshoori
  • Email: (Private)
  • Member Since: Nov 7, 2008
  • Last Logged In: Oct 14, 2009 11:19 AM
  • Status Level:  
  • Location: Toronto
  • Occupation: Compiler Back-end Developer
  • Biography: Currently, a developer of the optimizing back end of the IBM XL compiler brand, Visda has been in IT for more than 10 years. She has spent her career since graduation from the EE Department of State University of New York, New Paltz, at 4 different groups, in 2 different countries with IBM. With each change, she has set the bar higher for herself, working on more complex set of computing problems. She obtained her MSEE from Columbia University, New York, in 2002.

Visda's Latest Content

So many times we get clients complaining to us that their code used to work on an older release but it's broken using the new release of the compiler. After closer look at the sample test case provided, we find out they have been lucky to have a working copy of the code. You see, the breakage is expected because they have broken the ansi-aliasing rules.

Not many of us follow the rules defined in C and C++ standards^1^ religiously. Although, the aliasing rules encourage accessing an object by lvalues of types compatible, we often have to break this rule in order to make the code "work".

By default, the xlc on z/Os compiles with ANSIALIAS. Based on the assumption that pointers in the source file access objects of the same type, the compiler determines storage locations that is accessed in two or more ways, i.e. aliased. If, for example, we have a struct s with two members s1 and s2, the storage for s overlaps with storage for both s.s1 and s.s2. But the storage of the s.s1 and s.s2 don't overlap. This knowledge is critical to aggressive compiler optimization. It allows some loads to move up and stores to move down. The rearrangements in the sequence of execution is desirable and increases executing more of the code in parallel.

Casting a pointer to point to a different object is a common C practice. For each type mismatch, xlc generates a warning and/or an informational message, which you may not notice if you have set the level of diagnostic messages to error or higher, -qflag=E, S, or U, or if you are redirecting all compiler messages to a hardly-ever-looked-at log file. Often the first time you notice a problem is when you execute the code and get an incorrect result.

You have broken the rules, now what?

You can compile routines that are not ansi alias compilant with low levels of optimization, e.g. at OPT0. The higher the level, the more aggressive the optimizations based on aliasing information. You can turn off optimization per routine, by #pragma option_override(func,"OPt(LEVEL,0)").

You can use -qnoansialias compile option or use cc utility which passes noansialias to the compiler by default. This may not be desirable because it usually results in significant performance degradation, e.g. gcc compiled at -O3 with -qnoansialias runs 20% slower.

You can fix the non-compliance in your source code.

1ISO/IEC 14882:1998(E), Section 3.10, Paragraph 15 states:

If a program attempts to access the stored value of an object through an lvalue of other than one of the following types thebehaviour is undefined:

  • the dynamic type of the object
  • a cv-qualified version of the dynamic type of the object
  • a type that is signed or unsigned type corresponding to the dynamic type of the object
  • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object
  • an aggregate or union type that includes one of the aforementioned type among its members (including, recursively, a member of a subaggregate or contained union)
  • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object
  • a char or unsigned char type

Example:

/*alias.c*/
int foo(char *c)
{
char a[100];
char *cptr = a;
*(int *)cptr = *(int*)c;
return 0;
}
xlc -c alias.c -O3 -qlist=./ -qflag=i -qinfo

INFORMATIONAL CCN3495 ./alias.c:5 Pointer type conversion found.
INFORMATIONAL CCN3374 ./alias.c:5 Pointer types "int*" and "char*" are not compatible.
INFORMATIONAL CCN3495 ./alias.c:5 Pointer type conversion found.
INFORMATIONAL CCN3374 ./alias.c:5 Pointer types "int*" and "char*" are not compatible.
INFORMATIONAL CCN3415 ./alias.c:7 The external function definition "foo" is never referenced.

0 Comments Permalink

Search.jpg I think this option's name, (especially the negative one), is pretty confusing. Be that as it may, NOSEARCH wipes out all the previous search specifications and SEARCH sets them.

In METAL C a subset of standard C libraries have been defined, in this context this option becomes pretty handy.

In short, if strcpy is used in the user code, to avoid unexpected compile time messages complaining about strcpy syntax, incorrect run time behavior or what not, its declaration and definition should be pulled in from the METAL string.h header file.


cat foo.c


#include <string.h>
int main() {
char s[10];
memset(s,0,sizeof(s));
strcpy(s,"hello");
return 55;
}



xlc -S -c -qmetal foo.c -qlist=./
grep 'string.h' foo.lst



1 /usr/include/string.h wrong!!!

xlc -S -c -qmetal -qnosearch -I/usr/include/metal foo.c -qlist=./
grep 'string.h' hello.lst



1 /usr/include/metal/string.h correct!!!


The End!

1 Comments Permalink

Compilers are expected to make volatiles immune to optimizations that result in incorrect access to the volatile variables e.g. reducing the load/stores, re-ordering them, and etc.

A recent study on volatiles identified a few bugs with GCC 4.3.0 and LLVM-GCC 2.2. We put our compiler to test and found none of the three bugs identified in this paper applies. Not bad!

The first test case loads a volatile variable in the loop. Although invariant, we expect the compiler to leave x in the loop. The generated pseudo assembly code at O2 and O3 confirm this.

Here is the source code:
const volatile int x;
volatile int y;
void foo(void)
{
for(y=0; y>10; y++)
{
int z=x;
}
}

The assembly listing of the source code above at O3, below, shows the load of x in each iteration of the unrolled loop:

@1L3 DS 0H
L r0,x(r15,r1,0)
L r0,y(r14,r1,0)
AHI r0,H'1'
ST r0,y(r14,r1,0)
L r0,y(r14,r1,0)
CHI r0,H'10'
BNH @1L5
L r0,x(r15,r1,0)
L r0,y(r14,r1,0)
AHI r0,H'1'
ST r0,y(r14,r1,0)
L r0,y(r14,r1,0)
CHI r0,H'10'
BNH @1L5
L r0,x(r15,r1,0)
L r0,y(r14,r1,0)
AHI r0,H'1'
ST r0,y(r14,r1,0)
L r0,y(r14,r1,0)
CHI r0,H'10'
BNH @1L5
L r0,x(r15,r1,0)
L r0,y(r14,r1,0)
AHI r0,H'1'
ST r0,y(r14,r1,0)
L r0,y(r14,r1,0)
CHI r0,H'10'
BH @1L3

The second test accesses a volatile variable on the fall through path of a condition.

Source is:
extern in qux();
volatile int w;
int bar(void)
{
if(qux())
return 0;
else
return w;
}

In the pseudo listing, below, w is correctly accessed when qux() returns zero. This listing generated at O3 is:

L r15,=V(qux)(,r3,66)
L r2,_CEECAA_(,r12,500)
BASR r14,r15
LTR r15,r15
L r1,=Q(w)(,r3,70)
BE @1L1
LA r15,0
B @1L3
@1L1 DS 0H
L r15,w(r1,r2,0)
@1L3 DS 0H

In the last source code a volatile variable is incremented inside the loop.

volatile int a;
void baz(void)
{
int i;
for(i=0; i<3; i++)
{
a += 7;
}
}

We unroll and the loop by three and access "a" three times. The listing of compile at O3 looks like below.

L r0,a(r14,r1,0)
AHI r0,H'7'
ST r0,a(r14,r1,0)
L r0,a(r14,r1,0)
AHI r0,H'7'
ST r0,a(r14,r1,0)
L r0,a(r14,r1,0)
AHI r0,H'7'
ST r0,a(r14,r1,0)

0 Comments Permalink

Write your own drafts, invite selected collaborators, or leave it open for all to pitch in.