Unwind behaviour in Clang/LLVM

Folks,

We’re having some discussions about the behaviour of exception handling and Dwarf sharing unwind logic, tables, etc. and it seems that the code around it wasn’t designed with any particular goal in mind, but evolved (like the EHABI) and now we’re seeing the results from it.

The problems below are assuming C vs. C++, but it actually apply to any possibly-exceptional vs. never-exceptional cases.

  1. C vs. C++

We have two unwind flags: nounwind, which flags functions that can’t unwind (leaf, nothrow, etc) and uwtable, which forces generation of the table regardless of nounwind. It seems sensible that C++ code with exceptions enabled should generate the tables for all functions, in case they’re called by (or call) external functions. In C we don’t want any of that.

GCC seems to never emit tables, and G++ always do, even on C code (.c files, no exception or anything), which is very sensible and in line with my reasoning above. Clang, on the other hand, always generates them. I guess it’ll have to figure out what to do based on its impressions on what language is being used to produce similar results.

I believe that emitting the tables on anything that could potentially interact with exceptional code makes sense, but that’s clearly a front-end decision. To LLVM, nounwind and uwtables should be absolute:

IF (uwtables)
IF (nownwind)
CantUnwind
ELSE
Unwind Table
ELSE
do nothing
ENDIF

  1. .fnstart/.fnend+friends

Another problem is that the emission of unwinding tables (based on .fnstart/.fnend symbols and others) is conditional only to the existence (or not) of an exception handling class being loaded (EHABI, Dwarf). Which means that, we can’t disable the EH on a per-function basis.

We’ll have to change the way these symbols are emitted, at least when using ARMException, so that we can emit the tables and honour the uwtable on a per-function basis.

Again, this is a requirement for problem 1, but it’d need to be fixed after 3.

  1. Unwinding code

Currently, even when no exception handling are needed, the exception code is used to generate Dwarf unwinding directives (CFI) for the debugger.

Both DwarfCFIException and ARMException inherit from DwarfException, and they are called to do the debug info about the stack unwinding, which is (at least) misplaced. The consensus is that this code should be factored out.

The part that is relevant to this thread is that, today, if -arm-disable-ehabi is requested, ARMException will not be used and we won’t have a way of generating debug stack directives, which is wrong.

Factoring out this code is a requirement for the unwinding problem (1), since if we disable EH today, we’ll disable Dwarf stack unwinding altogether. But we also need a final solution for problem 4 below before we start.

  1. Clang EH control

There are a number of Clang/LLVM options to control exception handling:

  • -fno-excetpion (enable/disable EH on C++ mode, off in C mode)

  • -fcxx-exception (no idea, is it objC++ specific? does it control tables in any way?)

  • -funwind-tables (forces uwtable attribute?)

  • -arm-disable-ehabi (ARM specific bogus flag)

Those options are not always completely exclusive, and they damage different parts of the compilation process (as seen recently on the list), so we need a clear consensus on what each option mean (or should mean), and translate it to the back-end (via function attributes). This would considerably simplify the back-end and help us tackle this refactoring.

My main target for this problem is to have the one true option on the front-ends, and rely only on function attributes on the back-end (including tools like llc). For that, I’d love to be left with -fexception only and infer all the rest from the language / conditions of the code.

Ex:

IF (C++ mode)
IF (-fno-exception)
no uwtable
no nounwind
ELSE
uwtable
IF (leaf / nothrow)
nounwind
ENDIF

ENDIF
ELSE
no uwtable
no nounwind
ENDIF

My main goal is to get rid of (at least) -arm-disable-ehabi.

Finally,

If you got this far, you’re really interested in making the exception handling more user/dev friendly in LLVM, so I welcome any critics about the “proposal” above, as well as any explanations of the doubts expressed. I may be wrong about many things, feel free to enlighten me! We may have a lot less work to do, and I’ll be happy. :wink:

I believe the dependency graph of the solutions are:

4 → 3 → 2 → 1

So, we first should solve the flags problem, than refactor the unwinding code out of EH, make the debug generation use them as well, and then we can start with the EH specific changes. The problem is that 4 will change things considerably, so we might need some scaffolding during the whole process.

Makes sense?

cheers,
–renato

This is not true. Even for nounwind, you want to get basic tables so
that backtrace(3) works.

Joerg

Hi Joerg,

It's a matter of consensus, I believe. Is it the general consensus that we
will *always* want unwind tables to exist? Code size is a clear reason to
not want unwind tables at all, but there might not be many more. If the
general consensus is that unwind tables are a must, and should only be
turned off in special cases, then we just keep emitting them and create (or
reuse) a flag to stop it. If not, language / flags decision (-fexception,
-g, profiling, etc) should turn them on. However, if every one agrees that,
no matter what, we *will* emit unwind tables, than the whole argument is
moot, and there is absolutely nothing to "fix" besides removing
-arm-disable-ehabi.

cheers,
--renato

My point is that there are two different questions here:

(1) Should enough unwind data be provided for a basic, read-only stack
walk?

(2) Should landing pads etc. be provided for exception handling.

The second implies the first, but not the other way around. Some
platforms require (1), e.g. AMD64. Debugging in any form is certainly a
lot more difficult without. Binary size (not so much code size itself)
increases a bit, but typically in the 1-2 per cent range. For NetBSD we
are moving to always creating .eh_frame on all platforms as default,
because the troubleshooting help justifies the price.

That said, the option already exists for changing the default:
-funwind-tables. There shouldn't be another ARM specific flag. I can't
say what the best default is.

Joerg

Hi Joerg,

You are right, there are three separate issues here: unwinding, debug info
and exception handling.

Debug and EH require unwinding, but one doesn't require the other and
unwinding is not exclusive to either.

(1) Should enough unwind data be provided for a basic, read-only stack
walk?

As you said, platforms and systems should define their own defaults, and
that's mainly driven by the front-end via flags and triples.

The behaviour of flags should be precise, and different flags should be
on/off by default depending on the triple, so build systems can enforce
flags if they need to make sure the behaviour will be the same across
different platforms.

I can't decide that, but those decisions should stay in the front-end. To
the back-end, function attributes should be able to control table emission
(or maybe we need flags, I don't know).

That said, the option already exists for changing the default:
-funwind-tables. There shouldn't be another ARM specific flag.

So, can I assume that -f{no-}unwind-tables's syntax is to completely
enable/disable the unwind tables and add/remove the ELF sections from the
objects? If that's so, I can easily remove -arm-disable-ehabi and check on
that flag.

thanks,
--renato

Debug and EH require unwinding, but one doesn't require the other and
unwinding is not exclusive to either.

Correct.

I can't decide that, but those decisions should stay in the front-end. To
the back-end, function attributes should be able to control table emission
(or maybe we need flags, I don't know).

I disagree on this. Table emission by itself doesn't involve code
generation and I don't think it makes sense as a per function attribute
either. You either want it for all functions or only when needed (e.g.
exceptions are possible). As such, it makes perfect sense to me as a
global flag.

> That said, the option already exists for changing the default:
> -funwind-tables. There shouldn't be another ARM specific flag.
>

So, can I assume that -f{no-}unwind-tables's syntax is to completely
enable/disable the unwind tables and add/remove the ELF sections from the
objects? If that's so, I can easily remove -arm-disable-ehabi and check on
that flag.

-funwind-tables says that the tables should always be emitted. If there
are no other reasons like exception handling, they will only destructive
stack unwind.

-fno-unwind-tables says that tables should only be emitted, if another
(language specific) reason requires them. So for C++, it would normally
be ignored as exception support is the default. For C code, it would
ensure that no .eh_frame* sections are emitted, even on platforms that
require them for the ABI like AMD64.

Joerg

From: Renato Golin [mailto:renato.golin@linaro.org]

We're having some discussions about the behaviour of exception handling and Dwarf
sharing unwind logic, tables, etc. and it seems that the code around it wasn't
designed with any particular goal in mind, but evolved (like the EHABI) and now
we're seeing the results from it.

The problems below are assuming C vs. C++, but it actually apply to any possibly-exceptional
vs. never-exceptional cases.

1. C vs. C++

We have two unwind flags: nounwind, which flags functions that can't unwind (leaf,
nothrow, etc) and uwtable, which forces generation of the table regardless of
nounwind. It seems sensible that C++ code with exceptions enabled should generate
the tables for all functions, in case they're called by (or call) external functions.
In C we don't want any of that.

GCC seems to never emit tables, and G++ always do, even on C code (.c files,
no exception or anything), which is very sensible and in line with my reasoning above.
Clang, on the other hand, always generates them. I guess it'll have to figure out what
to do based on its impressions on what language is being used to produce similar results.

You can make GCC emit unwind tables for C if you use the command line option -funwind-tables.

This could be useful if you are compiling C code which is called by C++ code and which itself calls C++ code and you wish the C++ exception to propagate through the C code.

I believe that emitting the tables on anything that could potentially interact
with exceptional code makes sense, but that's clearly a front-end decision.
To LLVM, nounwind and uwtables should be absolute:

IF (uwtables)
IF (nownwind)
   CantUnwind
ELSE
   Unwind Table
ELSE
  do nothing
ENDIF

This certainly appears to me a sensible sequence of decision.

2. .fnstart/.fnend+friends

Another problem is that the emission of unwinding tables (based on
.fnstart/.fnend symbols and others) is conditional *only* to the existence
(or not) of an exception handling class being loaded (EHABI, Dwarf). Which
means that, we can't disable the EH on a per-function basis.

We'll have to change the way these symbols are emitted, at least when using
ARMException, so that we can emit the tables and honour the uwtable on a per-function basis.

Again, this is a requirement for problem 1, but it'd need to be fixed after 3.

3. Unwinding code

Currently, even when no exception handling are needed, the exception code is
used to generate Dwarf unwinding directives (CFI) for the debugger.

This is because the 2 are so similar.

Both DwarfCFIException and ARMException inherit from DwarfException, and they
are called to do the debug info about the stack unwinding, which is (at least)
misplaced. The consensus is that this code should be factored out.

There is some interaction in that if you are generating a .eh_frame section for exception handling then there is little sense is generating a DWARF .debug_frame section as well; I would hope most debuggers could use the .eh_frame section if present as its format is so similar to a .debug_frame section.

The part that is relevant to this thread is that, today, if -arm-disable-ehabi
is requested, ARMException will not be used and we won't have a way of
generating debug stack directives, which is wrong.

What does -arm-disable-ehabi actually mean?

Currently it is effectively "don't generate exception tables".

Maybe is should it rather be "don't generate EHABI exception tables but generate .eh_frame tables instead"? Obviously this requires the necessary DWARF like support to generate the information for the .eh_frame tables.

Factoring out this code is a requirement for the unwinding problem (1), since
if we disable EH today, we'll disable Dwarf stack unwinding altogether. But we
also need a final solution for problem 4 below before we start.

I think the solution depends on what we mean when we specify -arm-disable-ehabi ... is it

IF(arm_disable_ehabi)
   USE ARMException
ELSE
   USE DwarfCFiNoException <---- Just generates DWARF debugging information
ENDIF

Or is it

IF(arm_disable_ehabi)
   USE ARMException
ELSE
   USE DwarfCFIException
ENDIF

4. Clang EH control

There are a number of Clang/LLVM options to control exception handling:
* -fno-excetpion (enable/disable EH on C++ mode, off in C mode)
* -fcxx-exception (no idea, is it objC++ specific? does it control tables in any way?)
* -funwind-tables (forces uwtable attribute?)
* -arm-disable-ehabi (ARM specific bogus flag)

Those options are not always completely exclusive, and they damage different
parts of the compilation process (as seen recently on the list), so we need
a clear consensus on what each option mean (or should mean), and translate it
to the back-end (via function attributes). This would considerably simplify
the back-end and help us tackle this refactoring.

My main target for this problem is to have the one true option on the front-ends,
and rely only on function attributes on the back-end (including tools like llc).
For that, I'd love to be left with -fexception only and infer all the rest from
the language / conditions of the code.

Ex:

IF (C++ mode)
  IF (-fno-exception)
    no uwtable
    no nounwind
  ELSE
    uwtable
    IF (leaf / nothrow)
      nounwind
    ENDIF
  ENDIF
ELSE
  no uwtable
  no nounwind
ENDIF

My main goal is to get rid of (at least) -arm-disable-ehabi.

Hmmm! I'm very nervous about the backend making decisions based on the language.

As I mentioned above I also wonder if you do still need to support -funwind-tables for compiling C code through which you wish to allow exceptions to propogate.

In which case the logic is more like ....

  IF (-funwind-tables || -fexceptions)
    uwtable
    IF (leaf / nothrow)
      nounwind
    ENDIF
  ELSE
    no uwtable
    no nounwind
  ENDIF

The main difference I see between -fexceptions and -funwind-tables is:

-fexceptions allows compiling exception handling constructs in the source language and enables the generation of unwind tables.
-funwind-tables only enables the generation of unwind tables.

Keith

Keith

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782

You can make GCC emit unwind tables for C if you use the command line
option -funwind-tables.

This could be useful if you are compiling C code which is called by C++
code and which itself calls C++ code and you wish the C++ exception to
propagate through the C code.

Yes, we still need the possibility to force unwind tables in C code, and
that's what -funwind-tables is there for.

Since -fexception only triggers landing pads and cleanup blocks, we don't
need to worry about it, but the -funwind-tables should communicate with the
back-end via some clear and unambiguous means.

Maybe function attributes aren't enough, but we need to make sure that they
don't clash with the flags, if we do use them.

There is some interaction in that if you are generating a .eh_frame section

for exception handling then there is little sense is generating a DWARF
.debug_frame section as well; I would hope most debuggers could use the
.eh_frame section if present as its format is so similar to a .debug_frame
section.

Right, makes sense.

It seems, then, that we basically need two types of unwinding, and they
could live in different places.

Before your patch, the debugger wasn't able to use the EHABI stack
unwinding code. Is that because it was using .push/.save instead of .cfi
directives? Or is that because the table generated is not readable by
normal debuggers?

What does -arm-disable-ehabi actually mean?

Currently it is effectively "don't generate exception tables".

Yes. It has no effect on the front-end. It should actually be replaced by
whatever mechanism -f{no-}unwind-tables is using.

I created a bug (PR18758) and copied you.

Maybe is should it rather be "don't generate EHABI exception tables but

generate .eh_frame tables instead"? Obviously this requires the necessary
DWARF like support to generate the information for the .eh_frame tables.

This is where things start getting a little interesting. If we all agree
that generating unwind tables is good *in any case*, even on embedded
devices like Coretx-M0, than I think we should hard-code .eh_frame
generation under any circumstance, and use -funwind-tables to generate
EHABI tables.

Clang would then enable it by default depending on the language contract,
which is of little importance to the back-end.

But the question I don't have an answer yet is: if we use that flag, what
do we do when -fno-unwind-tables clashes with the uwtables function
attribute?

IF(arm_disable_ehabi)

   USE ARMException
ELSE
   USE DwarfCFIException
ENDIF

Today, it means:

IF(arm_disable_ehabi)
  nothing at all
ELSE
  USE ARMException
ENDIF

I'm sensing that the consensus is driving towards *always* emitting unwind
tables, but I can't just use DwarfCFIException on ARM, it won't work. This
is why we need to carefully extract the common interface, not just for the
debug x EH problem, but also the Dwarf x EHABI problem.

Hmmm! I'm very nervous about the backend making decisions based on the

language.

No, sorry! That was a front-end decision! I'd die before enquiring the
language in the back-end! :smiley:

  IF (-funwind-tables || -fexceptions)

    uwtable
    IF (leaf / nothrow)
      nounwind
    ENDIF
  ELSE
    no uwtable
    no nounwind
  ENDIF

I'd only like to completely remove the unwind tables if the user forcefully
selected -fno-unwind-tables, so I wouldn't like Clang to automatically
select that, even in C code.

-fexceptions allows compiling exception handling constructs in the source

language and enables the generation of unwind tables.
-funwind-tables only enables the generation of unwind tables.

That makes total sense. Right now, I can't see a difference between
-fno-unwind-tables and -arm-disable-ehabi.

As far as I could see, -fcxx-exceptions has no relevance to this
discussion, so I'll drop it right here.

My questions about the flags were answered, and it's going to be a lot
easier than I thought. I'll change the ehabi flag to connect via
unwind-tables and will send a patch review.

Once that's done, we can get some work done on refactoring ARMException,
but only after your patch lands upstream.

Thanks!
--renato

Folks,

We're having some discussions about the behaviour of exception handling
and Dwarf sharing unwind logic, tables, etc. and it seems that the code
around it wasn't designed with any particular goal in mind, but evolved
(like the EHABI) and now we're seeing the results from it.

The problems below are assuming C vs. C++, but it actually apply to any
possibly-exceptional vs. never-exceptional cases.

1. C vs. C++

We have two unwind flags: nounwind, which flags functions that can't
unwind (leaf, nothrow, etc) and uwtable, which forces generation of the
table regardless of nounwind. It seems sensible that C++ code with
exceptions enabled should generate the tables for all functions, in case
they're called by (or call) external functions. In C we don't want any of
that.

GCC seems to never emit tables, and G++ always do, even on C code (.c
files, no exception or anything), which is very sensible and in line with
my reasoning above. Clang, on the other hand, always generates them. I
guess it'll have to figure out what to do based on its impressions on what
language is being used to produce similar results.

I believe that emitting the tables on anything that could potentially
interact with exceptional code makes sense, but that's clearly a front-end
decision. To LLVM, nounwind and uwtables should be absolute:

IF (uwtables)
  IF (nownwind)
    CantUnwind
  ELSE
    Unwind Table
ELSE
  do nothing
ENDIF

This looks wrong, based on the LangRef:

"uwtable
  This attribute indicates that the ABI being targeted requires that an
unwind table entry be produce for this function even if we can show that no
exceptions passes by it."

I think it's probably:

if (nounwind)
  can't unwind

if (uwtable || (!nounwind && need uwtable to unwind))
  unwind table

2. .fnstart/.fnend+friends

Another problem is that the emission of unwinding tables (based on
.fnstart/.fnend symbols and others) is conditional *only* to the existence
(or not) of an exception handling class being loaded (EHABI, Dwarf). Which
means that, we can't disable the EH on a per-function basis.

We'll have to change the way these symbols are emitted, at least when
using ARMException, so that we can emit the tables and honour the uwtable
on a per-function basis.

Again, this is a requirement for problem 1, but it'd need to be fixed
after 3.

3. Unwinding code

Currently, even when no exception handling are needed, the exception code
is used to generate Dwarf unwinding directives (CFI) for the debugger.

Both DwarfCFIException and ARMException inherit from DwarfException, and
they are called to do the debug info about the stack unwinding, which is
(at least) misplaced. The consensus is that this code should be factored
out.

The part that is relevant to this thread is that, today, if
-arm-disable-ehabi is requested, ARMException will not be used and we won't
have a way of generating debug stack directives, which is wrong.

Factoring out this code is a requirement for the unwinding problem (1),
since if we disable EH today, we'll disable Dwarf stack unwinding
altogether. But we also need a final solution for problem 4 below before we
start.

4. Clang EH control

There are a number of Clang/LLVM options to control exception handling:
* -fno-excetpion (enable/disable EH on C++ mode, off in C mode)
* -fcxx-exception (no idea, is it objC++ specific? does it control tables
in any way?)
* -funwind-tables (forces uwtable attribute?)
* -arm-disable-ehabi (ARM specific bogus flag)

Those options are not always completely exclusive, and they damage
different parts of the compilation process (as seen recently on the list),
so we need a clear consensus on what each option mean (or should mean), and
translate it to the back-end (via function attributes). This would
considerably simplify the back-end and help us tackle this refactoring.

I believe the intent is:
  -fexceptions/-fno-exceptions controls whether we generate code that copes
with exceptions passing through it.
  -fcxx-exceptions/-fno-cxx-exceptions controls whether we allow exception
constructs in C++ code (throw, catch, try) and whether we validate
exception specifications (both during compilation and at runtime).
  -fobjc-exceptions/-fno-objc-exceptions controls whether we allow
exception constructs in ObjC code (@throw, @try, @catch).

So:

  -fno-exceptions implies -fno-cxx-exceptions and -fno-objc-exceptions
  -fcxx-exceptions and -fobjc-exceptions require -fexceptions

The (-cc1) frontend defaults to -fno-exceptions -fno-cxx-exceptions
-fno-objc-exceptions (I'm not sure why).
The driver defaults to:
  * in ObjC++: -fcxx-exceptions -fobjc-exceptions -fexceptions
  * in ObjC: -fobjc-exceptions -fexceptions
  * in C++: -fcxx-exceptions -fexceptions
  * in C: <nothing>

(Users might want to specify -fexceptions in C, when building code like
qsort that might have exceptions thrown across it.)

-funwind-tables appears to be an entirely orthogonal flag, which is by
default determined based on the target (with some -f flags to override the
default), entirely ignoring the -fexceptions flags and language mode. This
does not appear to be a flag that an end-user should touch, under most
circumstances, but it's far from clear to me that we're getting the default
right here (maybe it should depend on -fexceptions?).

The 'nounwind' attribute is set if -fexceptions is specified, or if we have
some other way of knowing the function does not throw. Exception: in
-fobjc-exceptions mode, we ask the ObjC runtime whether to set the flag.
This looks like a bug to me.

The 'uwtable' attribute is set based on the value we determined for
-funwind-tables (either through an explicit flag or from the target).

My main target for this problem is to have the one true option on the

front-ends, and rely only on function attributes on the back-end (including
tools like llc). For that, I'd love to be left with -fexception only and
infer all the rest from the language / conditions of the code.

Ex:

IF (C++ mode)
  IF (-fno-exception)
    no uwtable
    no nounwind
  ELSE
    uwtable
    IF (leaf / nothrow)
      nounwind
    ENDIF
  ENDIF
ELSE
  no uwtable
  no nounwind

This seems wrong -- in C with -fexceptions we do not want nounwind, and
sometimes want uwtable (depending on ABI).

Does LTO change this analysis?

I don't think so.

Joerg

if (nounwind)
  can't unwind

can't unwind == unwind table + no EH directives + no EH table

if (uwtable || (!nounwind && need uwtable to unwind))

  unwind table

"need unwind table to unwind" is probably true in almost all cases. At
least in all where ARMException and DwarfCFIException are concerned, which
is the ones we're discussing about.

I'm beginning to think that there is no reason at all to have an uwtable
attribute, given that the -funwind-tables is propagated to the back-end AND
if we emit the table for one function we should do it for all.

I believe the intent is:

  -fexceptions/-fno-exceptions controls whether we generate code that
copes with exceptions passing through it.

Right. Landing pads, cleanups, etc. We'll need those for emitting the EH
tables, but not the unwind tables, so for this particular discussion, we
don't need to worry.

  -fcxx-exceptions/-fno-cxx-exceptions controls whether we allow exception
constructs in C++ code (throw, catch, try) and whether we validate
exception specifications (both during compilation and at runtime).
  -fobjc-exceptions/-fno-objc-exceptions controls whether we allow
exception constructs in ObjC code (@throw, @try, @catch).

Language-specific stuff, not even important to the EH tables (since in the
back end we don't care what constructs you use in the language, only the IR
basic block structure).

  -fno-exceptions implies -fno-cxx-exceptions and -fno-objc-exceptions

  -fcxx-exceptions and -fobjc-exceptions require -fexceptions

Will -fcxx-exceptions also include -fexceptions? I mean, if the user
specify -fcxx-exceptions in C, will that also turn on all the internal
flags that -fexception would?

If so, we really don't need to worry at all about them.

-funwind-tables appears to be an entirely orthogonal flag, which is by

default determined based on the target (with some -f flags to override the
default), entirely ignoring the -fexceptions flags and language mode.

Right. They do clash in the back-end, since one generates EH unwinding and
the other might only generate Dwarf unwinding. We need to clear that
confusion in the back-end, but I don't think that the front-end should even
care on how it gets implemented in the end, as long as it works.

This does not appear to be a flag that an end-user should touch, under most

circumstances, but it's far from clear to me that we're getting the default
right here (maybe it should depend on -fexceptions?).

I think that both -fexceptions and -g should turn -funwind-tables by
default. The third user is the backtrace which doesn't need debug or EH
info (just the unwind table), and you need the -funwind-tables IFF your
target doesn't have it on by default.

I can only think about GPU targets that won't need any of that, but they're
not using Dwarf or EHABI handlers, so we shouldn't concern about that.
Embedded CPUs might want them disabled to save space, and for that we
should actively disable (-fno-unwind-tables or -Os/z).

The 'nounwind' attribute is set if -fexceptions is specified, or if we have

some other way of knowing the function does not throw.

You mean -fno-exceptions, I believe. I think this behaviour is correct.

The 'uwtable' attribute is set based on the value we determined for

-funwind-tables (either through an explicit flag or from the target).

Seems reasonable, though unnecessary in most cases.

This seems wrong -- in C with -fexceptions we do not want nounwind, and

sometimes want uwtable (depending on ABI).

Yes, I agree, I was wrong. Unwind tables are almost entirely orthogonal to
EH and Dwarf.

Thanks everyone for the enlightening responses, I'll have to digest
everything again and see if I remember any of it tomorrow... :slight_smile:

I managed to get a definite step out of this (http://llvm.org/PR18758), and
I think we can safely ignore the -fexceptions flags for now.

My revised plan:

0. Get Keith's patch in to have unwinding without EH
1. Connect -funwind-tables with EHABI
2. Abstract the unwind code where both EH and the Dwarf producers can make
use of
3. Disable unwind tables if -fno-unwind-tables on ARM
4. Apply CFI unwinding if -funwind-tables AND -fno-exceptions on EHABI

I'm not sure why we're using .save/.push and not CFI with EHABI, but step 2
would be a lot simpler if we could unify both exception handling classes,
and step 4 would completely disappear. Anton/Logan?

cheers,
--renato

if (nounwind)
  can't unwind

can't unwind == unwind table + no EH directives + no EH table

if (uwtable || (!nounwind && need uwtable to unwind))

  unwind table

"need unwind table to unwind" is probably true in almost all cases. At
least in all where ARMException and DwarfCFIException are concerned, which
is the ones we're discussing about.

I'm beginning to think that there is no reason at all to have an uwtable
attribute, given that the -funwind-tables is propagated to the back-end AND
if we emit the table for one function we should do it for all.

I believe the intent is:

  -fexceptions/-fno-exceptions controls whether we generate code that
copes with exceptions passing through it.

Right. Landing pads, cleanups, etc. We'll need those for emitting the EH
tables, but not the unwind tables, so for this particular discussion, we
don't need to worry.

  -fcxx-exceptions/-fno-cxx-exceptions controls whether we allow
exception constructs in C++ code (throw, catch, try) and whether we
validate exception specifications (both during compilation and at runtime).
  -fobjc-exceptions/-fno-objc-exceptions controls whether we allow
exception constructs in ObjC code (@throw, @try, @catch).

Language-specific stuff, not even important to the EH tables (since in the
back end we don't care what constructs you use in the language, only the IR
basic block structure).

  -fno-exceptions implies -fno-cxx-exceptions and -fno-objc-exceptions

  -fcxx-exceptions and -fobjc-exceptions require -fexceptions

Will -fcxx-exceptions also include -fexceptions? I mean, if the user
specify -fcxx-exceptions in C, will that also turn on all the internal
flags that -fexception would?

If so, we really don't need to worry at all about them.

-fcxx-exceptions implies -fexceptions if the input kind is C++ and is
ignored if not.
-fobjc-exceptions implies -fexceptions if the input kind is ObjC(++) and is
ignored if not.

Which isn't quite what you asked, but I think the conclusion is the same
(you don't need to care, the driver does the right thing).

-funwind-tables appears to be an entirely orthogonal flag, which is by

default determined based on the target (with some -f flags to override the
default), entirely ignoring the -fexceptions flags and language mode.

Right. They do clash in the back-end, since one generates EH unwinding and
the other might only generate Dwarf unwinding. We need to clear that
confusion in the back-end, but I don't think that the front-end should even
care on how it gets implemented in the end, as long as it works.

This does not appear to be a flag that an end-user should touch, under most

circumstances, but it's far from clear to me that we're getting the default
right here (maybe it should depend on -fexceptions?).

I think that both -fexceptions and -g should turn -funwind-tables by
default. The third user is the backtrace which doesn't need debug or EH
info (just the unwind table), and you need the -funwind-tables IFF your
target doesn't have it on by default.

I can only think about GPU targets that won't need any of that, but
they're not using Dwarf or EHABI handlers, so we shouldn't concern about
that. Embedded CPUs might want them disabled to save space, and for that we
should actively disable (-fno-unwind-tables or -Os/z).

This (-fexceptions and -g imply -funwind-tables) seems like it's probably
the right thing for most targets. With SjLj exceptions, -fexceptions
probably doesn't need -funwind-tables.

The 'nounwind' attribute is set if -fexceptions is specified, or if we

have some other way of knowing the function does not throw.

You mean -fno-exceptions, I believe. I think this behaviour is correct.

The 'uwtable' attribute is set based on the value we determined for

Thanks, I think that's the general consensus, yes.

Do we have such logic in Clang at the moment?

My original point was that the back-end shouldn't try to guess, so
front-ends should pass this information down, either via function
attributes or flags. Attributes would be better for multi-stage compilation
process, but if the default target description is shared between front and
back ends, than we might not need this, and flags become the preferred
method.

This is another reason to proceed with a separate library for target
description (that deals with triples, -m flags, defaults, etc), to be used
by both front and back ends, so then we don't have to worry about changing
all sides whenever a default changes.

cheers,
--renato

Let me answer my own question. Right now, both -funwind-tables and
-fno-unwind-tables only enable the -muniwind-tables for -cc1, and either
lack or presence of that flag in -cc1 has the same behaviour on C++ code:
they both generate .eh_frame sections.

The only behaviour I found is that -munwind-tables will add uwtable to
functions, which had no effect on x86_64. Is that because x86_64 mandates
unwind tables?

If the semantics is that uwtable turns on tables on targets that don't
require it (SjLj), but not that it turns off if missing on targets that
mandate it, I can't use it to disable them on ARM. To be honest, recently,
I'm not even sure I need, or want to disable.

With Keith's patch to generate Dwarf unwind, the -arm-disable-ehabi flag
could possibly be removed clean, and we can go directly to step 2.

Keith, Reid, are you happy with always generating unwind tables on ARM
regardless?

cheers,
--renato

Just to double check, none of this will change the current behavior on Darwin, right?

-Jim

Right! Unless Darwin starts using EHABI. :wink:

--renato

Perfect. Thanks!

-Jim

Depends on the ABI. On X86-64 we should produce the tables even with C
according to the ABI.

Cheers,
Rafael

I disagree on this. Table emission by itself doesn't involve code
generation and I don't think it makes sense as a per function attribute
either. You either want it for all functions or only when needed (e.g.
exceptions are possible). As such, it makes perfect sense to me as a
global flag.

It has to be an attribute because of LTO. You can LTO a file compiled
with -fasynchronous-unwind-tables and one with
-fno-asynchronous-unwind-tables. That is why we have the uwtable
attribute.

Cheers,
Rafael