[PATCH] Do not remove labels with LABEL_PRESERVE_P

Steven Bosscher stevenb.gcc@gmail.com
Wed Sep 24 13:51:00 GMT 2014

On Wed, Sep 24, 2014 at 2:51 PM, Ilya Enkovich wrote:
> 2014-09-24 16:47 GMT+04:00 Steven Bosscher :
> It is not a control flow instruction. It copies value of instruction
> pointer into a general purpose register.  Therefore REG_LABEL_OPERAND
> seems to be correct.

OK - sorry for being a bit slow on the up-take, I got confused by the
asm syntax :-)

So I'm going to speculate a bit more... What you want to have is:

    leaq L2(%rip), rXX

What happens is that L2 is "deleted", which is to say converted to a
NOTE_INSN_DELETED_LABEL. Then the notes are re-ordered
(NOTE_INSN_DELETED_LABEL notes are not tied to anything in the insns
stream and can end up anywhere) so you end up with something like,

L2:                     # (was deleted)
    leaq L2(%rip),rXX

I bet you'd find that in the failing test case the label is output to
the assembly file but it's simply in the wrong place.  For the large
code model, we get away with it because the prologue is output late
and the order of the insns is not adjusted (a few passes later, the
CFG doesn't even exist anymore so you don't go through cfgcleanup).
But if you emit the label early and let it go through the entire RTL
pipeline then anything can happen.

If the above makes sense, then you'll want to emit the label late, or
not at all, to the insns stream.

If you emit the label late into the insns stream, you'd rewrite the
set_rip as a define_insn_and_split that emits the label as part of the
last splitting pass. But there is no splitting pass late enough to
guarantee that the label and insns won't get separated.

If you don't emit the label to the insns stream, you would write
ix86_output_set_rip() and call that from the define_insns for set_rip.
You'd not emit the label in the expander. You'd create it and make it
an operand, but not emit it. Your ix86_output_set_rip() would write
the label and the set_rip instruction. This is probably the only way
to make 100% sure that the label is always exactly at the set_rip

Something like below (completely untested, etc...).

Hope this helps,


Index: config/i386/i386-protos.h
--- config/i386/i386-protos.h   (revision 215483)
+++ config/i386/i386-protos.h   (working copy)
@@ -303,6 +303,7 @@ extern enum attr_cpu ix86_schedule;

 extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
+extern const char * ix86_output_set_rip_insn (rtx *operands);

 #ifdef RTX_CODE
 /* Target data for multipass lookahead scheduling.
Index: config/i386/i386.c
--- config/i386/i386.c  (revision 215483)
+++ config/i386/i386.c  (working copy)
@@ -11225,8 +11225,6 @@ ix86_expand_prologue (void)

              gcc_assert (Pmode == DImode);
              label = gen_label_rtx ();
-             emit_label (label);
-             LABEL_PRESERVE_P (label) = 1;
              tmp_reg = gen_rtx_REG (Pmode, R11_REG);
              gcc_assert (REGNO (pic_offset_table_rtx) != REGNO (tmp_reg));
              insn = emit_insn (gen_set_rip_rex64 (pic_offset_table_rtx,
@@ -12034,8 +12032,6 @@ ix86_expand_split_stack_prologue (void)
              rtx x;

              label = gen_label_rtx ();
-             emit_label (label);
-             LABEL_PRESERVE_P (label) = 1;
              emit_insn (gen_set_rip_rex64 (reg10, label));
              emit_insn (gen_set_got_offset_rex64 (reg11, label));
              emit_insn (ix86_gen_add3 (reg10, reg10, reg11));
@@ -25016,6 +25012,17 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op

   return "";
+/* Output the assembly for a SET_RIP instruction.  We do so with this output
+   function to ensure that the label and %rip load instruction are together. */
+const char *
+ix86_output_set_rip_insn (rtx *operands)
+  output_asm_label (operands[1]);
+  output_asm_insn ("lea{q}\t{%l1(%%rip), %0|%0, %l1[rip]}", operands);
+  return "";

 /* Clear stack slot assignments remembered from previous functions.
    This is called from INIT_EXPANDERS once before RTL is emitted for each
Index: config/i386/i386.md
--- config/i386/i386.md (revision 215483)
+++ config/i386/i386.md (working copy)
@@ -12010,7 +12010,7 @@
   [(set (match_operand:DI 0 "register_operand" "=r")
        (unspec:DI [(label_ref (match_operand 1))] UNSPEC_SET_RIP))]
-  "lea{q}\t{%l1(%%rip), %0|%0, %l1[rip]}"
+  "* return ix86_output_set_rip_insn (operands);"
   [(set_attr "type" "lea")
    (set_attr "length_address" "4")
    (set_attr "mode" "DI")])

More information about the Gcc-patches mailing list