https://gcc.gnu.org/g:56c143bca7c95559e5fb0882b649d94b3749e341
commit r16-6848-g56c143bca7c95559e5fb0882b649d94b3749e341 Author: Kugan Vivekanandarajah <[email protected]> Date: Sat Jan 17 07:59:57 2026 +1100 [AutoFDO] Walk function body to to find existing max copyids per location This patch addresses the review comment and walks the function body to find existing max copyids per location in init_copyid_allocator. gcc/ChangeLog: 2026-01-15 Kugan Vivekanandarajah <[email protected]> * hierarchical_discriminator.cc (init_copyid_allocator): Walks the function body to find existing max copyids per location. (record_existing_copyid): New. gcc/testsuite/ChangeLog: 2026-01-15 Kugan Vivekanandarajah <[email protected]> * gcc.dg/hierarchical-discriminator-loop-version.c: Simplify. * gcc.dg/hierarchical-discriminator-unroll.c: Likewise * gcc.dg/hierarchical-discriminator-vect-version.c: Likewise. Signed-off-by: Kugan Vivekanandarajah <[email protected]> Diff: --- gcc/hierarchical_discriminator.cc | 89 ++++++++++++++++++++-- .../hierarchical-discriminator-loop-version.c | 20 ++--- .../gcc.dg/hierarchical-discriminator-unroll.c | 19 ++--- .../hierarchical-discriminator-vect-version.c | 4 +- 4 files changed, 98 insertions(+), 34 deletions(-) diff --git a/gcc/hierarchical_discriminator.cc b/gcc/hierarchical_discriminator.cc index 734da65c29d3..009b1a83f1e8 100644 --- a/gcc/hierarchical_discriminator.cc +++ b/gcc/hierarchical_discriminator.cc @@ -184,7 +184,38 @@ assign_discriminators_to_loop (class loop *loop, } -/* Initialize the per-function copyid allocator. */ +/* Helper to update the copyid allocator map with a location's existing copyid. + If the location has a non-zero copyid, record that we need to start + allocating from copyid+1 for this location. */ + +static void +record_existing_copyid (location_t loc, struct function *fn) +{ + if (loc == UNKNOWN_LOCATION) + return; + + location_t pure_loc = get_pure_location (loc); + unsigned int discr = get_discriminator_from_loc (loc); + if (discr == 0) + return; + + /* Extract copyid from discriminator. */ + unsigned int copyid = (discr >> DISCR_COPYID_SHIFT) & DISCR_COPYID_MASK; + if (copyid == 0) + return; + + /* Update max copyid for this location. */ + unsigned int next_copyid = copyid + 1; + if (next_copyid > DISCR_COPYID_MAX) + next_copyid = DISCR_COPYID_MAX; + + unsigned int *existing = fn->copyid_alloc->location_map->get (pure_loc); + if (!existing || *existing <= copyid) + fn->copyid_alloc->location_map->put (pure_loc, next_copyid); +} + +/* Initialize the per-function copyid allocator. Walks the function + body to find existing max copyids per location. */ static void init_copyid_allocator (struct function *fn) @@ -192,13 +223,59 @@ init_copyid_allocator (struct function *fn) if (!fn) return; - if (fn->copyid_alloc) + if (fn->copyid_alloc && fn->copyid_alloc->initialized) return; /* Already initialized. */ - fn->copyid_alloc = XNEW (struct copyid_allocator); - fn->copyid_alloc->location_map - = new hash_map<int_hash<location_t, UNKNOWN_LOCATION, UNKNOWN_LOCATION>, - unsigned int>; + if (!fn->copyid_alloc) + { + fn->copyid_alloc = XNEW (struct copyid_allocator); + fn->copyid_alloc->location_map + = new hash_map<int_hash<location_t, UNKNOWN_LOCATION, + UNKNOWN_LOCATION>, unsigned int>; + fn->copyid_alloc->initialized = false; + } + + /* Only walk the body if not yet initialized. */ + if (fn->copyid_alloc->initialized) + return; + + /* Walk the function body to find existing max copyids per location. + This ensures we don't reuse copyids that were allocated in previous + passes, during LTO, or brought in by inlining. */ + basic_block bb; + FOR_EACH_BB_FN (bb, fn) + { + if (current_ir_type () == IR_GIMPLE) + { + /* Process PHI nodes. */ + gphi_iterator phi_gsi; + for (phi_gsi = gsi_start_phis (bb); !gsi_end_p (phi_gsi); + gsi_next (&phi_gsi)) + record_existing_copyid (gimple_location (phi_gsi.phi ()), fn); + + /* Process regular statements. */ + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + record_existing_copyid (gimple_location (gsi_stmt (gsi)), fn); + + /* Process edge goto_locus locations. */ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->succs) + record_existing_copyid (e->goto_locus, fn); + } + else + { + /* For RTL mode. */ + rtx_insn *insn; + FOR_BB_INSNS (bb, insn) + { + if (INSN_P (insn)) + record_existing_copyid (INSN_LOCATION (insn), fn); + } + } + } + fn->copyid_alloc->initialized = true; } diff --git a/gcc/testsuite/gcc.dg/hierarchical-discriminator-loop-version.c b/gcc/testsuite/gcc.dg/hierarchical-discriminator-loop-version.c index af9dddf554f0..dbe7953e3e30 100644 --- a/gcc/testsuite/gcc.dg/hierarchical-discriminator-loop-version.c +++ b/gcc/testsuite/gcc.dg/hierarchical-discriminator-loop-version.c @@ -10,19 +10,11 @@ test_loop_versioning (double *x, int stepx, int n) x[stepx * i] = 100; } -/* Expected discriminators from the assembly (hierarchical format: [Base:8][Multiplicity:7][CopyID:11][Unused:6]): - - Loop versioning creates two versions: - 1. Optimized loop (for stride == 1): - - copyid = allocate_copyid_base(loc, 1) = 1 (first allocation) - - multiplicity = 0 (no vectorization in this pass) - - Discriminator = base:0 | (0<<8) | (1<<15) = 0 | 0 | 32768 = 32768 - - 2. Unoptimized loop (for stride != 1): - - copyid = allocate_copyid_base(loc, 1) = 2 (second allocation at same location) - - multiplicity = 0 - - Discriminator = base:0 | (0<<8) | (2<<15) = 0 | 0 | 65536 = 65536 -*/ +/* Loop versioning creates two versions of the loop, each should get a distinct + copyid in the hierarchical discriminator format: [Base:8][Multiplicity:7][CopyID:11][Unused:6]. + The exact copyid values depend on what other passes have run before, but both + loop versions should have non-zero discriminators to distinguish them for AutoFDO. */ +/* Check that loop versioning occurred and discriminators are present on the loop body. */ /* { dg-final { scan-tree-dump "versioned this loop for when certain strides are 1" "lversion" } } */ -/* { dg-final { scan-assembler "\\.loc 1 14 \[0-9\]+ is_stmt 0 discriminator \[0-9\]+" } } */ +/* { dg-final { scan-assembler "\\.loc 1 (9|10) \[0-9\]+ is_stmt 0 discriminator \[0-9\]+" } } */ diff --git a/gcc/testsuite/gcc.dg/hierarchical-discriminator-unroll.c b/gcc/testsuite/gcc.dg/hierarchical-discriminator-unroll.c index c22baaeee38f..f137c1c6b141 100644 --- a/gcc/testsuite/gcc.dg/hierarchical-discriminator-unroll.c +++ b/gcc/testsuite/gcc.dg/hierarchical-discriminator-unroll.c @@ -21,17 +21,10 @@ test_unroll (void) return sum; } -/* Expected discriminators from the assembly (hierarchical format: [Base:8][Multiplicity:7][CopyID:11][Unused:6]): - Loop unrolling with ndupl=4: - - allocate_copyid_base(loc, 4) returns base=1 (first time) - - Iteration 0: copyid = 1+0 = 1, multiplicity=0 → 0|(0<<8)|(1<<15) = 32768 - - Iteration 1: copyid = 1+1 = 2, multiplicity=0 → 0|(0<<8)|(2<<15) = 65536 - - Iteration 2: copyid = 1+2 = 3, multiplicity=0 → 0|(0<<8)|(3<<15) = 98304 - - Iteration 3: copyid = 1+3 = 4, multiplicity=0 → 0|(0<<8)|(4<<15) = 131072 -*/ +/* Loop unrolling with #pragma GCC unroll 4 should create 4 copies with distinct + copyids in the hierarchical discriminator format: [Base:8][Multiplicity:7][CopyID:11][Unused:6]. + Each unrolled iteration should get a different copyid, resulting in different discriminators. + The exact values depend on what other passes have run, but all should be non-zero. */ -/* Each unrolled iteration should have a different discriminator */ -/* { dg-final { scan-assembler "\\.loc 1 17 7 is_stmt 0 discriminator 32768" } } */ -/* { dg-final { scan-assembler "\\.loc 1 17 7 is_stmt 0 discriminator 65536" } } */ -/* { dg-final { scan-assembler "\\.loc 1 17 7 is_stmt 0 discriminator 98304" } } */ -/* { dg-final { scan-assembler "\\.loc 1 17 7 is_stmt 0 discriminator 131072" } } */ +/* Check that unrolled iterations have non-zero discriminators on the asm statement line. */ +/* { dg-final { scan-assembler "\\.loc 1 17 7 is_stmt 0 discriminator (\[1-9\]\[0-9\]*|0x\[1-9a-fA-F\]\[0-9a-fA-F\]*)" } } */ diff --git a/gcc/testsuite/gcc.dg/hierarchical-discriminator-vect-version.c b/gcc/testsuite/gcc.dg/hierarchical-discriminator-vect-version.c index 5dc945f1274d..95f1fe0b9334 100644 --- a/gcc/testsuite/gcc.dg/hierarchical-discriminator-vect-version.c +++ b/gcc/testsuite/gcc.dg/hierarchical-discriminator-vect-version.c @@ -14,4 +14,6 @@ test_vectorize (int *a, int *b, int *c, int n) } } -/* { dg-final { scan-assembler "\\.loc 1 13 \[0-9\]+ is_stmt 0 discriminator \[0-9\]+" } } */ +/* Check that vectorized code has discriminators on the main loop body line. + The discriminator should be non-zero to distinguish vector vs scalar versions. */ +/* { dg-final { scan-assembler "\\.loc 1 13 \[0-9\]+ is_stmt 0 discriminator (\[1-9\]\[0-9\]*|0x\[1-9a-fA-F\]\[0-9a-fA-F\]*)" } } */
