[IRMemoryMap] Test interleaved Mallocs and Frees

This adds a new command to the ir-memory-map tester:

  free <allocation-index>

The argument to free is an index which identifies which live allocation
to free. Index 0 identifies the first live allocation in the address
space, index 1 identifies the second, etc. where the allocations are
sorted in increasing order.

For illustrative purposes, assume malloc returns monotonically
increasing addresses. Here are some examples of how free would work:

Example 1
---------

malloc 16 1
malloc 32 1
free 1      //< Free the 32-byte allocation.
free 0      //< Next, free the 16-byte allocation.

Example 2
---------

malloc 16 1
malloc 32 1
free 0      //< Free the 16-byte allocation.
free 0      //< Next, free the 32-byte allocation.

llvm-svn: 333700
diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp
index 01ac977..8fc5a34 100644
--- a/lldb/tools/lldb-test/lldb-test.cpp
+++ b/lldb/tools/lldb-test/lldb-test.cpp
@@ -169,9 +169,11 @@
 using AllocationT = std::pair<addr_t, addr_t>;
 bool areAllocationsOverlapping(const AllocationT &L, const AllocationT &R);
 using AddrIntervalMap =
-      IntervalMap<addr_t, bool, 8, IntervalMapHalfOpenInfo<addr_t>>;
+      IntervalMap<addr_t, unsigned, 8, IntervalMapHalfOpenInfo<addr_t>>;
 bool evalMalloc(IRMemoryMap &IRMemMap, StringRef Line,
                 AddrIntervalMap &AllocatedIntervals);
+bool evalFree(IRMemoryMap &IRMemMap, StringRef Line,
+              AddrIntervalMap &AllocatedIntervals);
 int evaluateMemoryMapCommands(Debugger &Dbg);
 } // namespace irmemorymap
 
@@ -569,9 +571,45 @@
     ++Probe;
   }
 
-  // Insert the new allocation into the interval map.
+  // Insert the new allocation into the interval map. Use unique allocation IDs
+  // to inhibit interval coalescing.
+  static unsigned AllocationID = 0;
   if (Size)
-    AllocatedIntervals.insert(Addr, EndOfRegion, true);
+    AllocatedIntervals.insert(Addr, EndOfRegion, AllocationID++);
+
+  return true;
+}
+
+bool opts::irmemorymap::evalFree(IRMemoryMap &IRMemMap, StringRef Line,
+                                 AddrIntervalMap &AllocatedIntervals) {
+  // ::= free <allocation-index>
+  size_t AllocIndex;
+  int Matches = sscanf(Line.data(), "free %zu", &AllocIndex);
+  if (Matches != 1)
+    return false;
+
+  outs() << formatv("Command: free(allocation-index={0})\n", AllocIndex);
+
+  // Find and free the AllocIndex-th allocation.
+  auto Probe = AllocatedIntervals.begin();
+  for (size_t I = 0; I < AllocIndex && Probe != AllocatedIntervals.end(); ++I)
+    ++Probe;
+
+  if (Probe == AllocatedIntervals.end()) {
+    outs() << "Free error: Invalid allocation index\n";
+    exit(1);
+  }
+
+  Status ST;
+  IRMemMap.Free(Probe.start(), ST);
+  if (ST.Fail()) {
+    outs() << formatv("Free error: {0}\n", ST);
+    exit(1);
+  }
+
+  // Erase the allocation from the live interval map.
+  outs() << formatv("Free: [{0:x}, {1:x})\n", Probe.start(), Probe.stop());
+  Probe.erase();
 
   return true;
 }
@@ -618,6 +656,9 @@
     if (evalMalloc(IRMemMap, Line, AllocatedIntervals))
       continue;
 
+    if (evalFree(IRMemMap, Line, AllocatedIntervals))
+      continue;
+
     errs() << "Could not parse line: " << Line << "\n";
     exit(1);
   }