whitepaper: 398/185 — wave6d (rails-0012..16, jsc-0001/2, vtk, sm-0002, redis/valkey-0003, helm-0002/3, k8s-0003)
This commit is contained in:
parent
eb9612e4bf
commit
3735145aa5
47 changed files with 3488 additions and 33 deletions
241
defects/gcc/unit/GccGimpleRangePathTest.java
Normal file
241
defects/gcc/unit/GccGimpleRangePathTest.java
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Unit test for gcc-0002: path_range_query::compute_exit_dependencies O(P^2*N) defect.
|
||||
*
|
||||
* Models the pattern in gcc/gimple-range-path.cc:
|
||||
*
|
||||
* while (!worklist.is_empty())
|
||||
* {
|
||||
* name = worklist.pop();
|
||||
* def_bb = def_stmt(name).bb;
|
||||
* if (!m_path.contains(def_bb)) // O(P) linear scan — the defect
|
||||
* continue;
|
||||
* for (phi args e) {
|
||||
* if (m_path.contains(e.src) // O(P) linear scan — the defect
|
||||
* && new_dep(arg))
|
||||
* worklist.push(arg);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* m_path is an auto_vec<basic_block>, .contains() does a linear walk.
|
||||
*
|
||||
* Slow path: List.contains() — O(P) per worklist item.
|
||||
* Fast path: pre-built HashSet from path — O(1) per worklist item.
|
||||
*/
|
||||
public class GccGimpleRangePathTest {
|
||||
|
||||
/**
|
||||
* Simulate compute_exit_dependencies.
|
||||
*
|
||||
* @param pathBBs the set of basic-block IDs on the path (m_path)
|
||||
* @param phiGraph phiGraph[defBB] = list of {argBB, argId} phi arg pairs
|
||||
* @param initDeps initial SSA names in the worklist (imported by exit BB)
|
||||
* @param defBlock defBlock[ssaName] = the BB where it is defined
|
||||
* @param useList list, not set — mirrors auto_vec<basic_block>
|
||||
* @return op count (each contains() call = 1 op + |path| for list)
|
||||
*/
|
||||
static long[] computeDepsOps(
|
||||
List<Integer> pathList, // m_path as list
|
||||
Set<Integer> pathSet, // fast version: null for slow
|
||||
Map<Integer, List<int[]>> phiGraph, // defBB → [[srcBB, argSSA], ...]
|
||||
Set<Integer> initDeps,
|
||||
Map<Integer, Integer> defBlock) {
|
||||
|
||||
Set<Integer> dependencies = new HashSet<>(initDeps);
|
||||
Deque<Integer> worklist = new ArrayDeque<>(initDeps);
|
||||
long ops = 0;
|
||||
|
||||
while (!worklist.isEmpty()) {
|
||||
int name = worklist.pop();
|
||||
Integer defBB = defBlock.get(name);
|
||||
if (defBB == null) continue;
|
||||
|
||||
// contains check — O(P) slow, O(1) fast
|
||||
boolean onPath;
|
||||
if (pathSet != null) {
|
||||
ops++; // O(1)
|
||||
onPath = pathSet.contains(defBB);
|
||||
} else {
|
||||
ops++;
|
||||
int found = 0;
|
||||
for (int bb : pathList) { ops++; if (bb == defBB) { found = 1; break; } }
|
||||
onPath = found == 1;
|
||||
}
|
||||
if (!onPath) continue;
|
||||
|
||||
List<int[]> phiArgs = phiGraph.get(defBB);
|
||||
if (phiArgs == null) continue;
|
||||
for (int[] arg : phiArgs) {
|
||||
int srcBB = arg[0], argSSA = arg[1];
|
||||
// src contains check
|
||||
boolean srcOnPath;
|
||||
if (pathSet != null) {
|
||||
ops++;
|
||||
srcOnPath = pathSet.contains(srcBB);
|
||||
} else {
|
||||
ops++;
|
||||
int found = 0;
|
||||
for (int bb : pathList) { ops++; if (bb == srcBB) { found = 1; break; } }
|
||||
srcOnPath = found == 1;
|
||||
}
|
||||
if (srcOnPath && dependencies.add(argSSA))
|
||||
worklist.push(argSSA);
|
||||
}
|
||||
}
|
||||
return new long[]{ ops, dependencies.size() };
|
||||
}
|
||||
|
||||
static long slowOps(List<Integer> path, Map<Integer,List<int[]>> phi,
|
||||
Set<Integer> initDeps, Map<Integer,Integer> defBlock) {
|
||||
return computeDepsOps(path, null, phi, initDeps, defBlock)[0];
|
||||
}
|
||||
|
||||
static long[] fastResult(List<Integer> path, Map<Integer,List<int[]>> phi,
|
||||
Set<Integer> initDeps, Map<Integer,Integer> defBlock) {
|
||||
Set<Integer> pathSet = new HashSet<>(path);
|
||||
return computeDepsOps(path, pathSet, phi, initDeps, defBlock);
|
||||
}
|
||||
|
||||
static long slowResult(List<Integer> path, Map<Integer,List<int[]>> phi,
|
||||
Set<Integer> initDeps, Map<Integer,Integer> defBlock) {
|
||||
return computeDepsOps(path, null, phi, initDeps, defBlock)[1];
|
||||
}
|
||||
|
||||
// Build a chain: path = [0,1,...,P-1], each BB i defines SSA i,
|
||||
// phi at BB i has one arg from BB i-1 with SSA (i + P).
|
||||
// init deps = {0} (SSA name 0 defined in BB 0 on path)
|
||||
static Object[] buildChain(int P) {
|
||||
List<Integer> path = new ArrayList<>();
|
||||
for (int i = 0; i < P; i++) path.add(i);
|
||||
|
||||
Map<Integer, List<int[]>> phi = new HashMap<>();
|
||||
Map<Integer, Integer> defBlock = new HashMap<>();
|
||||
// SSA name i defined in BB i
|
||||
for (int i = 0; i < P; i++) {
|
||||
defBlock.put(i, i);
|
||||
if (i > 0) {
|
||||
// BB i has a phi with arg from BB (i-1) using SSA (i-1)
|
||||
phi.computeIfAbsent(i, k -> new ArrayList<>())
|
||||
.add(new int[]{ i - 1, i - 1 });
|
||||
}
|
||||
}
|
||||
Set<Integer> initDeps = new HashSet<>();
|
||||
initDeps.add(P - 1); // start from the last SSA name
|
||||
return new Object[]{ path, phi, initDeps, defBlock };
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void main(String[] args) {
|
||||
int pass = 0, total = 0;
|
||||
|
||||
// Test 1: correctness - small path, both paths find same dependencies
|
||||
total++;
|
||||
{
|
||||
Object[] c = buildChain(5);
|
||||
List<Integer> path = (List<Integer>) c[0];
|
||||
Map<Integer,List<int[]>> phi = (Map<Integer,List<int[]>>) c[1];
|
||||
Set<Integer> initDeps = (Set<Integer>) c[2];
|
||||
Map<Integer,Integer> defBlock = (Map<Integer,Integer>) c[3];
|
||||
|
||||
long slowDeps = slowResult(path, phi, initDeps, defBlock);
|
||||
long[] fastR = fastResult(path, phi, initDeps, defBlock);
|
||||
if (slowDeps == fastR[1]) {
|
||||
pass++;
|
||||
System.out.printf("PASS test1: correctness — both find %d dependencies%n", slowDeps);
|
||||
} else {
|
||||
System.out.printf("FAIL test1: slow=%d fast=%d%n", slowDeps, fastR[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 2: op count slow >> fast for large P
|
||||
total++;
|
||||
{
|
||||
int P = 100;
|
||||
Object[] c = buildChain(P);
|
||||
List<Integer> path = (List<Integer>) c[0];
|
||||
Map<Integer,List<int[]>> phi = (Map<Integer,List<int[]>>) c[1];
|
||||
Set<Integer> initDeps = (Set<Integer>) c[2];
|
||||
Map<Integer,Integer> defBlock = (Map<Integer,Integer>) c[3];
|
||||
|
||||
long slow = slowOps(path, phi, initDeps, defBlock);
|
||||
long fast = fastResult(path, phi, initDeps, defBlock)[0];
|
||||
boolean slowBig = slow > P * 2;
|
||||
boolean fastSmall = fast < slow / 2;
|
||||
if (slowBig && fastSmall) {
|
||||
pass++;
|
||||
System.out.printf("PASS test2: P=%d slow=%d ops fast=%d ops%n", P, slow, fast);
|
||||
} else {
|
||||
System.out.printf("FAIL test2: P=%d slow=%d fast=%d (expected slow>>fast)%n",
|
||||
P, slow, fast);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 3: speedup >= 5x at P=50
|
||||
total++;
|
||||
{
|
||||
int P = 50;
|
||||
Object[] c = buildChain(P);
|
||||
List<Integer> path = (List<Integer>) c[0];
|
||||
Map<Integer,List<int[]>> phi = (Map<Integer,List<int[]>>) c[1];
|
||||
Set<Integer> initDeps = (Set<Integer>) c[2];
|
||||
Map<Integer,Integer> defBlock = (Map<Integer,Integer>) c[3];
|
||||
|
||||
long slow = slowOps(path, phi, initDeps, defBlock);
|
||||
long fast = fastResult(path, phi, initDeps, defBlock)[0];
|
||||
long ratio = slow / Math.max(fast, 1);
|
||||
if (ratio >= 5) {
|
||||
pass++;
|
||||
System.out.printf("PASS test3: speedup %dx at P=%d%n", ratio, P);
|
||||
} else {
|
||||
System.out.printf("FAIL test3: speedup only %dx at P=%d (slow=%d fast=%d)%n",
|
||||
ratio, P, slow, fast);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 4: empty path — no dependencies found
|
||||
total++;
|
||||
{
|
||||
List<Integer> path = new ArrayList<>();
|
||||
Map<Integer,List<int[]>> phi = new HashMap<>();
|
||||
Set<Integer> initDeps = new HashSet<>(Arrays.asList(0, 1, 2));
|
||||
Map<Integer,Integer> defBlock = new HashMap<>();
|
||||
defBlock.put(0, 99); defBlock.put(1, 98); defBlock.put(2, 97);
|
||||
|
||||
long slowDeps = slowResult(path, phi, initDeps, defBlock);
|
||||
long[] fastR = fastResult(path, phi, initDeps, defBlock);
|
||||
// none should be found (none of defBlocks are on path)
|
||||
if (slowDeps == fastR[1]) {
|
||||
pass++;
|
||||
System.out.printf("PASS test4: empty path — both find 0 deps on path (slow=%d fast=%d)%n",
|
||||
slowDeps, fastR[1]);
|
||||
} else {
|
||||
System.out.printf("FAIL test4: slow=%d fast=%d%n", slowDeps, fastR[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 5: single BB path
|
||||
total++;
|
||||
{
|
||||
List<Integer> path = new ArrayList<>(Collections.singletonList(0));
|
||||
Map<Integer,List<int[]>> phi = new HashMap<>();
|
||||
Set<Integer> initDeps = new HashSet<>(Collections.singletonList(0));
|
||||
Map<Integer,Integer> defBlock = new HashMap<>();
|
||||
defBlock.put(0, 0);
|
||||
|
||||
long slowDeps = slowResult(path, phi, initDeps, defBlock);
|
||||
long[] fastR = fastResult(path, phi, initDeps, defBlock);
|
||||
if (slowDeps == fastR[1]) {
|
||||
pass++;
|
||||
System.out.printf("PASS test5: single BB — both find %d deps%n", slowDeps);
|
||||
} else {
|
||||
System.out.printf("FAIL test5: slow=%d fast=%d%n", slowDeps, fastR[1]);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.printf("%n%d/%d PASS%n", pass, total);
|
||||
if (pass != total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue