https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60874

--- Comment #8 from Uroš Bizjak <ubizjak at gmail dot com> ---
After lots of debugging...

The problem is with the label that is passed as an argument to
__go_set_defer_retaddr. In function main.$thunk0, in _.179r.cse1 dump, we have:

...

(insn 7 3 8 2 (set (reg:DI 84)
        (high:DI (label_ref:DI 47))) rr.go:57 236 {*movdi}
     (insn_list:REG_LABEL_OPERAND 47 (nil)))
(insn 8 7 9 2 (set (reg:DI 83)
        (lo_sum:DI (reg:DI 84)
            (label_ref:DI 47))) rr.go:57 230 {*movdi_er_low_l}
     (insn_list:REG_LABEL_OPERAND 47 (expr_list:REG_EQUAL (label_ref:DI 47)
            (nil))))
(insn 9 8 10 2 (set (reg:DI 16 $16)
        (reg:DI 83)) rr.go:57 236 {*movdi}
     (nil))
(call_insn 10 9 11 2 (parallel [
            (set (reg:DI 0 $0)
                (call (mem:DI (symbol_ref:DI ("__go_set_defer_retaddr") [flags
0x41]  <function_decl 0x2000066a900 __go_set_defer_retaddr>) [0
__go_set_defer_retaddr S8 A64])
                    (const_int 0 [0])))
            (use (reg:DI 29 $29))
            (clobber (reg:DI 26 $26))
        ]) rr.go:57 357 {*call_value_osf_1_er}
     (expr_list:REG_CALL_DECL (symbol_ref:DI ("__go_set_defer_retaddr") [flags
0x41]  <function_decl 0x2000066a900 __go_set_defer_retaddr>)
        (nil))
    (expr_list:DI (use (reg:DI 16 $16))
        (nil)))

...

(call_insn 46 45 47 5 (parallel [
            (call (mem:DI (reg/f:DI 80 [ D.1014 ]) [0 *_42 S8 A64])
                (const_int 4048 [0xfd0]))
            (use (reg:DI 29 $29))
            (clobber (reg:DI 26 $26))
        ]) rr.go:57 210 {*call_osf_1_er}
     (expr_list:REG_DEAD (reg/f:DI 80 [ D.1014 ])
        (expr_list:REG_DEAD (reg:DI 21 $21)
            (expr_list:REG_DEAD (reg:DI 20 $20)
                (expr_list:REG_DEAD (reg:DI 19 $19)
                    (expr_list:REG_DEAD (reg:DI 18 $18)
                        (expr_list:REG_DEAD (reg:DI 17 $17)
                            (expr_list:REG_DEAD (reg:DI 16 $16)
                                (expr_list:REG_CALL_DECL (nil)
                                    (nil)))))))))
    (expr_list (use (reg:DI 21 $21))
        (expr_list (use (reg:DI 20 $20))
            (expr_list (use (reg:DI 19 $19))
                (expr_list (use (reg:DI 18 $18))
                    (expr_list (use (reg:DI 17 $17))
                        (expr_list (use (reg:DI 16 $16))
                            (expr_list:BLK (use (mem:BLK (reg/f:DI 30 $30) [0 
S4048 A64]))
                                (nil)))))))))
;;  succ:       6 [100.0%]  (FALLTHRU)
;; lr  out       15 [$15] 26 [$26] 29 [$29] 30 [$30] 31 [AP] 63 [FP]
;; live  out     15 [$15] 29 [$29] 30 [$30] 31 [AP] 63 [FP]

;; basic block 6, loop depth 0, count 0, freq 10000, maybe hot
;;  prev block 5, next block 7, flags: (REACHABLE, RTL, MODIFIED)
;;  pred:       2 [39.0%]
;;              5 [100.0%]  (FALLTHRU)
;; bb 6 artificial_defs: { }
;; bb 6 artificial_uses: { u-1(15){ }u-1(29){ }u-1(30){ }u-1(31){ }u-1(63){ }}
;; lr  in        15 [$15] 26 [$26] 29 [$29] 30 [$30] 31 [AP] 63 [FP]
;; lr  use       15 [$15] 29 [$29] 30 [$30] 31 [AP] 63 [FP]
;; lr  def       81
;; live  in      15 [$15] 29 [$29] 30 [$30] 31 [AP] 63 [FP]
;; live  gen     81
;; live  kill
(code_label/s 47 46 48 6 2 ("retaddr") [5 uses])
(note 48 47 49 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
(insn 49 48 52 6 (set (reg:DI 81 [ <retval> ])
        (const_int 0 [0])) rr.go:57 236 {*movdi}
     (nil))

 succ:       8 [100.0%]  (FALLTHRU)

Unfortunatelly, this is not a robust approach, since in a follow-up
_.180r.fwprop1 pass (insn 49) propagates to function return value, leaving:

(code_label/s 47 46 48 6 2 ("retaddr") [5 uses])
(note 48 47 52 6 [bb 6] NOTE_INSN_BASIC_BLOCK)
;;  succ:       8 [100.0%]  (FALLTHRU)

The following 181r.cprop pass removes the label (also updates passed argument
to __go_set_defer_retaddr in (insn 7) and (insn 8)) and merges bb after a thunk
call:

(insn 7 3 8 2 (set (reg/f:DI 84)
        (high:DI (label_ref:DI [47 deleted]))) rr.go:57 236 {*movdi}
     (insn_list:REG_LABEL_OPERAND 47 (nil)))
(insn 8 7 9 2 (set (reg/f:DI 83)
        (lo_sum:DI (reg/f:DI 84)
            (label_ref:DI [47 deleted]))) rr.go:57 230 {*movdi_er_low_l}
     (expr_list:REG_DEAD (reg/f:DI 84)
        (insn_list:REG_LABEL_OPERAND 47 (expr_list:REG_EQUAL (label_ref:DI [47
deleted])
                (nil)))))

...

(call_insn 46 45 47 5 (parallel [
            (call (mem:DI (reg/f:DI 80 [ D.1014 ]) [0 *_42 S8 A64])
                (const_int 4048 [0xfd0]))
            (use (reg:DI 29 $29))
            (clobber (reg:DI 26 $26))
        ]) rr.go:57 210 {*call_osf_1_er}
     (expr_list:REG_DEAD (reg/f:DI 80 [ D.1014 ])
        (expr_list:REG_DEAD (reg:DI 21 $21)
            (expr_list:REG_DEAD (reg:DI 20 $20)
                (expr_list:REG_DEAD (reg:DI 19 $19)
                    (expr_list:REG_DEAD (reg:DI 18 $18)
                        (expr_list:REG_DEAD (reg:DI 17 $17)
                            (expr_list:REG_DEAD (reg:DI 16 $16)
                                (expr_list:REG_CALL_DECL (nil)
                                    (nil)))))))))
    (expr_list (use (reg:DI 21 $21))
        (expr_list (use (reg:DI 20 $20))
            (expr_list (use (reg:DI 19 $19))
                (expr_list (use (reg:DI 18 $18))
                    (expr_list (use (reg:DI 17 $17))
                        (expr_list (use (reg:DI 16 $16))
                            (expr_list:BLK (use (mem:BLK (reg/f:DI 30 $30) [0 
S4048 A64]))
                                (nil)))))))))
(note/s 47 46 52 5 ("retaddr") NOTE_INSN_DELETED_LABEL 2)
;;  succ:       8 [100.0%]  (FALLTHRU)

The missing label is substituted with a reference to some nearby label,
resulting in:

[+]     ldah $16,$L8($29)               !gprelhigh
        stq $26,4048($30)
        stq $9,4056($30)
[+]     lda $16,$L8($16)                !gprellow
        jsr $26,($27),__go_set_defer_retaddr            !lituse_jsr!22
...
$L10:
$L8:
        ldq $27,memcpy($29)             !literal!12
        lda $17,56($9)
        mov $30,$16
        lda $18,4048($31)
        jsr $26,($27),memcpy            !lituse_jsr!12
...
[++]    jsr $26,($27),0
        ldah $29,0($26)         !gpdisp!24
        lda $29,0($29)          !gpdisp!24
$L11:
        mov $31,$0


The [+] marks wrong label load and [++] marks thunk call. $L8 is an unrelated
label that gets loaded as an argument to __go_set_defer_retaddr.

Since $L8 is "far" away from thunk call, this fails the test in
__go_can_recover (runtime/go-recover.c):

  dret = (const char *) d->__retaddr;
  if (ret <= dret && ret + 16 >= dret)
    return 1;

Manually changing $L8 to $L11 in the call to __go_set_defer_retaddr (in an
assembly) results in a successful test.

Reply via email to