(Configuration: x86_64, GCC 4.2.3 base line) I've run into a problem where GCSE decides to kill a conditional jump instruction because it thinks that the result is always false. This happens when GCSE decides to propagate a constant that is "narrowed" [the original mode of the constant is word_mode (DImode) and the use of the constant is in a narrower mode (SImode)].
This situation arises inside the code generated by our GCC/UPC compiler, and so far I haven't been able to come up with a regular C test case that demonstrates the failure. For efficiency reasons, internal to the compiler, we overlay a 16 byte struct on top of a TImode value. The 16 byte struct is the representation of UPC's "pointer-to-shared", which is a potentially cross-node pointer consisting of three parts (vaddr, thread, phase). It looks like this: typedef struct { void *vaddr; unsigned int thread; unsigned int phase; } __attribute__ ((__aligned__(16))) upc_shared_ptr_t; Although not allowed by GCC, you can think of it has having an additional "__attribute__ ((__mode__(__TI__)))" specification. Here is an excerpt from the offending RTL that when passed to GCSE will lead to incorrect deletion of a conditional jump: [...] (insn 19 16 21 2 (set (reg:DI 81) (const_int 4294967296 [0x100000000])) 81 {*movdi_1_rex64} (nil) (nil)) (insn 21 19 24 2 (set (subreg:DI (reg:TI 70 [ D.2967 ]) 8) (reg:DI 81)) 81 {*movdi_1_rex64} (nil) (nil)) (insn 24 21 25 2 (set (reg:SI 60 [ p$phase ]) (const_int 1 [0x1])) 40 {*movsi_1} (nil) (nil)) (insn 25 24 26 2 (set (reg:SI 61 [ p$thread ]) (subreg:SI (reg:TI 70 [ D.2967 ]) 8)) 40 {*movsi_1} (nil) (expr_list:REG_EQUAL (const_int 4294967296 [0x100000000]) (nil))) [...] ;; Start of basic block 5, registers live: (nil) (code_label 53 52 54 5 2 "" [2 uses]) (note 54 53 56 5 [bb 5] NOTE_INSN_BASIC_BLOCK) (insn 56 54 57 5 (set (reg:CCZ 17 flags) (compare:CCZ (reg:SI 61 [ p$thread ]) (const_int 0 [0x0]))) 3 {*cmpsi_ccno_1} (nil) (nil)) (jump_insn 57 56 59 5 (set (pc) (if_then_else (eq (reg:CCZ 17 flags) (const_int 0 [0x0])) (label_ref 63) (pc))) 531 {*jcc_1} (nil) (expr_list:REG_BR_PROB (const_int 7000 [0x1b58]) (nil))) [...] The conditional jump instruction formed by instructions 56 and 57 above is deleted because GCSE thinks that (reg:SI 61 [ p$thread ]) is non-zero. It comes to this conclusion when it propagates the REG_EQUAL (const_int 4294967296 [0x100000000]) value listed in instruction 25: (insn 25 24 26 2 (set (reg:SI 61 [ p$thread ]) (subreg:SI (reg:TI 70 [ D.2967 ]) 8)) 40 {*movsi_1} (nil) (expr_list:REG_EQUAL (const_int 4294967296 [0x100000000]) (nil))) Note that it takes 33 bits to express 0x100000000, and it won't fit into an SImode container. What CSE/GCSE should have done here is written that REG_EQUAL note as follows: (insn 25 24 26 2 (set (reg:SI 61 [ p$thread ]) (subreg:SI (reg:TI 70 [ D.2967 ]) 8)) 40 {*movsi_1} (nil) (expr_list:REG_EQUAL (const_int 0) (nil))) because only the lower 32 bits of the value are relevant. In that case, the conditional jump can be rewritten into an unconditional jump, but certainly not deleted. The code that decides it is OK to use the wider constant, without adjustment to the narrow mode is here: /* If we are looking for a CONST_INT, the mode doesn't really matter, as long as we are narrowing. So if we looked in vain for a mode narrower than word_mode before, look for word_mode now. */ if (p == 0 && code == CONST_INT && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode)) { x = copy_rtx (x); PUT_MODE (x, word_mode); p = lookup (x, SAFE_HASH (x, VOIDmode), word_mode); } The logic above is OK as far as it goes, but the subsequent return of the unadjusted wider constant causes problems: for (p = p->first_same_value; p; p = p->next_same_value) if (GET_CODE (p->exp) == code /* Make sure this is a valid entry in the table. */ && exp_equiv_p (p->exp, p->exp, 1, false)) return p->exp; I'd think that somewhere in there gen_lowpart() needs to be called. I'd appreciate your review of the above analysis and any suggestions that you might have on implementing a fix.