Ehren's Blog

i686 vs x86-64 issues

Posted in Seneca by ehren on November 17, 2009

Falling behind with my blog is not a good thing because I have a lot to report. Some/most of it is old news by now but I need to get it up here. Incidentally I’ve completed a rudimentary Dehydra analysis on the mozilla-central repository so that my plugin can eventually be applied, however I will present the results in my next post (here’s the post, btw).

Anyway, last week, upon embarking on the static analysis component of this project, I ran into trouble using my GCC plugin on two of the CDOT’s x86_64 Fedora boxes. The plugin compiled, but using it on any test code invoked an internal compiler error (a segmentation fault). This was quite troubling since the plugin worked fine when compiled for i386 (tested with my personal Debian machine and another Fedora i686 system at Seneca).

Ultimately I solved the problem by finding a slightly different way of coding the optimization, but I’ll document a few of the steps I’ve attempted.

Although I have now updated it with the fix, the plugin code of my previous post contained the following (see that post for the context):

  tree lhs = gimple_get_lhs (stmt);
  tree zero = build_int_cst (TREE_TYPE (lhs), 0);
  gimple assign = gimple_build_assign_stat (lhs, zero);
  tree var = make_rename_temp (TREE_TYPE (lhs), "dummy_var");
  gimple_call_set_lhs (stmt, var);
  gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING);

One clue about the issue is that the call on line 4 to make_rename_temp warns “initialization makes pointer from integer without a cast”. At the time my thoughts on the issue were “who cares, it works”. Even getting the ICE (which complained about the call to make_rename_temp), I figured that changing the code wasn’t the thing to do. Instead a convoluted journey of debugging the plugin with gdb, examining the registers, etc, etc, was what I had in mind. Conclusion: the call to make_rename_temp results in a crash.

In any event, I found a solution although it’s been long enough that I can’t quite remember how I arrived at it:

  tree lhs = gimple_get_lhs (stmt);
  tree zero = build_int_cst (TREE_TYPE (lhs), 0);
  gimple assign = gimple_build_assign_stat (lhs, zero);
  tree var = create_tmp_var (TREE_TYPE (lhs), "dummy_var");
  add_referenced_var (var);
  mark_sym_for_renaming (var);
  gimple_call_set_lhs (stmt, var);
  gsi_insert_after (&gsi, assign, GSI_CONTINUE_LINKING);

All of that add_referenced_var/mark_sym_for_renaming business is because the call to create_tmp_var creates a temporary that’s not in SSA form ie you’ll have an initialization like int dummy_var.0; and then when it’s used you’ll get dummy_var.0 = 0; when what you want is dummy_var.0_1 = 0;.

Looking at the code for mark_sym_for_renaming in tree-dfa.c, note that it’s basically identical to the code I used to replace it’s call:

tree
make_rename_temp (tree type, const char *prefix)
{
  tree t = create_tmp_var (type, prefix);

  if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
      || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
    DECL_GIMPLE_REG_P (t) = 1;

  if (gimple_referenced_vars (cfun))
    {
      add_referenced_var (t);
      mark_sym_for_renaming (t);
    }

  return t;
}

So where is the error with my original approach given that it works on i686? I’m thinking that the representation of a tree as a union of tree nodes may be at issue ie I was sticking the return of make_rename_tmp where it should not be stuck.

Although it wasn’t of much use to me, I’ll present a quick example of debugging GCC with gdb for those interested (this applies to GCC plugins as well). I have found this page, on debugging a segmentation fault, particularly useful. For those who just want to step through the compiler for kicks, those instructions will work as well.

Here’s a concrete example:
I’ve installed my GCC at /home/ehren/gcc/dist/bin/gcc and am compiling hello.c which is in my home directory. The compiler was produced with -g3 -O0.

First run the compiler with -v to determine the actual command passed to cc1 or cc1plus (gcc or g++ is just a driver for these programs)
~$ gcc/dist/bin/gcc hello.c -v

The output will contain the following line:
/home/ehren/gcc/dist/libexec/gcc/i686-pc-linux-gnu/4.5.0/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -o /tmp/cctQO1Kb.s

Now invoke cc1 with gdb:

~$ gdb /home/ehren/gcc/dist/libexec/gcc/i686-pc-linux-gnu/4.5.0/cc1

And then run it using the arguments given in the line above (the -v is now unnecessary but there’s no harm in including it). Set a breakpoint first if you’re not getting an internal compiler error:

(gdb) break main
(gdb) run -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -o /tmp/cctQO1Kb.s

And you’re good to go.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: