)]}'
{
  "commit": "c7836d2ff5abab2dbb8220b629cac64c949ee607",
  "tree": "cdf9fae5c21801ee6127fface3ba5bac6da0017f",
  "parents": [
    "fd6a0a94e4a8d6f04d28109daca4a5d67201f4e0"
  ],
  "author": {
    "name": "Evan Brown CA",
    "email": "ezb@google.com",
    "time": "Wed Sep 30 12:50:44 2026 -0700"
  },
  "committer": {
    "name": "Copybara-Service",
    "email": "copybara-worker@google.com",
    "time": "Wed Sep 30 12:52:00 2026 -0700"
  },
  "message": "Schedule `Group{ctrl + seq.offset()}` load ahead of `PrefetchToLocalCache(slot_array + seq.offset())` in `find_large` and `find_or_prepare_insert_large`.\n\nMotivation: because `Group g{ctrl + seq.offset()}` no longer waits on `slot_array()`, the compiler schedules `vmovdqu` control load + hashing + `H2` earlier, and overlaps `slot_array()` + `seq.offset()` + `prefetcht0` with the `vmovdqu` load latency.\n\nWhy this improves lookup latency:\n1. Critical-path vs. non-blocking instruction priority at `seq.offset()`:\n   - Both `vmovdqu (%rax,%r9), %xmm1` (`Group{ctrl + seq.offset()}`) and `prefetcht0 (%rdi,%r9,8)` (`PrefetchToLocalCache(slot_array + seq.offset())`) depend on `seq.offset()` (`%r9 \u003d andnq %r9, %rcx, %r9`) and become ready in the exact same cycle in the out-of-order scheduler, competing for the same Load/AGU execution ports (`HWPort2`/`HWPort3` on Haswell/Skylake).\n   - `vmovdqu` is on the critical data-dependency chain of the lookup (`vmovdqu` [6c] -\u003e `vpcmpeqb` [1c] -\u003e `vpmovmskb` [3c] -\u003e `tzcntl` [3c] -\u003e `addq` [1c] -\u003e `andnq` [1c] -\u003e `cmpq (%rdi,%r11,8)` [6c]). Any 1-cycle delay in issuing `vmovdqu` delays the entire lookup by 1 cycle.\n   - By contrast, `prefetcht0` has zero data dependents, and the prefetched slot address `(%rdi,%r11,8)` is not read by `cmpq` until 13 cycles later (after `vmovdqu -\u003e vpcmpeqb -\u003e vpmovmskb -\u003e tzcntl -\u003e addq -\u003e andnq` completes).\n2. Earlier scheduling of `crc32q` and H2 broadcast in the function prologue:\n   - When `PrefetchToLocalCache(slot_array + seq.offset())` was first in the loop body, LLVM\u0027s instruction scheduler materialized `slot_array` (`movq %rax, %rcx; subq %rdi, %rcx; addq $0xf, %rcx`) in the entry block ahead of `prefetcht2 (%rax)` and `andl $0x7c0, %r8d` (the per-table seed mask feeding `crc32q`).\n   - Placing `Group g{ctrl + seq.offset()}` first allows LLVM to schedule `prefetcht2 (%rax)` and `andl $0x7c0, %r8d` + `crc32q` 3 instructions (1 dispatch group) earlier, sinking the 3-instruction `slot_array` calculation into the shadow of the `crc32q` hash finalization chain.\n3. Eliminating address-generation instructions before `vmovdqu` when `sizeof(slot_type) \u003e 8`:\n   - On x86-64, SIB addressing `(%base, %index, scale)` only supports `scale` in `{1, 2, 4, 8}`. For tables with `sizeof(slot_type)` not in `{1, 2, 4, 8}` (e.g., `24` for `std::string`, `40` for `pair\u003cstring, flat_hash_set\u003e`, etc.), computing `slot_array + seq.offset()` requires extra shift/LEA instructions (`leaq (%r8,%r8,4), %rax`) that depend on `seq.offset()`. Previously, `leaq` + `prefetcht0` were emitted ahead of `vmovdqu (%r9,%r8), %xmm1`; now `vmovdqu (%r9,%r13), %xmm1` (which always has `scale \u003d 1`) issues immediately after `andnq`.\n\nPiperOrigin-RevId: 991163033\nChange-Id: I758a9d2d38d8fd008cc40d30993836bf4e1da711\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "0b88b2f2c9efbafa31a3fc5af854923634c66c78",
      "old_mode": 33188,
      "old_path": "absl/container/internal/raw_hash_set.h",
      "new_id": "a942d0bbe902a259fd62a6aff3999148ffd3c750",
      "new_mode": 33188,
      "new_path": "absl/container/internal/raw_hash_set.h"
    }
  ]
}
