)]}'
{
  "commit": "7c9a0cfc58cdc69d9e5239e8c81c4161dce8a73e",
  "tree": "e46b708242c12d5ddb3d9052ff01f8a4811e6195",
  "parents": [
    "44e267cf138447324c3bd06d214ce40b970e8389"
  ],
  "author": {
    "name": "Richard Sandiford",
    "email": "rdsandiford@googlemail.com",
    "time": "Wed Jun 03 12:59:48 2026 +0100"
  },
  "committer": {
    "name": "Richard Sandiford",
    "email": "rdsandiford@googlemail.com",
    "time": "Wed Jun 03 12:59:48 2026 +0100"
  },
  "message": "cfgrtl: Forbid forwarder blocks from having clobbers [PR125375]\n\nIn this testcase, jump2 was presented with:\n\n L1:\n    set the return register\n    do epilogue stuff\n    goto L4\n\n L2:\n    do the same epilogue stuff\n\n L3:\n    clobber the return register\n    goto L4\n\nThe question then is: is the L3 block a forwarder block?  It is a\nforwarder block in the sense that a jump to L3 can be replaced with a\njump to L4.  But it isn\u0027t a forwarder block in the sense of a jump to L3\nbeing equivalent to a jump to L4.  In particular, a jump to L4 cannot be\nmerged with a jump or fallthrough to L3 unless we can prove that the\nclobber is valid for both paths.\n\nIn the testcase, L3 was marked as a forwarder block and so cross-jumping\ncreated:\n\n L1:\n    set the return register\n\n L2:\n    do epilogue stuff\n\n L3:\n    clobber the return register\n    goto L4\n\nThe set of the return register was then inevitably deleted as dead.\n\nThe clobber in this case is of the return register.  But the same\nprinciple/problem would apply to any clobber.  We can\u0027t introduce new\nclobbers on a path without proving that the clobbered thing is dead.\n\nThis question arises due to an old quirk of active_insn_p that predates\nCVS history:\n\n  bool\n  active_insn_p (const rtx_insn *insn)\n  {\n    return (CALL_P (insn) || JUMP_P (insn)\n\t    || JUMP_TABLE_DATA_P (insn) /* FIXME */\n\t    || (NONJUMP_INSN_P (insn)\n\t\t\u0026\u0026 (! reload_completed\n\t\t    || (GET_CODE (PATTERN (insn)) !\u003d USE\n\t\t\t\u0026\u0026 GET_CODE (PATTERN (insn)) !\u003d CLOBBER))));\n  }\n\nThus a clobber is \"active\" before RA but not after it.  This means\nthat, according to flow_active_insn_p, a block with a clobber is not\na forwarder block before RA, but can be afterwards.\n\nThe \"most optimal\" solution would probably be to split the concept\nof forwarder block into two, one that allows clobbers and one that\ndoesn\u0027t.  However, that would be difficult to retrofit at this stage\nand isn\u0027t likely to be suitable for backporting.  This patch therefore\ntakes the more conservative approach of making flow_active_insn_p treat\nclobbers in the same way after RA as it does before RA.\n\nSome of this infrastructure is probably ripe for updating.  For example,\nflow might have required explicit uses of the return register, but DF\nshould cope well enough without.  We should probably also check\nwhether the active_insn_p behaviour still makes sense.\n\ngcc/\n\tPR rtl-optimization/125375\n\t* cfgrtl.cc (flow_active_insn_p): Return true for clobbers.\n\ngcc/testsuite/\n\t* gcc.dg/pr125375.c: New test.\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "0e409140e71d3aeeff1ff734cbb2f872321ce5fd",
      "old_mode": 33188,
      "old_path": "gcc/cfgrtl.cc",
      "new_id": "18f09cceed0081c996e490771e66ee80affc9449",
      "new_mode": 33188,
      "new_path": "gcc/cfgrtl.cc"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "512d2377858502721e5818a2693ecd5ce51fd9ff",
      "new_mode": 33188,
      "new_path": "gcc/testsuite/gcc.dg/pr125375.c"
    }
  ]
}
