summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.target/cris/torture/sync-mis-op-s-1.c
blob: f2835aa06c11c1eb086a598a5bb29f2b68cd6cf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* { dg-do run { target *-*-linux* } } */
/* { dg-additional-sources "../sync-1.c" } */
/* { dg-options "-Dop -Dtype=short -mno-unaligned-atomic-may-use-library" } */

/* Make sure we get a SIGTRAP or equivalent when passing unaligned
   but otherwise valid pointers to the atomic builtins.  */

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

#ifndef type
#error type not defined
#endif

#ifndef op
#define op 0
#endif

#ifndef xchg
#define xchg 0
#endif

#if op
int sfa (type *p, type *q, int a);
#endif

#if xchg
void acen (type *ptr, type *val, type *ret);
#endif

#ifndef misalignment
#define misalignment 1
#endif

volatile int trap_expected = 0;

struct { char x[misalignment]; type i; } s __attribute__ ((__aligned__ (4)))
  = { {0}, (type) 0xdeadbeef };
type x = 2;
type ret = 42;

#ifdef TRAP_USING_ABORT
#define SYMSTR(x) STR1(__USER_LABEL_PREFIX__, x)
#define STR1(x,y) STR2(x, y)
#define STR2(x,y) #x #y
/* LTO requires marking seemingly-unused-but-used global functions.  */
void my_abort (void) __asm__ (SYMSTR (abort)) __attribute__ ((__used__));
void my_abort (void)
#else
#ifdef __gnu_linux__
void trap_handler(int signum)
#else
#error "can't catch break 8"
#endif
#endif
{
  if (1
#ifndef TRAP_USING_ABORT
      && signum == SIGTRAP
#endif
      && trap_expected
      && s.i == (type) 0xdeadbeef
      && x == 2 && ret == 42)
    exit (0);

#ifdef TRAP_USING_ABORT
  /* We might be able to trust the exit-value getting through, but add
     a NULL-dereference SEGV just in case.  Make sure gcc doesn't
     understand the NULL.  */
  *({ int *p; asm ("" : "=rm" (p) : "0" (0)); p; }) = 0xdead;
  exit (2);
#else
  abort ();
#endif
}

int main(void)
{
  type ret;

#ifndef TRAP_USING_ABORT
#ifdef __gnu_linux__
  if (signal (SIGTRAP, trap_handler) == SIG_ERR)
    abort ();
#endif
#endif

#ifndef mis_ok
  trap_expected = 1;
#endif

#if op
  sfa (&s.i, &s.i, 42);

  /* We should have fallen into the trap now.  But don't call abort
     yet: if the trap is implemented as a call to abort, we have to
     tell the difference.  Set a global variable *and* make sure the
     setting isn't eliminated by optimizers: another call to sfa
     should do it.  */
  trap_expected = 0;

#ifdef mis_ok
  /* We're missing a sequence point, but we shouldn't have the initial
     value.  */
  if (s.i == (type) 0xdeadbeef)
    abort ();
  exit (0);
#endif

  sfa (&x, &x, 1);
#else
  acen (&s.i, &x, &ret);

#ifdef mis_ok
  if (s.i != 2 || x != 2 || ret != (type) 0xdeadbeef)
    abort ();
  exit (0);
#endif

  trap_expected = 0;

  acen (&x, &x, &ret);
#endif

  abort ();
}