package unit; import java.util.*; /** * Unit test for llvm-0005: AssumptionCache::transferAffectedValuesInCache O(N*M) defect. * * Models the pattern: * for (auto &A : src_list) // O(N) iterations * if (!is_contained(dst_list, A)) // O(M) linear scan — the defect * dst_list.push_back(A); * * Slow path: List.contains() — O(N*M) total * Fast path: pre-built HashSet from dst — O(N+M) total */ public class LlvmAssumptionCacheTransferTest { // Simulate a ResultElem: just an integer assume-id // is_contained checks by value equality static long slowTransfer(List dst, List src) { long ops = 0; for (int a : src) { // O(N) ops++; boolean found = false; for (int d : dst) { // O(M) linear scan ops++; if (d == a) { found = true; break; } } if (!found) dst.add(a); } return ops; } static long fastTransfer(List dst, List src) { long ops = 0; // Build set from dst once: O(M) Set dstSet = new HashSet<>(dst); ops += dst.size(); // building the set for (int a : src) { // O(N) ops++; if (dstSet.add(a)) { // O(1) dst.add(a); } } return ops; } static boolean correctnessCheck(List dstInit, List src) { // slow List slowDst = new ArrayList<>(dstInit); slowTransfer(slowDst, src); // fast List fastDst = new ArrayList<>(dstInit); fastTransfer(fastDst, src); return new HashSet<>(slowDst).equals(new HashSet<>(fastDst)); } static List makeList(int from, int to) { List l = new ArrayList<>(); for (int i = from; i < to; i++) l.add(i); return l; } public static void main(String[] args) { int pass = 0, total = 0; // Test 1: no overlap total++; if (correctnessCheck(makeList(0, 5), makeList(5, 10))) { pass++; System.out.println("PASS test1: no overlap"); } else System.out.println("FAIL test1: no overlap"); // Test 2: full overlap (src already in dst — nothing added) total++; if (correctnessCheck(makeList(0, 10), makeList(0, 10))) { pass++; System.out.println("PASS test2: full overlap"); } else System.out.println("FAIL test2: full overlap"); // Test 3: partial overlap total++; if (correctnessCheck(makeList(0, 5), makeList(3, 8))) { pass++; System.out.println("PASS test3: partial overlap"); } else System.out.println("FAIL test3: partial overlap"); // Test 4: op count shows O(N*M) vs O(N+M) total++; int N = 200, M = 200; List dst = makeList(0, M); List src = makeList(M / 2, M / 2 + N); // half overlap List dstForSlow = new ArrayList<>(dst); List dstForFast = new ArrayList<>(dst); long slowOps = slowTransfer(dstForSlow, src); long fastOps = fastTransfer(dstForFast, src); // slow should be roughly N*M/2 (each src item scans half of dst on average) boolean slowIsQuadratic = slowOps > (long) N * M / 4; boolean fastIsLinear = fastOps <= N + M + 10; if (slowIsQuadratic && fastIsLinear) { pass++; System.out.printf("PASS test4: op count slow=%d O(N*M) fast=%d O(N+M) N=%d M=%d%n", slowOps, fastOps, N, M); } else { System.out.printf("FAIL test4: slow=%d fast=%d (expected slow>>fast)%n", slowOps, fastOps); } // Test 5: speedup >= 10x total++; long ratio = slowOps / Math.max(fastOps, 1); if (ratio >= 10) { pass++; System.out.printf("PASS test5: speedup %dx (slow=%d fast=%d)%n", ratio, slowOps, fastOps); } else { System.out.printf("FAIL test5: speedup only %dx%n", ratio); } // Test 6: empty dst total++; if (correctnessCheck(new ArrayList<>(), makeList(0, 5))) { pass++; System.out.println("PASS test6: empty dst"); } else System.out.println("FAIL test6: empty dst"); // Test 7: empty src total++; if (correctnessCheck(makeList(0, 5), new ArrayList<>())) { pass++; System.out.println("PASS test7: empty src"); } else System.out.println("FAIL test7: empty src"); System.out.printf("%n%d/%d PASS%n", pass, total); if (pass != total) System.exit(1); } }