)]}'
{
  "commit": "81a34bdbcb3e27a8fb2438fd90bbb76ec506fb40",
  "tree": "8c5a15be46fc5893acead2149440809bf8037451",
  "parents": [
    "263ce2e907f72273abf246e923d7530894f25281"
  ],
  "author": {
    "name": "Kyrylo Tkachov",
    "email": "ktkachov@nvidia.com",
    "time": "Fri Aug 14 09:51:09 2026 -0700"
  },
  "committer": {
    "name": "Kyrylo Tkachov",
    "email": "ktkachov@nvidia.com",
    "time": "Tue Aug 25 12:46:10 2026 +0200"
  },
  "message": "middle-end: do not widen a multiply-add across a shared conversion\n\nconvert_plusminus_to_widen folds a multiply and an addition into a single\nWIDEN_MULT_PLUS_EXPR.  That is only a win if the multiply dies, so the pass\nrequires its result to be single-use.  When the multiply reaches the addition\nthrough a conversion, the check is applied to the wrong value: the multiply is\nsingle-use because only the conversion reads it, while the value the additions\nactually share is the conversion result.  Each addition then gets its own copy\nof the multiply and the original stays live.\n\nFor\n\n  void f (const signed char *base, int i, const signed char **out)\n  {\n    unsigned long o \u003d (unsigned long) ((long) i * 128);\n    out[0] \u003d base + o;\n    out[1] \u003d base + o + 16;\n    out[2] \u003d base + o + 32;\n    out[3] \u003d base + o + 48;\n  }\n\nthe pass turns\n\n  _2 \u003d i_10(D) * 128;\n  o_11 \u003d (long unsigned int) _2;\n  _3 \u003d base_12(D) + o_11;\n  _4 \u003d o_11 + 16;\n  _6 \u003d o_11 + 32;\n  _8 \u003d o_11 + 48;\n\ninto\n\n  _2 \u003d i_10(D) w* 128;\n  o_11 \u003d (long unsigned int) _2;\n  _3 \u003d base_12(D) + o_11;\n  _4 \u003d WIDEN_MULT_PLUS_EXPR \u003ci_10(D), 128, 16\u003e;\n  _6 \u003d WIDEN_MULT_PLUS_EXPR \u003ci_10(D), 128, 32\u003e;\n  _8 \u003d WIDEN_MULT_PLUS_EXPR \u003ci_10(D), 128, 48\u003e;\n\nwhich is four multiplies where there was one.  On AArch64 that is 3 SMADDL\nplus the three constants in registers instead of one SBFIZ and three adds, and\nbecause every address then needs its own register offset it also blocks LDP\nformation.\n\nApply the same single-use requirement to the conversion result.\n\nFound in the Stockfish NNUE sparse affine kernel, where the eight weight\ncolumn addresses share one scaled index.  On an AArch64 build the number of\nSMADDL in the binary falls from 19 to 5, dynamic instruction count falls by\nabout 4.7%.\n\nBootstrapped and tested on aarch64-none-linux-gnu.\n\ngcc/ChangeLog:\n\n\t* tree-ssa-math-opts.cc (convert_plusminus_to_widen): Require the\n\tresult of an intervening conversion to be single-use.\n\ngcc/testsuite/ChangeLog:\n\n\t* gcc.dg/widening-mul-conv-1.c: New test.\n\nSigned-off-by: Kyrylo Tkachov \u003cktkachov@nvidia.com\u003e\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5ea25ed298a11a789b1c9392ae76f4560d68f55e",
      "new_mode": 33188,
      "new_path": "gcc/testsuite/gcc.dg/widening-mul-conv-1.c"
    },
    {
      "type": "modify",
      "old_id": "ebc3300ae33247cd9f6469e3e794903fd58a0e67",
      "old_mode": 33188,
      "old_path": "gcc/tree-ssa-math-opts.cc",
      "new_id": "b371b5b7cff929cf2289fc47e652835ff15cf9ce",
      "new_mode": 33188,
      "new_path": "gcc/tree-ssa-math-opts.cc"
    }
  ]
}
