Hello,

when testing an out-of-tree patch I ran into a latent bug.
The symptom is error messages along the lines of
/tmp/cc6q0E3x.s:38: Error: co-processor offset out of range
caused by an out-of-range reference to a literal pool constant.
This happens only with -O0.

This turns out to caused by insn_and_split patterns in sync.md
used to represent atomic instructions.  Those will (must) always
be split (usually into some form of compare-and-swap loop).  If
optimization is on, this split happens shortly after reload,
before literal pool placement is finalized.

However, when building with -O0, this split is done very late;
in fact it happens *after* the machine-dependent reorg pass
where literal pools are handled.  This means that this pass
sees the atomic patterns as single insns, and unfortunately,
since they have no length attribute, they are handled as if
they had a default length of 4 bytes.

But since those patterns in the end will expand to at least
5-9 actual machine instructions, this default drastically
underestimates the code size, causing the out of range
references.

The patch below adds length attributes giving conservative
estimates of the final resulting code sizes.  (They could
probably be made more specific, but since this is relevant
only for -O0, that's probably not worth the effort.)

This fixes the problems I was seeing.

Tested on arm-linux-gnueabi with no regressions.

OK for mainline?

Bye,
Ulrich


ChangeLog:

        * config/arm/sync.md (cas_length): New mode attribute.
        (atomic_op_length, atomic_nand_length): Likewise.
        ("atomic_compare_and_swap<mode>_1"): Add length attribute.
        ("atomic_exchange<mode>"): Likewise.
        ("atomic_<sync_optab><mode>"): Likewise.
        ("atomic_nand<mode>"): Likewise.
        ("atomic_fetch_<sync_optab><mode>"): Likewise.
        ("atomic_fetch_nand<mode>"): Likewise.
        ("atomic_<sync_optab>_fetch<mode>"): Likewise.
        ("atomic_nand_fetch<mode>"): Likewise.

Index: gcc/config/arm/sync.md
===================================================================
*** gcc/config/arm/sync.md      (revision 189459)
--- gcc/config/arm/sync.md      (working copy)
***************
*** 127,138 ****
    {
      arm_split_compare_and_swap (operands);
      DONE;
!   })
  
  (define_mode_attr cas_cmp_operand
    [(SI "arm_add_operand") (DI "cmpdi_operand")])
  (define_mode_attr cas_cmp_str
    [(SI "rIL") (DI "rDi")])
  
  (define_insn_and_split "atomic_compare_and_swap<mode>_1"
    [(set (reg:CC_Z CC_REGNUM)                                  ;; bool out
--- 127,141 ----
    {
      arm_split_compare_and_swap (operands);
      DONE;
!   }
!   [(set_attr "length" "32")])
  
  (define_mode_attr cas_cmp_operand
    [(SI "arm_add_operand") (DI "cmpdi_operand")])
  (define_mode_attr cas_cmp_str
    [(SI "rIL") (DI "rDi")])
+ (define_mode_attr cas_length
+   [(SI "32") (DI "44")])
  
  (define_insn_and_split "atomic_compare_and_swap<mode>_1"
    [(set (reg:CC_Z CC_REGNUM)                                  ;; bool out
***************
*** 155,161 ****
    {
      arm_split_compare_and_swap (operands);
      DONE;
!   })
  
  (define_insn_and_split "atomic_exchange<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")     ;; output
--- 158,165 ----
    {
      arm_split_compare_and_swap (operands);
      DONE;
!   }
!   [(set_attr "length" "<cas_length>")])
  
  (define_insn_and_split "atomic_exchange<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")     ;; output
***************
*** 175,181 ****
      arm_split_atomic_op (SET, operands[0], NULL, operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   })
  
  (define_mode_attr atomic_op_operand
    [(QI "reg_or_int_operand")
--- 179,186 ----
      arm_split_atomic_op (SET, operands[0], NULL, operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   }
!   [(set_attr "length" "20")])
  
  (define_mode_attr atomic_op_operand
    [(QI "reg_or_int_operand")
***************
*** 186,191 ****
--- 191,199 ----
  (define_mode_attr atomic_op_str
    [(QI "rn") (HI "rn") (SI "rn") (DI "r")])
  
+ (define_mode_attr atomic_op_length
+   [(QI "24") (HI "24") (SI "24") (DI "28")])
+ 
  (define_insn_and_split "atomic_<sync_optab><mode>"
    [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua")
        (unspec_volatile:QHSD
***************
*** 204,210 ****
      arm_split_atomic_op (<CODE>, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
      DONE;
!   })
  
  (define_insn_and_split "atomic_nand<mode>"
    [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua")
--- 212,222 ----
      arm_split_atomic_op (<CODE>, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_op_length>")])
! 
! (define_mode_attr atomic_nand_length
!   [(QI "28") (HI "28") (SI "28") (DI "32")])
  
  (define_insn_and_split "atomic_nand<mode>"
    [(set (match_operand:QHSD 0 "mem_noofs_operand" "+Ua")
***************
*** 225,231 ****
      arm_split_atomic_op (NOT, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
      DONE;
!   })
  
  (define_insn_and_split "atomic_fetch_<sync_optab><mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
--- 237,244 ----
      arm_split_atomic_op (NOT, NULL, operands[3], operands[0],
                         operands[1], operands[2], operands[4]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_nand_length>")])
  
  (define_insn_and_split "atomic_fetch_<sync_optab><mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
***************
*** 247,253 ****
      arm_split_atomic_op (<CODE>, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
      DONE;
!   })
  
  (define_insn_and_split "atomic_fetch_nand<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
--- 260,267 ----
      arm_split_atomic_op (<CODE>, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_op_length>")])
  
  (define_insn_and_split "atomic_fetch_nand<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
***************
*** 270,276 ****
      arm_split_atomic_op (NOT, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
      DONE;
!   })
  
  (define_insn_and_split "atomic_<sync_optab>_fetch<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
--- 284,291 ----
      arm_split_atomic_op (NOT, operands[0], operands[4], operands[1],
                         operands[2], operands[3], operands[5]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_nand_length>")])
  
  (define_insn_and_split "atomic_<sync_optab>_fetch<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
***************
*** 292,298 ****
      arm_split_atomic_op (<CODE>, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   })
  
  (define_insn_and_split "atomic_nand_fetch<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
--- 307,314 ----
      arm_split_atomic_op (<CODE>, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_op_length>")])
  
  (define_insn_and_split "atomic_nand_fetch<mode>"
    [(set (match_operand:QHSD 0 "s_register_operand" "=&r")
***************
*** 315,321 ****
      arm_split_atomic_op (NOT, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   })
  
  (define_insn "arm_load_exclusive<mode>"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
--- 331,338 ----
      arm_split_atomic_op (NOT, NULL, operands[0], operands[1],
                         operands[2], operands[3], operands[4]);
      DONE;
!   }
!   [(set_attr "length" "<atomic_nand_length>")])
  
  (define_insn "arm_load_exclusive<mode>"
    [(set (match_operand:SI 0 "s_register_operand" "=r")
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  ulrich.weig...@de.ibm.com

Reply via email to