This is the mail archive of the gcc-bugs@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]

[Bug rtl-optimization/24319] [3.4/4.0/4.1 regression] amd64 register spill error with -fschedule-insns



------- Comment #6 from uros at kss-loka dot si  2005-11-09 15:27 -------
The problem is caused by the combination of (1) x86_64 parameter passing
convention, (2) x86 instructions that _require_ parameters in specific
registers and (3) sched1 scheduling pass.

ad 1)

x86_64 passes function parameters in registers in the order, defined in
x86_64_int_parameter_registers[] array.

  5 /*RDI*/, 4 /*RSI*/, 1 /*RDX*/, 2 /*RCX*/,
  FIRST_REX_INT_REG /*R8 */, FIRST_REX_INT_REG + 1 /*R9 */

Additionally, RAX is used as a hidden argument register.

In original example, call sequence to "memory_to_string" is constructed as:

(insn 17 15 18 0 (set (reg:DI 4 si)
        (reg:DI 61)) 81 {*movdi_1_rex64} (insn_list:REG_DEP_TRUE 15 (nil))
    (expr_list:REG_DEAD (reg:DI 61)
        (nil)))

(insn 18 17 19 0 (set (reg:DI 5 di [ c_string ])
        (reg/v/f:DI 60 [ c_string ])) 81 {*movdi_1_rex64} (nil)
    (expr_list:REG_DEAD (reg/v/f:DI 60 [ c_string ])
        (nil)))

(call_insn 19 18 20 0 (set (reg:DI 0 ax)
        (call (mem:QI (symbol_ref:DI ("memory_to_string") [flags 0x3]
<function_decl 0x4044f080 memory_to_string>) [0 S1 A8])
            (const_int 0 [0x0]))) 732 {*call_value_0_rex64}
(insn_list:REG_DEP_TRUE 17 (insn_list:REG_DEP_TRUE 18 (nil)))
    (expr_list:REG_DEAD (reg:DI 4 si)
        (expr_list:REG_DEAD (reg:DI 5 di [ c_string ])
            (expr_list:REG_EH_REGION (const_int 0 [0x0])
                (nil))))
    (expr_list:REG_DEP_TRUE (use (reg:DI 5 di [ c_string ]))
        (expr_list:REG_DEP_TRUE (use (reg:DI 4 si))
            (nil))))


ad 2)

Please note, that this sequence can be found just after *strlenqi_rex_1
mega-pattern. This pattern requires parameters to be put in excactly defined
registers:

(define_insn "*strlenqi_rex_1"
  [(set (match_operand:DI 0 "register_operand" "=&c")
        (unspec:DI [(mem:BLK (match_operand:DI 5 "register_operand" "1"))
                    (match_operand:QI 2 "register_operand" "a")
                    (match_operand:DI 3 "immediate_operand" "i")
                    (match_operand:DI 4 "register_operand" "0")] UNSPEC_SCAS))
   (use (reg:SI DIRFLAG_REG))
   (clobber (match_operand:DI 1 "register_operand" "=D"))
   (clobber (reg:CC FLAGS_REG))]

However, at the time of sched1 pass (before reload) hard registers are not
known yet. We have following RTL pattern just above "memory_to_string" call
sequence (reg_notes are not shown for clarity):

(insn 13 12 14 0 (parallel [
            (set (reg:DI 63)
                (unspec:DI [
                        (mem:BLK (reg/f:DI 65 [ c_string ]) [0 A8])
                        (reg:QI 67)
                        (const_int 1 [0x1])
                        (reg:DI 66)
                    ] 20))
            (use (reg:SI 19 dirflag))
            (clobber (reg/f:DI 65 [ c_string ]))
            (clobber (reg:CC 17 flags))
        ]) 511 {*strlenqi_rex_1}


ad 3)

Sched1 pass is free to move (insn 17) and (insn 18) before (insn 13) as it
doesn't recognize register allocating conflicts between these instructions.
Following that move, reload has no registers to spill and ICEs.

The testcase from comment #3 ICEs with:
error: unable to find a register to spill in class âAREGâ

Here, the same problem could be observed. As "foo" is missing a prototype,
hidden RAX register gets allocated in addition to RDI:

(insn 20 18 21 0 (set (reg:DI 5 di)
        (reg:DI 61)) 81 {*movdi_1_rex64} (insn_list:REG_DEP_TRUE 18 (nil))
    (expr_list:REG_DEAD (reg:DI 61)
        (nil)))

(insn 21 20 22 0 (set (reg:QI 0 ax)
        (const_int 0 [0x0])) 55 {*movqi_1} (nil)
    (nil))

(call_insn 22 21 23 0 (set (reg:SI 0 ax)
        (call (mem:QI (symbol_ref:DI ("foo") [flags 0x41] <function_decl
0x402cbd80 foo>) [0 S1 A8])
            (const_int 0 [0x0]))) 732 {*call_value_0_rex64}
(insn_list:REG_DEP_TRUE 20 (insn_list:REG_DEP_TRUE 21 (nil)))
    (expr_list:REG_DEAD (reg:DI 5 di)
        (nil))
    (expr_list:REG_DEP_TRUE (use (reg:QI 0 ax))
        (expr_list:REG_DEP_TRUE (use (reg:DI 5 di))
            (nil))))

This AX register is then moved before "strlenqi_rex_1" pattern and this blocks
the AX register. (BTW: If prototype of "foo" is added, this particular testcase
compiles OK.)

One possible fix to this problem would be not to schedule instructions that
have assigned hard registers (move insns in above case). Considering the number
of x86 instructions, that require fixed registers I would suggest bugmasters to
raise the priority of this bug.

The x86 backend should not have these problems, but using -mregparm=X I think
it could also be tricked to this sort of ICEs.

(BTW: I have added Jim Wilson to CC of this bug as he is current maintaine of
insn scheduling pass code. Perhaps he has some ideas on how to solve this
problem.)


-- 

uros at kss-loka dot si changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |wilson at gcc dot gnu dot
                   |                            |org, uros at kss-loka dot si


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24319


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