Segmented Stacks: Pre-midterm work

Hi!

Attached my pre-midterm GSoC work for segmented stacks for review (with
the required fixes).

Thanks!

0001-New-command-line-option-to-enable-segmented-stacks.patch (1.66 KB)

0002-New-StackSegmenter-pass.patch (6.78 KB)

0003-Prologue-code-emission-for-X86.patch (9.61 KB)

0004-New-SelectionDAG-node-and-two-pseudo-instructions.patch (4.21 KB)

0005-Support-for-variable-sized-allocas.patch (10.4 KB)

0006-Test-code.patch (2.15 KB)

0007-Documentation.patch (6.21 KB)

Hi!

Attached my pre-midterm GSoC work for segmented stacks for review (with
the required fixes).

Nice work!

+ extern bool EnableSegmentedStacks;

Can you add a comment like the other declarations?

I think the patch looks good. There are possible improvements, but the patch is already in an state where it can be tested and extended by others, so IMHO it is probably good to commit. Duncan, Chris, what do you think?

Some possible work items are vaargs, adding optimizations to drop some of the checks, letting the FE select which functions should have it (and adding the no_split_stack attribute to clang), generating .note.GNU-split-stack, etc).

Thanks!
--
Sanjoy Das
http://playingwithpointers.com

Cheers,
Rafael

Hi!

I've been working on coroutines for some time, and it seems you were
right - it makes much more sense to have regular C (and assembly) code
for handling coroutines. For instance, I'd otherwise would have to
make an assumption about the threading model the platform has (or
assume there are no threads at all, which prevents me from allowing
goroutine like ("run parallel till you need to write to a channel")
behavior).

Right now I'm sort-of dogfooding my work by trying to get Go running
on dragonegg. I've discovered some small issues already (for instance
I need to save R10 somewhere when compiling a function with a nest
parameter). I'll send a revised set of patches within sometime this
week, addressing all such issues I can find.

That apart, about getting Go to work with dragonegg:

1. Does it sound viable?
2. What things do I need to keep in mind?

Currently, I'm passing `-fplugin=./dragonegg.so' to gccgo and have
edited dragonegg to enable segmented stacks when it detects the
language is "GNU Go". This seems to do what I expect (saving the fact
the binaries throw a mysterious SIGILL :slight_smile: ).

Thanks!

Hi Sanjoy,

I've been working on coroutines for some time, and it seems you were
right - it makes much more sense to have regular C (and assembly) code
for handling coroutines. For instance, I'd otherwise would have to
make an assumption about the threading model the platform has (or
assume there are no threads at all, which prevents me from allowing
goroutine like ("run parallel till you need to write to a channel")
behavior).

Right now I'm sort-of dogfooding my work by trying to get Go running
on dragonegg. I've discovered some small issues already (for instance
I need to save R10 somewhere when compiling a function with a nest
parameter). I'll send a revised set of patches within sometime this
week, addressing all such issues I can find.

That apart, about getting Go to work with dragonegg:

1. Does it sound viable?
2. What things do I need to keep in mind?

Currently, I'm passing `-fplugin=./dragonegg.so' to gccgo and have
edited dragonegg to enable segmented stacks when it detects the
language is "GNU Go". This seems to do what I expect (saving the fact
the binaries throw a mysterious SIGILL :slight_smile: ).

thanks for working on this! As far as I know, split stacks are the only thing
special to GCC Go, otherwise the generic GCC infrastructure was enough. If that
is true then you shouldn't need to do more than what you described above, except
for poking at things until they work of course! The usual source of trouble is
when front-ends trying to write things directly to the assembler file, bypassing
the generic machinery (and thereby bypassing dragonegg). In order to support
LTO front-ends shouldn't do this anymore, but some (eg: java) still do. I had
a look at the GO front-end and I see this suspicious code:

/* This is called by the Go frontend proper to add data to the
    .go_export section. */

void
go_write_export_data (const char *bytes, unsigned int size)
{
   static section* sec;

   if (sec == NULL)
     {
       gcc_assert (targetm_common.have_named_sections);
       sec = get_section (".go_export", SECTION_DEBUG, NULL);
     }

   switch_to_section (sec);
   assemble_string (bytes, size);
}

So you might want to check if copying .go_export sections from the GCC compiled
assembler file into the dragonegg compile assembler files suddenly causes Go
programs to start working.

Ciao, Duncan.

Not true. At least on x86_64, Go uses a different calling convention.

Joerg

Hi!

I've been working on coroutines for some time, and it seems you were
right - it makes much more sense to have regular C (and assembly) code
for handling coroutines. For instance, I'd otherwise would have to
make an assumption about the threading model the platform has (or
assume there are no threads at all, which prevents me from allowing
goroutine like ("run parallel till you need to write to a channel")
behavior).

Right now I'm sort-of dogfooding my work by trying to get Go running
on dragonegg.

Nice idea. That should find the corner cases!

I've discovered some small issues already (for instance
I need to save R10 somewhere when compiling a function with a nest
parameter). I'll send a revised set of patches within sometime this
week, addressing all such issues I can find.

Thanks!

That apart, about getting Go to work with dragonegg:

1. Does it sound viable?
2. What things do I need to keep in mind?

I haven't been keeping track of gcc, but I would think so. Go was added
after most of the LTO work in gcc, so other than debug info it should
have a reasonable separation from the "middle end".

Currently, I'm passing `-fplugin=./dragonegg.so' to gccgo and have
edited dragonegg to enable segmented stacks when it detects the
language is "GNU Go". This seems to do what I expect (saving the fact
the binaries throw a mysterious SIGILL :slight_smile: ).

Thanks!

Thanks!

Rafael

thanks for working on this! As far as I know, split stacks are the only thing
special to GCC Go, otherwise the generic GCC infrastructure was enough.

Not true. At least on x86_64, Go uses a different calling convention.

Both gcc-go and 6g? Do you know if it is documented somewhere?

Joerg

Thanks,
Rafael

thanks for working on this! As far as I know, split stacks are the only thing
special to GCC Go, otherwise the generic GCC infrastructure was enough. If that
is true then you shouldn't need to do more than what you described above, except
for poking at things until they work of course! The usual source of trouble is
when front-ends trying to write things directly to the assembler file, bypassing
the generic machinery (and thereby bypassing dragonegg). In order to support
LTO front-ends shouldn't do this anymore, but some (eg: java) still do. I had
a look at the GO front-end and I see this suspicious code:

/* This is called by the Go frontend proper to add data to the
    .go_export section. */

void
go_write_export_data (const char *bytes, unsigned int size)
{
   static section* sec;

   if (sec == NULL)
     {
       gcc_assert (targetm_common.have_named_sections);
       sec = get_section (".go_export", SECTION_DEBUG, NULL);
     }

   switch_to_section (sec);
   assemble_string (bytes, size);
}

:frowning:

Fixing things like this was fairly painful in the past. It is sad to see new cases showing up.

So you might want to check if copying .go_export sections from the GCC compiled
assembler file into the dragonegg compile assembler files suddenly causes Go
programs to start working.

Ciao, Duncan.

Cheers,
Rafael

You might be confusing the two main compiler implementations. The gc
compilers pass everything on the stack on all architectures, but gccgo
matches gcc's calling convention as far as I'm aware.

- Evan

As far as I can see (after hand-tweaking the assembly generated for a
simple example), there is no problem with the calling
convention. Also, go_write_export_data only seems to generate to some
sort of debug information (which does not look like DWARF).

However, there seems to be some problem with how LLVM handles
trampolines -- I'm currently trying find out what exactly the problem
is.

It's not exactly debug info. It's export info. Go doesn't have header
files, but the compiler needs some way of discovering what functions,
types, variables, and constants a package defines when it is imported.
It does this by parsing the package's export information.

- Evan