This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR optimization/9414 (Sparc)


Hi,

This is a miscompilation bug of BIND 9.2.1 on Ultrasparc, a regression from 
3.0.4 present on the 3.2 branch but latent on the other branches.

Unfortunately I couldn't further shrink the testcase (this is a scheduling 
issue, very sensitive to tiny modifications) so the problem is only visible 
on visual inspection.

The problem occurs for the following statements:

        res->priming = isc_boolean_false;
        fetch = res->primefetch;
        res->primefetch = 0;

(isc_boolean_false is an enum equal to 0).

They are translated into the following RTL code (.flow2):

(insn 152 174 153 (set (reg:SI 9 %o1 [150])
        (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 108 [0x6c])) [4 <variable>.primefetch+0 S4 A32])) 
51 {*movsi_insn} (nil)
    (expr_list:REG_EQUIV (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 108 [0x6c])) [4 <variable>.primefetch+0 S4 A32])
        (nil)))

(insn 153 152 149 (set (mem/f:SI (plus:SI (reg/f:SI 30 %fp)
                (const_int -20 [0xffffffffffffffec])) [4 S4 A32])
        (reg:SI 9 %o1 [150])) 51 {*movsi_insn} (insn_list 152 (nil))
    (expr_list:REG_DEAD (reg:SI 9 %o1 [150])
        (nil)))

(insn 149 153 156 (set (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 104 [0x68])) [31 <variable>.priming+0 S4 A64])
        (const_int 0 [0x0])) 51 {*movsi_insn} (nil)
    (nil))

(insn 156 149 175 (set (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 108 [0x6c])) [4 <variable>.primefetch+0 S4 A32])
        (const_int 0 [0x0])) 51 {*movsi_insn} (nil)
    (nil))


Then the peephole2 pass merges the last two insns in

(insn 445 153 175 (set (mem/s:DI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 104 [0x68])) [31 S8 A64])
        (const_int 0 [0x0])) -1 (nil)
    (nil))

Note that the alias set (31) is that of the first former insn, so the 
aliasing informations of the second former insn are simply thrown away. 
Therefore insn 445 doesn't alias insn 152 whereas 149+156 did.

And of course the 2nd scheduling pass swaps insn 152 and insn 445:

(insn 445 174 152 (set (mem/s:DI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 104 [0x68])) [31 S8 A64])
        (const_int 0 [0x0])) 58 {*movdi_insn_sp32_v9} (nil)
    (nil))

(insn:TI 152 445 153 (set (reg:SI 9 %o1 [150])
        (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 108 [0x6c])) [4 <variable>.primefetch+0 S4 A32])) 
51 {*movsi_insn} (nil)
    (expr_list:REG_EQUIV (mem/s:SI (plus:SI (reg/v/f:SI 16 %l0 [110])
                (const_int 108 [0x6c])) [4 <variable>.primefetch+0 S4 A32])
        (nil)))

i.e we have actually compiled:

        res->priming = isc_boolean_false;
        res->primefetch = 0;
        fetch = res->primefetch;


The culprits are the 10 Sparc memory access widening peepholes, which turns 
SImode into DImode and SFmode into DFmode when possible, for example:

(define_peephole2
  [(set (match_operand:SI 0 "memory_operand" "")
      (const_int 0))
   (set (match_operand:SI 1 "memory_operand" "")
      (const_int 0))]
  "TARGET_V9
   && mems_ok_for_ldd_peep (operands[0], operands[1], NULL_RTX)"
  [(set (match_dup 0)
       (const_int 0))]
  "operands[0] = change_address (operands[0], DImode, NULL);")


The problem is that change_address from emit-rtl.c simply preserves the alias 
set of its first argument, so we can't use it in the peepholes. The right 
function to use appears to be widen_memory_access, which is more careful 
about the aliasing informations. But it is actually a big hammer:

  /* The widened memory may alias other stuff, so zap the alias set.  */
  /* ??? Maybe use get_alias_set on any remaining expression.  */

  MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
				   MEM_ALIGN (new), mode);


Bootstrapped/regtested on sparc-sun-solaris2.8 (c,c++,objc,f77 3.2 branch) 
and sparc-sun-solaris2.9 (c,c++,objc,f77 3.3 branch).

-- 
Eric Botcazou


2003-03-23  Eric Botcazou  <ebotcazou at libertysurf dot fr>

        PR optimization/9414
        * config/sparc/sparc.md (widening peepholes): Use
	widen_memory_access instead of change_address.
Index: config/sparc/sparc.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.md,v
retrieving revision 1.148.2.15.4.1
diff -u -r1.148.2.15.4.1 sparc.md
--- config/sparc/sparc.md	2 Oct 2002 03:47:05 -0000	1.148.2.15.4.1
+++ config/sparc/sparc.md	20 Mar 2003 12:32:47 -0000
@@ -8669,7 +8711,7 @@
    && mems_ok_for_ldd_peep (operands[0], operands[1], NULL_RTX)"
   [(set (match_dup 0)
        (const_int 0))]
-  "operands[0] = change_address (operands[0], DImode, NULL);")
+  "operands[0] = widen_memory_access (operands[0], DImode, 0);")
 
 (define_peephole2
   [(set (match_operand:SI 0 "memory_operand" "")
@@ -8680,7 +8722,7 @@
    && mems_ok_for_ldd_peep (operands[1], operands[0], NULL_RTX)"
   [(set (match_dup 1)
        (const_int 0))]
-  "operands[1] = change_address (operands[1], DImode, NULL);")
+  "operands[1] = widen_memory_access (operands[1], DImode, 0);")
 
 (define_peephole2
   [(set (match_operand:SI 0 "register_operand" "")
@@ -8691,7 +8733,7 @@
    && mems_ok_for_ldd_peep (operands[1], operands[3], operands[0])" 
   [(set (match_dup 0)
 	(match_dup 1))]
-  "operands[1] = change_address (operands[1], DImode, NULL);
+  "operands[1] = widen_memory_access (operands[1], DImode, 0);
    operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));")
 
 (define_peephole2
@@ -8703,7 +8745,7 @@
    && mems_ok_for_ldd_peep (operands[0], operands[2], NULL_RTX)"
   [(set (match_dup 0)
 	(match_dup 1))]
-  "operands[0] = change_address (operands[0], DImode, NULL);
+  "operands[0] = widen_memory_access (operands[0], DImode, 0);
    operands[1] = gen_rtx_REG (DImode, REGNO (operands[1]));")
 
 (define_peephole2
@@ -8715,7 +8757,7 @@
    && mems_ok_for_ldd_peep (operands[1], operands[3], operands[0])"
   [(set (match_dup 0)
 	(match_dup 1))]
-  "operands[1] = change_address (operands[1], DFmode, NULL);
+  "operands[1] = widen_memory_access (operands[1], DFmode, 0);
    operands[0] = gen_rtx_REG (DFmode, REGNO (operands[0]));")
 
 (define_peephole2
@@ -8727,7 +8769,7 @@
   && mems_ok_for_ldd_peep (operands[0], operands[2], NULL_RTX)"
   [(set (match_dup 0)
 	(match_dup 1))]
-  "operands[0] = change_address (operands[0], DFmode, NULL);
+  "operands[0] = widen_memory_access (operands[0], DFmode, 0);
    operands[1] = gen_rtx_REG (DFmode, REGNO (operands[1]));")
 
 (define_peephole2
@@ -8739,7 +8781,7 @@
   && mems_ok_for_ldd_peep (operands[3], operands[1], operands[0])"
   [(set (match_dup 2)
 	(match_dup 3))]
-   "operands[3] = change_address (operands[3], DImode, NULL);
+   "operands[3] = widen_memory_access (operands[3], DImode, 0);
     operands[2] = gen_rtx_REG (DImode, REGNO (operands[2]));")
 
 (define_peephole2
@@ -8751,7 +8793,7 @@
   && mems_ok_for_ldd_peep (operands[2], operands[0], NULL_RTX)" 
   [(set (match_dup 2)
 	(match_dup 3))]
-  "operands[2] = change_address (operands[2], DImode, NULL);
+  "operands[2] = widen_memory_access (operands[2], DImode, 0);
    operands[3] = gen_rtx_REG (DImode, REGNO (operands[3]));
    ")
  
@@ -8764,7 +8806,7 @@
   && mems_ok_for_ldd_peep (operands[3], operands[1], operands[0])"
   [(set (match_dup 2)
 	(match_dup 3))]
-  "operands[3] = change_address (operands[3], DFmode, NULL);
+  "operands[3] = widen_memory_access (operands[3], DFmode, 0);
    operands[2] = gen_rtx_REG (DFmode, REGNO (operands[2]));")
 
 (define_peephole2
@@ -8776,7 +8818,7 @@
   && mems_ok_for_ldd_peep (operands[2], operands[0], NULL_RTX)"
   [(set (match_dup 2)
 	(match_dup 3))]
-  "operands[2] = change_address (operands[2], DFmode, NULL);
+  "operands[2] = widen_memory_access (operands[2], DFmode, 0);
    operands[3] = gen_rtx_REG (DFmode, REGNO (operands[3]));")
  
 ;; Optimize the case of following a reg-reg move with a test
typedef unsigned short isc_uint16_t;
typedef unsigned int isc_uint32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned long long u_longlong_t;
typedef uint64_t upad64_t;
typedef u_longlong_t u_offset_t;

typedef struct _pthread_mutex {
        struct {
                uint16_t __pthread_mutex_flag1;
                uint8_t __pthread_mutex_flag2;
                uint8_t __pthread_mutex_ceiling;
                uint16_t __pthread_mutex_type;
                uint16_t __pthread_mutex_magic;
        } __pthread_mutex_flags;
        union {
                struct {
                        uint8_t __pthread_mutex_pad[8];
                } __pthread_mutex_lock64;
                struct {
                        uint32_t __pthread_ownerpid;
                        uint32_t __pthread_lockword;
                } __pthread_mutex_lock32;
                upad64_t __pthread_mutex_owner64;
        } __pthread_mutex_lock;
        upad64_t __pthread_mutex_data;
} pthread_mutex_t;

typedef unsigned int size_t;
typedef enum { isc_boolean_false = 0, isc_boolean_true = 1 } isc_boolean_t;
typedef enum {
        isc_assertiontype_require,
        isc_assertiontype_ensure,
        isc_assertiontype_insist,
        isc_assertiontype_invariant
} isc_assertiontype_t;

typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t,
                                        const char *);

extern isc_assertioncallback_t isc_assertion_failed;

typedef struct isc_buffer isc_buffer_t;
typedef struct isc_event isc_event_t;
typedef struct { isc_event_t *head, *tail; } isc_eventlist_t;
typedef unsigned int isc_eventtype_t;
typedef struct isc_mem isc_mem_t;
typedef unsigned int isc_result_t;
typedef struct isc_socketmgr isc_socketmgr_t;
typedef struct isc_task isc_task_t;
typedef struct isc_taskmgr isc_taskmgr_t;
typedef struct isc_timermgr isc_timermgr_t;
typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
typedef void (*isc_eventdestructor_t)(isc_event_t *);

struct isc_event {
        size_t ev_size;
        unsigned int ev_attributes;
        void * ev_tag;
        isc_eventtype_t ev_type;
        isc_taskaction_t ev_action;
        void * ev_arg;
        void * ev_sender;
        isc_eventdestructor_t ev_destroy;
        void * ev_destroy_arg;
        struct { struct isc_event *prev, *next; } ev_link;
};

extern void isc_event_free(isc_event_t **);
extern void isc_error_runtimecheck(const char *, int, const char *);

typedef struct {
        unsigned int magic;
} isc__magic_t;

extern int pthread_mutex_lock(pthread_mutex_t *);
extern int pthread_mutex_unlock(pthread_mutex_t *);

typedef pthread_mutex_t isc_mutex_t;

typedef struct dns_db dns_db_t;
typedef void dns_dbnode_t;
typedef struct dns_dispatch dns_dispatch_t;
typedef struct dns_dispatchmgr dns_dispatchmgr_t;
typedef struct dns_fetch dns_fetch_t;
typedef struct dns_fixedname dns_fixedname_t;
typedef struct dns_name dns_name_t;
typedef unsigned char dns_offsets_t[128];
typedef struct dns_rdata dns_rdata_t;
typedef isc_uint16_t dns_rdataclass_t;
typedef struct dns_rdataset dns_rdataset_t;
typedef isc_uint16_t dns_rdatatype_t;
typedef struct dns_resolver dns_resolver_t;
typedef isc_uint16_t dns_trust_t;
typedef isc_uint32_t dns_ttl_t;
typedef struct dns_view dns_view_t;

struct dns_name {
        unsigned int magic;
        unsigned char * ndata;
        unsigned int length;
        unsigned int labels;
        unsigned int attributes;
        unsigned char * offsets;
        isc_buffer_t * buffer;
        struct { dns_name_t *prev, *next; } link;
        struct { dns_rdataset_t *head, *tail; } list;
};

typedef void (*isc_mem_water_t)(void *, int);
typedef void * (*isc_memalloc_t)(void *, size_t);
typedef void (*isc_memfree_t)(void *, void *);

extern void isc__mem_put(isc_mem_t *, void *, size_t );
extern void dns_db_detach(dns_db_t **dbp);
extern void dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep);

struct isc_buffer {
        unsigned int magic;
        void *base;
        unsigned int length;
        unsigned int used;
        unsigned int current;
        unsigned int active;
        struct { isc_buffer_t *prev, *next; } link;
        isc_mem_t *mctx;
};

typedef struct dns_rdatasetmethods {
        void (*disassociate)(dns_rdataset_t *rdataset);
        isc_result_t (*first)(dns_rdataset_t *rdataset);
        isc_result_t (*next)(dns_rdataset_t *rdataset);
        void (*current)(dns_rdataset_t *rdataset,
                                           dns_rdata_t *rdata);
        void (*clone)(dns_rdataset_t *source,
                                         dns_rdataset_t *target);
        unsigned int (*count)(dns_rdataset_t *rdataset);
} dns_rdatasetmethods_t;

struct dns_rdataset {
        unsigned int magic;
        dns_rdatasetmethods_t * methods;
        struct { dns_rdataset_t *prev, *next; } link;
        dns_rdataclass_t rdclass;
        dns_rdatatype_t type;
        dns_ttl_t ttl;
        dns_trust_t trust;
        dns_rdatatype_t covers;
        unsigned int attributes;
        void * private1;
        void * private2;
        void * private3;
        void * private4;
        void * private5;
};

extern void dns_rdataset_disassociate(dns_rdataset_t *rdataset);
extern isc_boolean_t dns_rdataset_isassociated(dns_rdataset_t *rdataset);

struct dns_fixedname {
        dns_name_t name;
        dns_offsets_t offsets;
        isc_buffer_t buffer;
        unsigned char data[255];
};

typedef struct dns_fetchevent {
        size_t ev_size;
        unsigned int ev_attributes;
        void * ev_tag;
        isc_eventtype_t ev_type;
        isc_taskaction_t ev_action;
        void * ev_arg;
        void * ev_sender;
        isc_eventdestructor_t ev_destroy;
        void * ev_destroy_arg;
        struct { struct dns_fetchevent *prev, *next; } ev_link;
        dns_fetch_t * fetch;
        isc_result_t result;
        dns_rdatatype_t qtype;
        dns_db_t * db;
        dns_dbnode_t * node;
        dns_rdataset_t * rdataset;
        dns_rdataset_t * sigrdataset;
        dns_fixedname_t foundname;
} dns_fetchevent_t;

extern void dns_resolver_destroyfetch(dns_fetch_t **fetchp);

typedef struct fetchctx fetchctx_t;

typedef struct fctxbucket {
        isc_task_t * task;
        isc_mutex_t lock;
        struct { fetchctx_t *head, *tail; } fctxs;
        isc_boolean_t exiting;
} fctxbucket_t;

struct dns_resolver {
        unsigned int magic;
        isc_mem_t * mctx;
        isc_mutex_t lock;
        dns_rdataclass_t rdclass;
        isc_socketmgr_t * socketmgr;
        isc_timermgr_t * timermgr;
        isc_taskmgr_t * taskmgr;
        dns_view_t * view;
        isc_boolean_t frozen;
        unsigned int options;
        dns_dispatchmgr_t * dispatchmgr;
        dns_dispatch_t * dispatchv4;
        dns_dispatch_t * dispatchv6;
        unsigned int nbuckets;
        fctxbucket_t * buckets;
        isc_uint32_t lame_ttl;
        unsigned int references;
        isc_boolean_t exiting;
        isc_eventlist_t whenshutdown;
        unsigned int activebuckets;
        isc_boolean_t priming;
        dns_fetch_t * primefetch;
};

void prime_done(isc_task_t *task, isc_event_t *event)
{
        dns_resolver_t *res;
        dns_fetchevent_t *fevent;
        dns_fetch_t *fetch;

        ((void) ((event->ev_type == (((4) << 16) + 1)) || ((isc_assertion_failed)("resolver.c", 4681, isc_assertiontype_require, "event->ev_type == (((4) << 16) + 1)"), 0)));
        fevent = (dns_fetchevent_t *)event;
        res = event->ev_arg;
        ((void) (((((res) != 0) && (((const isc__magic_t *)(res))->magic == ((('R') << 24 | ('e') << 16 | ('s') << 8 | ('!')))))) || ((isc_assertion_failed)("resolver.c", 4684, isc_assertiontype_require, "(((res) != 0) && (((const isc__magic_t *)(res))->magic == ((('R') << 24 | ('e') << 16 | ('s') << 8 | ('!')))))"), 0)));

        (void)(task);

        do { ; ((void) ((((pthread_mutex_lock(((&res->lock))) == 0) ? 0 : 34) == 0) || ((isc_error_runtimecheck)("resolver.c", 4688, "((pthread_mutex_lock(((&res->lock))) == 0) ? 0 : 34) == 0"), 0))); ; } while (0);

        ((void) ((res->priming) || ((isc_assertion_failed)("resolver.c", 4690, isc_assertiontype_insist, "res->priming"), 0)));
        res->priming = isc_boolean_false;
        fetch = res->primefetch;
        res->primefetch = 0;

        do { ((void) ((((pthread_mutex_unlock(((&res->lock))) == 0) ? 0 : 34) == 0) || ((isc_error_runtimecheck)("resolver.c", 4695, "((pthread_mutex_unlock(((&res->lock))) == 0) ? 0 : 34) == 0"), 0))); ; } while (0);

        if (fevent->node != 0)
                dns_db_detachnode(fevent->db, &fevent->node);

        if (fevent->db != 0)
                dns_db_detach(&fevent->db);
        if (dns_rdataset_isassociated(fevent->rdataset))
                dns_rdataset_disassociate(fevent->rdataset);
        ((void) ((fevent->sigrdataset == 0) || ((isc_assertion_failed)("resolver.c", 4703, isc_assertiontype_insist, "fevent->sigrdataset == 0"), 0)));

        do { isc__mem_put((res->mctx), (fevent->rdataset), (sizeof *fevent->rdataset) ); (fevent->rdataset) = 0; } while (0);

        isc_event_free(&event);

        dns_resolver_destroyfetch(&fetch);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]