https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66563
--- Comment #31 from Oleg Endo <olegendo at gcc dot gnu.org> --- (In reply to Kazumoto Kojima from comment #29) > Unfortunately, 4.9 and later compilers 'optimize' the above code > to the code like Just for my understanding ... In the pattern ... (define_expand "GOTaddr2picreg" [(set (reg:SI R0_REG) (unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))] UNSPEC_MOVA)) (set (match_dup 0) (const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))) (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI R0_REG)))] ... the 2nd (set ...) becomes the mov.l load from the constant pool, which is CSE'ed by some other optimization after the initial RTL expansion. If so, wouldn't it be a bit cleaner to avoid CSE by hiding the constant/symref load from CSE passes by doing something like the following ... (define_expand "GOTaddr2picreg" [(parallel [(set (reg:SI R0_REG) (unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))] UNSPEC_MOVA)) (set (match_dup 0) (const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))) (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI R0_REG)))])] <... everything else stays the same ...> (define_insn_and_split "*GOTaddr2picreg" [(set (reg:SI R0_REG) (unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))] UNSPEC_MOVA)) (set (match_dup 0) (const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))) (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI R0_REG)))] "" "#" "&& reload_completed" [(set (reg:SI R0_REG) (unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))] UNSPEC_MOVA)) (set (match_dup 0) (const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))) (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI R0_REG)))]) Alternatively, can't the mov.l constant load insn be marked as "volatile" so that it doesn't get optimized away for sure?