return cc_loc_result;
}
+/* Try to handle TLS MEMs, for which mem_loc_descriptor on XEXP (mem, 0)
+ failed. */
+
+static dw_loc_descr_ref
+tls_mem_loc_descriptor (rtx mem)
+{
+ tree base;
+ dw_loc_descr_ref loc_result, loc_result2;
+
+ if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX)
+ return NULL;
+
+ base = get_base_address (MEM_EXPR (mem));
+ if (base == NULL
+ || TREE_CODE (base) != VAR_DECL
+ || !DECL_THREAD_LOCAL_P (base))
+ return NULL;
+
+ loc_result = loc_descriptor_from_tree_1 (MEM_EXPR (mem), 2);
+ if (loc_result == NULL)
+ return NULL;
+
+ if (INTVAL (MEM_OFFSET (mem)))
+ {
+ if (INTVAL (MEM_OFFSET (mem)) >= 0)
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_plus_uconst,
+ INTVAL (MEM_OFFSET (mem)), 0));
+ else
+ {
+ loc_result2 = mem_loc_descriptor (MEM_OFFSET (mem), GET_MODE (mem),
+ VAR_INIT_STATUS_INITIALIZED);
+ if (loc_result2 == 0)
+ return NULL;
+ add_loc_descr (&loc_result, loc_result2);
+ add_loc_descr (&loc_result, new_loc_descr (DW_OP_plus, 0, 0));
+ }
+ }
+
+ return loc_result;
+}
+
/* The following routine converts the RTL for a variable or parameter
(resident in memory) into an equivalent Dwarf representation of a
mechanism for getting the address of that same variable onto the top of a
case MEM:
mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
VAR_INIT_STATUS_INITIALIZED);
+ if (mem_loc_result == NULL)
+ mem_loc_result = tls_mem_loc_descriptor (rtl);
if (mem_loc_result != 0)
add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
break;
INTVAL (XEXP (rtl, 1)), 0));
else
{
- add_loc_descr (&mem_loc_result,
- mem_loc_descriptor (XEXP (rtl, 1), mode,
- VAR_INIT_STATUS_INITIALIZED));
+ dw_loc_descr_ref mem_loc_result2
+ = mem_loc_descriptor (XEXP (rtl, 1), mode,
+ VAR_INIT_STATUS_INITIALIZED);
+ if (mem_loc_result2 == 0)
+ break;
+ add_loc_descr (&mem_loc_result, mem_loc_result2);
add_loc_descr (&mem_loc_result,
new_loc_descr (DW_OP_plus, 0, 0));
}
VAR_INIT_STATUS_INITIALIZED);
break;
+ case UNSPEC:
+ /* If delegitimize_address couldn't do anything with the UNSPEC, we
+ can't express it in the debug info. This can happen e.g. with some
+ TLS UNSPECs. */
+ break;
+
default:
gcc_unreachable ();
}
case MEM:
loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
initialized);
+ if (loc_result == NULL)
+ loc_result = tls_mem_loc_descriptor (rtl);
break;
case CONCAT:
/* Create the first one, so we have something to add to. */
loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
initialized);
+ if (loc_result == NULL)
+ return NULL;
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
for (i = 1; i < num_elem; i++)
temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
initialized);
+ if (temp == NULL)
+ return NULL;
add_loc_descr (&loc_result, temp);
mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
/* The way DW_OP_GNU_push_tls_address is specified, we
can only look up addresses of objects in the current
module. */
- if (DECL_EXTERNAL (loc))
+ if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc))
return 0;
first_op = INTERNAL_DW_OP_tls_addr;
second_op = DW_OP_GNU_push_tls_address;
if (offset != NULL_TREE)
{
/* Variable offset. */
- add_loc_descr (&ret, loc_descriptor_from_tree_1 (offset, 0));
+ ret1 = loc_descriptor_from_tree_1 (offset, 0);
+ if (ret1 == 0)
+ return 0;
+ add_loc_descr (&ret, ret1);
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
--- /dev/null
+/* PR middle-end/37275 */
+/* { dg-do compile { target ilp32 } } */
+/* { dg-options "-g -dA -O2 -march=i686 -fstack-protector" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void *memcpy (void *, const void *, size_t);
+extern void *malloc (size_t);
+
+typedef int A;
+
+struct B
+{
+ int x;
+};
+
+struct C
+{
+ struct F *c1;
+ void *c2;
+};
+
+enum D
+{
+ D0,
+ D1
+};
+
+struct E
+{
+ struct E *e1;
+ struct E *e2;
+ struct B e3;
+ void (*fn) (void *);
+ void *fn_data;
+ enum D e4;
+ _Bool e5;
+ _Bool e6;
+};
+
+struct F
+{
+ unsigned f1;
+ A f2;
+ int f3;
+};
+
+struct G
+{
+ void (*fn) (void *data);
+ void *data;
+ struct C g1;
+ struct E *t;
+};
+
+extern void fn1 (A * m);
+static inline void
+fn2 (A *x)
+{
+ if (!__sync_bool_compare_and_swap (x, 0, 1))
+ fn1 (x);
+}
+
+extern __thread struct G thr __attribute__ ((visibility ("hidden")));
+static inline struct G *
+fn3 (void)
+{
+ return &thr;
+}
+
+extern struct B *fn4 (void);
+extern struct B a;
+
+static inline struct B *
+fn5 (_Bool x)
+{
+ struct E *t = fn3 ()->t;
+ if (t)
+ return &t->e3;
+ else if (x)
+ return fn4 ();
+ else
+ return &a;
+}
+
+void
+fn6 (struct E *t, struct E *e1_t,
+ struct B *prev_e3)
+{
+ t->e1 = e1_t;
+ t->e3 = *prev_e3;
+ t->e4 = D0;
+ t->e5 = 0;
+ t->e6 = 0;
+ t->e2 = ((void *) 0);
+}
+
+void
+test (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), long x, long y, _Bool z)
+{
+ struct G *thr = fn3 ();
+ struct F *c1 = thr->g1.c1;
+ if (!z || c1 == 0 || (unsigned) c1->f3 > 64 * c1->f1)
+ {
+ struct E t;
+
+ fn6 (&t, thr->t, fn5 (0));
+ if (thr->t)
+ t.e6 = thr->t->e6;
+ thr->t = &t;
+ if (__builtin_expect (cpyfn != ((void *) 0), 0))
+ {
+ char buf[x + y - 1];
+ char *arg = (char *) (((unsigned long) buf + y - 1)
+ & ~(unsigned long) (y - 1));
+ cpyfn (arg, data);
+ fn (arg);
+ }
+ }
+ else
+ {
+ struct E *t;
+ struct E *e1 = thr->t;
+ char *arg;
+
+ t = malloc (sizeof (*t) + x + y - 1);
+ arg = (char *) (((unsigned long) (t + 1) + y - 1)
+ & ~(unsigned long) (y - 1));
+ fn6 (t, e1, fn5 (0));
+ thr->t = t;
+ if (cpyfn)
+ cpyfn (arg, data);
+ else
+ memcpy (arg, data, x);
+ thr->t = e1;
+ fn2 (&c1->f2);
+ }
+}