Bug 19020 - libcalls are removed (-ftrapv does not work)
: libcalls are removed (-ftrapv does not work)
Status: RESOLVED FIXED
Product: gcc
Classification: Unclassified
Component: middle-end
: 4.0.0
: P2 normal
: 4.4.0
Assigned To: Not yet assigned to anyone
:
: wrong-code
:
: 35412 35413
  Show dependency treegraph
 
Reported: 2004-12-15 20:23 UTC by Eric Botcazou
Modified: 2008-11-29 22:29 UTC (History)
11 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2005-11-13 16:50:18


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Eric Botcazou 2004-12-15 20:23:38 UTC
The following code should abort at runtime when compiled with -ftrapv:

#include <limits.h>

int __attribute__((noinline))
iaddv (int a, int b)
{
  return a + b;
}

int main(void)
{
  iaddv (INT_MAX, 1);
  return 0;
}

It doesn't in 64-bit mode:
[eric@localhost native]$ gcc-4.0 -o addv addv.c -ftrapv
[eric@localhost native]$ ./addv
[eric@localhost native]$ gcc-4.0 -o addv addv.c -ftrapv -m32
[eric@localhost native]$ ./addv
Aborted

The problem originates in .03.jump: the libcall to __addvdi3 is eliminated.
Comment 1 Steven Bosscher 2004-12-15 20:51:23 UTC
This doesn't happen on just amd64, I've seen this bug on all targets 
when I was playing with a patch to blow away libcall notes.  On ia64 
it lead to a link failure because of missing symbols, so fixing this 
problem will probably uncover a few latent bugs elsewhere. 
 
Comment 2 Steven Bosscher 2004-12-15 20:52:16 UTC
When I looked at this, the libcall was eliminated in the call to 
delete_trivially_dead_insns, somewhere around jump1. 
 
Comment 3 Andrew Pinski 2005-12-14 18:32:28 UTC
*** Bug 25418 has been marked as a duplicate of this bug. ***
Comment 4 Andrew Pinski 2006-04-22 15:41:04 UTC
*** Bug 27261 has been marked as a duplicate of this bug. ***
Comment 5 Richard Guenther 2007-01-17 15:35:08 UTC
There are a few issues, first we use emit_libcall_block to emit the trapping
PLUS
which sets a REG_EQUAL note with a non-trapping PLUS.

Second we analyze iaddv as not possibly throwing so we remove the call from
main()
during tree optimization as the result is unused.

Third, we widen the integer addition to DImode and dispatch to libgcc2
__addvdi3
which looks like

Dump of assembler code for function __addvdi3:
0x0000000000400580 <__addvdi3+0>:       sub    $0x8,%rsp
0x0000000000400584 <__addvdi3+4>:       test   %rsi,%rsi
0x0000000000400587 <__addvdi3+7>:       lea    (%rdi,%rsi,1),%rax
0x000000000040058b <__addvdi3+11>:      js     0x4005a0 <__addvdi3+32>
0x000000000040058d <__addvdi3+13>:      cmp    %rax,%rdi

so it tests for 64bit overflow instead of 32bit one.  Obviously allowind
LIBCALL_WIDEN is wrong for the trapping optabs, too.
Comment 6 Richard Guenther 2007-05-30 19:59:34 UTC
*** Bug 32153 has been marked as a duplicate of this bug. ***
Comment 7 Steven Bosscher 2008-03-01 10:50:34 UTC
With trunk as of today, the test case of comment #0 does trap if optimization
is disabled. At -O, the libcall is optimized away, but the call to iaddv() from
main() is also optimized away because iaddv is found to be pure.  You must use
the result of iaddv() to avoid this:

#include <limits.h>

int __attribute__((noinline))
iaddv (int a, int b)
{
  return a + b;
}

int main(void)
{
  return iaddv (INT_MAX, 1);
}
Comment 8 Richard Guenther 2008-03-01 13:52:32 UTC
On the expand side it is just wrong (and asking for trouble) to go the usual
expand_binop way for expanding trapping arithmetic.  At least we would need to
pass down a flag.
Comment 9 Richard Guenther 2008-03-01 14:29:46 UTC
If you remove libcall notes around all binops then the following testcase
passes in dg-torture:

/* { dg-do run { target hppa*-*-hpux* *-*-linux* powerpc*-*-darwin*
*-*-darwin[912]* } } */
/* { dg-options "-ftrapv" } */

#include <stdlib.h>
#include <limits.h>
#include <signal.h>

int ok;

void handle_abort (int sig)
{
  if (sig == SIGABRT)
    {
      ok = 1;
      exit (0);
    }
}

int __attribute__((noinline))
iaddv (int a, int b)
{
  return a + b;
}

volatile int x;

int main(void)
{
  struct sigaction sa;
  sigemptyset (&sa.sa_mask);
  sa.sa_handler = handle_abort;
  sa.sa_flags = SA_RESETHAND;
  if (sigaction (SIGABRT, &sa, NULL) == -1)
    return 0;
  /* ???  iaddv is analyzed to be pure, so use the result.  */
  x = iaddv (INT_MAX, 1);
  sa.sa_handler = SIG_DFL;
  if (sigaction (SIGABRT, &sa, NULL) == -1)
    return 0;
  if (!ok)
    abort ();
  return 0;
}

but I get a build failure of libjava then:

gnu/java/nio/natVMSelector.cc: In static member function 'static jint
gnu::java::nio::VMSelector::select(JArray<__java_int>*, JArray<__java_int>*,
JArray<__java_int>*, jlong)':
gnu/java/nio/natVMSelector.cc:127: error: unable to find a register to spill in
class 'AD_REGS'
gnu/java/nio/natVMSelector.cc:127: error: this is the insn:
(insn 58 57 59 6 gnu/java/nio/natVMSelector.cc:82 (parallel [
            (set (reg:DI 4 si [165])
                (mult:DI (zero_extend:DI (reg:SI 0 ax))
                    (zero_extend:DI (reg:SI 2 cx [166]))))
            (clobber (reg:CC 17 flags))
        ]) 304 {*umulsidi3_insn} (expr_list:REG_DEAD (reg:SI 2 cx [166])
        (expr_list:REG_DEAD (reg:SI 0 ax)
            (expr_list:REG_UNUSED (reg:CC 17 flags)
                (expr_list:REG_EQUAL (mult:DI (zero_extend:DI (reg:SI 0 ax))
                        (const_int 1000 [0x3e8]))
                    (nil))))))
gnu/java/nio/natVMSelector.cc:127: internal compiler error: in spill_failure,
at reload1.c:2000
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.


with the following patch

Index: optabs.c
===================================================================
--- optabs.c    (revision 132790)
+++ optabs.c    (working copy)
@@ -2148,12 +2148,9 @@ expand_binop (enum machine_mode mode, op

       insns = get_insns ();
       end_sequence ();
+      emit_insn (insns);

-      target = gen_reg_rtx (mode);
-      emit_libcall_block (insns, target, value,
-              gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
-
-      return target;
+      return value;
     }

   delete_insns_since (last);


I'll test forcing value to a register.
Comment 10 Richard Guenther 2008-03-01 15:24:01 UTC
Doesn't help.
Comment 11 Steven Bosscher 2008-03-03 19:35:53 UTC
Quoting your insn once more:

(insn 58 57 59 6 gnu/java/nio/natVMSelector.cc:82 (parallel [
            (set (reg:DI 4 si [165])
                (mult:DI (zero_extend:DI (reg:SI 0 ax))
                    (zero_extend:DI (reg:SI 2 cx [166]))))
            (clobber (reg:CC 17 flags))
        ]) 304 {*umulsidi3_insn} (expr_list:REG_DEAD (reg:SI 2 cx [166])
        (expr_list:REG_DEAD (reg:SI 0 ax)
            (expr_list:REG_UNUSED (reg:CC 17 flags)
                (expr_list:REG_EQUAL (mult:DI (zero_extend:DI (reg:SI 0 ax))
                        (const_int 1000 [0x3e8]))
                    (nil))))))

The register allocator failed to make your insn satisfy its constraints.
Operand 0 is (reg:DI 4 si) but the constraint for it is "=A", i.e. the ax
register.

The funny thing is that reload wants to make operand 0 be (reg:DI 0 ax), but
somehow it can't, even though (reg:SI 0 ax) dies in this insn. So apparently
the high part of (reg:DI 0 ax), i.e. (reg:SI 1 dx), lives across the insn.

This looks to me like a case of PR35404.  What do you think, Ian?
Comment 12 Paolo Bonzini 2008-05-31 07:25:26 UTC
*** Bug 36398 has been marked as a duplicate of this bug. ***
Comment 13 Richard Guenther 2008-07-18 18:22:31 UTC
*** Bug 36868 has been marked as a duplicate of this bug. ***
Comment 14 Eric Botcazou 2008-11-29 22:19:57 UTC
libcalls are gone in 4.4 and later.
Comment 15 Steven Bosscher 2008-11-29 22:23:52 UTC
I'm not sure if this bug is fixed, though.  -ftrapv is still broken afaik.
Comment 16 Eric Botcazou 2008-11-29 22:29:04 UTC
> I'm not sure if this bug is fixed, though.  -ftrapv is still broken afaik.

Probably, but let's ditch antiquated stuff and start afresh.