}
-/* 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)
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;
}
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\]+" } } */
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\]*)" } } */