[llvm] ab49dce - [DebugInfo][InstrRef][NFC] Use unique_ptr instead of raw pointers

Jeremy Morse via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 1 04:50:06 PST 2022


Author: Jeremy Morse
Date: 2022-03-01T12:49:50Z
New Revision: ab49dce01f211fd80f76f449035d771f5e2720b9

URL: https://github.com/llvm/llvm-project/commit/ab49dce01f211fd80f76f449035d771f5e2720b9
DIFF: https://github.com/llvm/llvm-project/commit/ab49dce01f211fd80f76f449035d771f5e2720b9.diff

LOG: [DebugInfo][InstrRef][NFC] Use unique_ptr instead of raw pointers

InstrRefBasedLDV allocates some big tables of ValueIDNum, to store live-in
and live-out block values in, that then get passed around as pointers
everywhere. This patch wraps the allocation in a std::unique_ptr, names
some types based on unique_ptr, and passes references to those around
instead. There's no functional change, but it makes it clearer to the
reader that references to these tables are borrowed rather than owned, and
we get some extra validity assertions too.

Differential Revision: https://reviews.llvm.org/D118774

Added: 
    

Modified: 
    llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
    llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
    llvm/unittests/CodeGen/InstrRefLDVTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index 4c2484f9d98f1..b4c0297fcd5fa 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -266,7 +266,7 @@ class TransferTracker {
   /// object fields to track variable locations as we step through the block.
   /// FIXME: could just examine mloctracker instead of passing in \p mlocs?
   void
-  loadInlocs(MachineBasicBlock &MBB, ValueIDNum *MLocs,
+  loadInlocs(MachineBasicBlock &MBB, ValueTable &MLocs,
              const SmallVectorImpl<std::pair<DebugVariable, DbgValue>> &VLocs,
              unsigned NumLocs) {
     ActiveMLocs.clear();
@@ -1022,8 +1022,8 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
 }
 
 bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
-                                             ValueIDNum **MLiveOuts,
-                                             ValueIDNum **MLiveIns) {
+                                             const ValueTable *MLiveOuts,
+                                             const ValueTable *MLiveIns) {
   if (!MI.isDebugRef())
     return false;
 
@@ -1782,8 +1782,8 @@ void InstrRefBasedLDV::accumulateFragmentMap(MachineInstr &MI) {
   AllSeenFragments.insert(ThisFragment);
 }
 
-void InstrRefBasedLDV::process(MachineInstr &MI, ValueIDNum **MLiveOuts,
-                               ValueIDNum **MLiveIns) {
+void InstrRefBasedLDV::process(MachineInstr &MI, const ValueTable *MLiveOuts,
+                               const ValueTable *MLiveIns) {
   // Try to interpret an MI as a debug or transfer instruction. Only if it's
   // none of these should we interpret it's register defs as new value
   // definitions.
@@ -1833,7 +1833,10 @@ void InstrRefBasedLDV::produceMLocTransferFunction(
 
     // Step through each instruction in this block.
     for (auto &MI : MBB) {
-      process(MI);
+      // Pass in an empty unique_ptr for the value tables when accumulating the
+      // machine transfer function.
+      process(MI, nullptr, nullptr);
+
       // Also accumulate fragment map.
       if (MI.isDebugValue() || MI.isDebugRef())
         accumulateFragmentMap(MI);
@@ -1922,7 +1925,7 @@ void InstrRefBasedLDV::produceMLocTransferFunction(
 
 bool InstrRefBasedLDV::mlocJoin(
     MachineBasicBlock &MBB, SmallPtrSet<const MachineBasicBlock *, 16> &Visited,
-    ValueIDNum **OutLocs, ValueIDNum *InLocs) {
+    FuncValueTable &OutLocs, ValueTable &InLocs) {
   LLVM_DEBUG(dbgs() << "join MBB: " << MBB.getNumber() << "\n");
   bool Changed = false;
 
@@ -2023,7 +2026,7 @@ void InstrRefBasedLDV::findStackIndexInterference(
 
 void InstrRefBasedLDV::placeMLocPHIs(
     MachineFunction &MF, SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
-    ValueIDNum **MInLocs, SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
+    FuncValueTable &MInLocs, SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
   SmallVector<unsigned, 4> StackUnits;
   findStackIndexInterference(StackUnits);
 
@@ -2152,7 +2155,7 @@ void InstrRefBasedLDV::placeMLocPHIs(
 }
 
 void InstrRefBasedLDV::buildMLocValueMap(
-    MachineFunction &MF, ValueIDNum **MInLocs, ValueIDNum **MOutLocs,
+    MachineFunction &MF, FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
     SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
   std::priority_queue<unsigned int, std::vector<unsigned int>,
                       std::greater<unsigned int>>
@@ -2294,7 +2297,7 @@ void InstrRefBasedLDV::BlockPHIPlacement(
 
 Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc(
     const MachineBasicBlock &MBB, const DebugVariable &Var,
-    const LiveIdxT &LiveOuts, ValueIDNum **MOutLocs,
+    const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
     const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
   // Collect a set of locations from predecessor where its live-out value can
   // be found.
@@ -2562,7 +2565,7 @@ void InstrRefBasedLDV::getBlocksForScope(
 void InstrRefBasedLDV::buildVLocValueMap(
     const DILocation *DILoc, const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
     SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks, LiveInsT &Output,
-    ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
+    FuncValueTable &MOutLocs, FuncValueTable &MInLocs,
     SmallVectorImpl<VLocTracker> &AllTheVLocs) {
   // This method is much like buildMLocValueMap: but focuses on a single
   // LexicalScope at a time. Pick out a set of blocks and variables that are
@@ -2947,7 +2950,7 @@ void InstrRefBasedLDV::makeDepthFirstEjectionMap(
 bool InstrRefBasedLDV::depthFirstVLocAndEmit(
     unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation,
     const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToAssignBlocks,
-    LiveInsT &Output, ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
+    LiveInsT &Output, FuncValueTable &MOutLocs, FuncValueTable &MInLocs,
     SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF,
     DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
     const TargetPassConfig &TPC) {
@@ -2956,15 +2959,8 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
   VTracker = nullptr;
 
   // No scopes? No variable locations.
-  if (!LS.getCurrentFunctionScope()) {
-    // FIXME: this is a sticking plaster to prevent a memory leak, these
-    // pointers will be automagically freed by being unique pointers, shortly.
-    for (unsigned int I = 0; I < MaxNumBlocks; ++I) {
-      delete[] MInLocs[I];
-      delete[] MOutLocs[I];
-    }
+  if (!LS.getCurrentFunctionScope())
     return false;
-  }
 
   // Build map from block number to the last scope that uses the block.
   SmallVector<unsigned, 16> EjectionMap;
@@ -2988,17 +2984,14 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
     CurBB = BBNum;
     CurInst = 1;
     for (auto &MI : MBB) {
-      process(MI, MOutLocs, MInLocs);
+      process(MI, MOutLocs.get(), MInLocs.get());
       TTracker->checkInstForNewValues(CurInst, MI.getIterator());
       ++CurInst;
     }
 
     // Free machine-location tables for this block.
-    delete[] MInLocs[BBNum];
-    delete[] MOutLocs[BBNum];
-    // Make ourselves brittle to use-after-free errors.
-    MInLocs[BBNum] = nullptr;
-    MOutLocs[BBNum] = nullptr;
+    MInLocs[BBNum].reset();
+    MOutLocs[BBNum].reset();
     // We don't need live-in variable values for this block either.
     Output[BBNum].clear();
     AllTheVLocs[BBNum].clear();
@@ -3066,16 +3059,6 @@ bool InstrRefBasedLDV::depthFirstVLocAndEmit(
     if (MOutLocs[MBB->getNumber()])
       EjectBlock(*MBB);
 
-  // Finally, there might have been gaps in the block numbering, from dead
-  // blocks being deleted or folded. In those scenarios, we might allocate a
-  // block-table that's never ejected, meaning we have to free it at the end.
-  for (unsigned int I = 0; I < MaxNumBlocks; ++I) {
-    if (MInLocs[I]) {
-      delete[] MInLocs[I];
-      delete[] MOutLocs[I];
-    }
-  }
-
   return emitTransfers(AllVarsNumbering);
 }
 
@@ -3173,13 +3156,13 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
   // Allocate and initialize two array-of-arrays for the live-in and live-out
   // machine values. The outer dimension is the block number; while the inner
   // dimension is a LocIdx from MLocTracker.
-  ValueIDNum **MOutLocs = new ValueIDNum *[MaxNumBlocks];
-  ValueIDNum **MInLocs = new ValueIDNum *[MaxNumBlocks];
+  FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(MaxNumBlocks);
+  FuncValueTable MInLocs = std::make_unique<ValueTable[]>(MaxNumBlocks);
   unsigned NumLocs = MTracker->getNumLocs();
   for (int i = 0; i < MaxNumBlocks; ++i) {
     // These all auto-initialize to ValueIDNum::EmptyValue
-    MOutLocs[i] = new ValueIDNum[NumLocs];
-    MInLocs[i] = new ValueIDNum[NumLocs];
+    MOutLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs);
+    MInLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs);
   }
 
   // Solve the machine value dataflow problem using the MLocTransfer function,
@@ -3216,7 +3199,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
     MTracker->loadFromArray(MInLocs[CurBB], CurBB);
     CurInst = 1;
     for (auto &MI : MBB) {
-      process(MI, MOutLocs, MInLocs);
+      process(MI, MOutLocs.get(), MInLocs.get());
       ++CurInst;
     }
     MTracker->reset();
@@ -3271,12 +3254,6 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
                       << " has " << MaxNumBlocks << " basic blocks and "
                       << VarAssignCount
                       << " variable assignments, exceeding limits.\n");
-
-    // Perform memory cleanup that emitLocations would do otherwise.
-    for (int Idx = 0; Idx < MaxNumBlocks; ++Idx) {
-      delete[] MOutLocs[Idx];
-      delete[] MInLocs[Idx];
-    }
   } else {
     // Optionally, solve the variable value problem and emit to blocks by using
     // a lexical-scope-depth search. It should be functionally identical to
@@ -3286,10 +3263,6 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF,
         SavedLiveIns, MOutLocs, MInLocs, vlocs, MF, AllVarsNumbering, *TPC);
   }
 
-  // Elements of these arrays will be deleted by emitLocations.
-  delete[] MOutLocs;
-  delete[] MInLocs;
-
   delete MTracker;
   delete TTracker;
   MTracker = nullptr;
@@ -3406,9 +3379,10 @@ class LDVSSAUpdater {
   /// Machine location where any PHI must occur.
   LocIdx Loc;
   /// Table of live-in machine value numbers for blocks / locations.
-  ValueIDNum **MLiveIns;
+  const ValueTable *MLiveIns;
 
-  LDVSSAUpdater(LocIdx L, ValueIDNum **MLiveIns) : Loc(L), MLiveIns(MLiveIns) {}
+  LDVSSAUpdater(LocIdx L, const ValueTable *MLiveIns)
+      : Loc(L), MLiveIns(MLiveIns) {}
 
   void reset() {
     for (auto &Block : BlockMap)
@@ -3565,11 +3539,13 @@ template <> class SSAUpdaterTraits<LDVSSAUpdater> {
 
 } // end namespace llvm
 
-Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF,
-                                                      ValueIDNum **MLiveOuts,
-                                                      ValueIDNum **MLiveIns,
-                                                      MachineInstr &Here,
-                                                      uint64_t InstrNum) {
+Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(
+    MachineFunction &MF, const ValueTable *MLiveOuts,
+    const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
+  assert(MLiveOuts && MLiveIns &&
+         "Tried to resolve DBG_PHI before location "
+         "tables allocated?");
+
   // This function will be called twice per DBG_INSTR_REF, and might end up
   // computing lots of SSA information: memoize it.
   auto SeenDbgPHIIt = SeenDbgPHIs.find(&Here);
@@ -3583,8 +3559,8 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF,
 }
 
 Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIsImpl(
-    MachineFunction &MF, ValueIDNum **MLiveOuts, ValueIDNum **MLiveIns,
-    MachineInstr &Here, uint64_t InstrNum) {
+    MachineFunction &MF, const ValueTable *MLiveOuts,
+    const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) {
   // Pick out records of DBG_PHI instructions that have been observed. If there
   // are none, then we cannot compute a value number.
   auto RangePair = std::equal_range(DebugPHINumToValue.begin(),
@@ -3691,7 +3667,7 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIsImpl(
         return None;
 
       ValueIDNum ValueToCheck;
-      ValueIDNum *BlockLiveOuts = MLiveOuts[PHIIt.first->BB.getNumber()];
+      const ValueTable &BlockLiveOuts = MLiveOuts[PHIIt.first->BB.getNumber()];
 
       auto VVal = ValidatedValues.find(PHIIt.first);
       if (VVal == ValidatedValues.end()) {

diff  --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
index 1ddcb488feae2..4bb0d42bcf0da 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
@@ -171,6 +171,13 @@ class ValueIDNum {
   static ValueIDNum TombstoneValue;
 };
 
+/// Type for a table of values in a block.
+using ValueTable = std::unique_ptr<ValueIDNum[]>;
+
+/// Type for a table-of-table-of-values, i.e., the collection of either
+/// live-in or live-out values for each block in the function.
+using FuncValueTable = std::unique_ptr<ValueTable[]>;
+
 /// Thin wrapper around an integer -- designed to give more type safety to
 /// spill location numbers.
 class SpillLocationNo {
@@ -507,7 +514,7 @@ class MLocTracker {
 
   /// Load values for each location from array of ValueIDNums. Take current
   /// bbnum just in case we read a value from a hitherto untouched register.
-  void loadFromArray(ValueIDNum *Locs, unsigned NewCurBB) {
+  void loadFromArray(ValueTable &Locs, unsigned NewCurBB) {
     CurBB = NewCurBB;
     // Iterate over all tracked locations, and load each locations live-in
     // value into our local index.
@@ -915,8 +922,8 @@ class InstrRefBasedLDV : public LDVImpl {
   extractSpillBaseRegAndOffset(const MachineInstr &MI);
 
   /// Observe a single instruction while stepping through a block.
-  void process(MachineInstr &MI, ValueIDNum **MLiveOuts = nullptr,
-               ValueIDNum **MLiveIns = nullptr);
+  void process(MachineInstr &MI, const ValueTable *MLiveOuts,
+               const ValueTable *MLiveIns);
 
   /// Examines whether \p MI is a DBG_VALUE and notifies trackers.
   /// \returns true if MI was recognized and processed.
@@ -924,8 +931,8 @@ class InstrRefBasedLDV : public LDVImpl {
 
   /// Examines whether \p MI is a DBG_INSTR_REF and notifies trackers.
   /// \returns true if MI was recognized and processed.
-  bool transferDebugInstrRef(MachineInstr &MI, ValueIDNum **MLiveOuts,
-                             ValueIDNum **MLiveIns);
+  bool transferDebugInstrRef(MachineInstr &MI, const ValueTable *MLiveOuts,
+                             const ValueTable *MLiveIns);
 
   /// Stores value-information about where this PHI occurred, and what
   /// instruction number is associated with it.
@@ -957,13 +964,13 @@ class InstrRefBasedLDV : public LDVImpl {
   /// \p InstrNum Debug instruction number defined by DBG_PHI instructions.
   /// \returns The machine value number at position Here, or None.
   Optional<ValueIDNum> resolveDbgPHIs(MachineFunction &MF,
-                                      ValueIDNum **MLiveOuts,
-                                      ValueIDNum **MLiveIns, MachineInstr &Here,
-                                      uint64_t InstrNum);
+                                      const ValueTable *MLiveOuts,
+                                      const ValueTable *MLiveIns,
+                                      MachineInstr &Here, uint64_t InstrNum);
 
   Optional<ValueIDNum> resolveDbgPHIsImpl(MachineFunction &MF,
-                                          ValueIDNum **MLiveOuts,
-                                          ValueIDNum **MLiveIns,
+                                          const ValueTable *MLiveOuts,
+                                          const ValueTable *MLiveIns,
                                           MachineInstr &Here,
                                           uint64_t InstrNum);
 
@@ -981,8 +988,8 @@ class InstrRefBasedLDV : public LDVImpl {
   /// live-out arrays to the (initialized to zero) multidimensional arrays in
   /// \p MInLocs and \p MOutLocs. The outer dimension is indexed by block
   /// number, the inner by LocIdx.
-  void buildMLocValueMap(MachineFunction &MF, ValueIDNum **MInLocs,
-                         ValueIDNum **MOutLocs,
+  void buildMLocValueMap(MachineFunction &MF, FuncValueTable &MInLocs,
+                         FuncValueTable &MOutLocs,
                          SmallVectorImpl<MLocTransferMap> &MLocTransfer);
 
   /// Examine the stack indexes (i.e. offsets within the stack) to find the
@@ -993,7 +1000,7 @@ class InstrRefBasedLDV : public LDVImpl {
   /// the IDF of each register.
   void placeMLocPHIs(MachineFunction &MF,
                      SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
-                     ValueIDNum **MInLocs,
+                     FuncValueTable &MInLocs,
                      SmallVectorImpl<MLocTransferMap> &MLocTransfer);
 
   /// Propagate variable values to blocks in the common case where there's
@@ -1024,7 +1031,7 @@ class InstrRefBasedLDV : public LDVImpl {
   /// is true, revisiting this block is necessary.
   bool mlocJoin(MachineBasicBlock &MBB,
                 SmallPtrSet<const MachineBasicBlock *, 16> &Visited,
-                ValueIDNum **OutLocs, ValueIDNum *InLocs);
+                FuncValueTable &OutLocs, ValueTable &InLocs);
 
   /// Produce a set of blocks that are in the current lexical scope. This means
   /// those blocks that contain instructions "in" the scope, blocks where
@@ -1052,11 +1059,11 @@ class InstrRefBasedLDV : public LDVImpl {
   /// scope, but which do contain DBG_VALUEs, which VarLocBasedImpl tracks
   /// locations through.
   void buildVLocValueMap(const DILocation *DILoc,
-                    const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
-                    SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
-                    LiveInsT &Output, ValueIDNum **MOutLocs,
-                    ValueIDNum **MInLocs,
-                    SmallVectorImpl<VLocTracker> &AllTheVLocs);
+                         const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
+                         SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
+                         LiveInsT &Output, FuncValueTable &MOutLocs,
+                         FuncValueTable &MInLocs,
+                         SmallVectorImpl<VLocTracker> &AllTheVLocs);
 
   /// Attempt to eliminate un-necessary PHIs on entry to a block. Examines the
   /// live-in values coming from predecessors live-outs, and replaces any PHIs
@@ -1074,7 +1081,7 @@ class InstrRefBasedLDV : public LDVImpl {
   /// \returns Value ID of a machine PHI if an appropriate one is available.
   Optional<ValueIDNum>
   pickVPHILoc(const MachineBasicBlock &MBB, const DebugVariable &Var,
-              const LiveIdxT &LiveOuts, ValueIDNum **MOutLocs,
+              const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
               const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders);
 
   /// Take collections of DBG_VALUE instructions stored in TTracker, and
@@ -1104,7 +1111,7 @@ class InstrRefBasedLDV : public LDVImpl {
   bool depthFirstVLocAndEmit(
       unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation,
       const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToBlocks,
-      LiveInsT &Output, ValueIDNum **MOutLocs, ValueIDNum **MInLocs,
+      LiveInsT &Output, FuncValueTable &MOutLocs, FuncValueTable &MInLocs,
       SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF,
       DenseMap<DebugVariable, unsigned> &AllVarsNumbering,
       const TargetPassConfig &TPC);

diff  --git a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
index 9b7683108d777..88585b58de11f 100644
--- a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
+++ b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
@@ -175,21 +175,21 @@ class InstrRefLDVTest : public testing::Test {
   }
 
   // Some routines for bouncing into LDV,
-  void buildMLocValueMap(ValueIDNum **MInLocs, ValueIDNum **MOutLocs,
+  void buildMLocValueMap(FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
                          SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
     LDV->buildMLocValueMap(*MF, MInLocs, MOutLocs, MLocTransfer);
   }
 
   void placeMLocPHIs(MachineFunction &MF,
                      SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
-                     ValueIDNum **MInLocs,
+                     FuncValueTable &MInLocs,
                      SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
     LDV->placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
   }
 
   Optional<ValueIDNum>
   pickVPHILoc(const MachineBasicBlock &MBB, const DebugVariable &Var,
-              const InstrRefBasedLDV::LiveIdxT &LiveOuts, ValueIDNum **MOutLocs,
+              const InstrRefBasedLDV::LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
               const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
     return LDV->pickVPHILoc(MBB, Var, LiveOuts, MOutLocs, BlockOrders);
   }
@@ -203,14 +203,14 @@ class InstrRefLDVTest : public testing::Test {
   void buildVLocValueMap(const DILocation *DILoc,
                     const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
                     SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
-                    InstrRefBasedLDV::LiveInsT &Output, ValueIDNum **MOutLocs,
-                    ValueIDNum **MInLocs,
+                    InstrRefBasedLDV::LiveInsT &Output, FuncValueTable &MOutLocs,
+                    FuncValueTable &MInLocs,
                     SmallVectorImpl<VLocTracker> &AllTheVLocs) {
     LDV->buildVLocValueMap(DILoc, VarsWeCareAbout, AssignBlocks, Output,
                            MOutLocs, MInLocs, AllTheVLocs);
   }
 
-  void initValueArray(ValueIDNum **Nums, unsigned Blks, unsigned Locs) {
+  void initValueArray(FuncValueTable &Nums, unsigned Blks, unsigned Locs) {
     for (unsigned int I = 0; I < Blks; ++I)
       for (unsigned int J = 0; J < Locs; ++J)
         Nums[I][J] = ValueIDNum::EmptyValue;
@@ -481,6 +481,19 @@ body:  |
                               unsigned MaxNumBlocks) {
     LDV->produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks);
   }
+
+  std::pair<FuncValueTable, FuncValueTable>
+  allocValueTables(unsigned Blocks, unsigned Locs) {
+    FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(Blocks);
+    FuncValueTable MInLocs = std::make_unique<ValueTable[]>(Blocks);
+
+    for (unsigned int I = 0; I < Blocks; ++I) {
+      MOutLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
+      MInLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
+    }
+
+    return std::make_pair(std::move(MOutLocs), std::move(MInLocs));
+  }
 };
 
 TEST_F(InstrRefLDVTest, MTransferDefs) {
@@ -898,41 +911,40 @@ TEST_F(InstrRefLDVTest, MLocSingleBlock) {
 
   // Set up live-in and live-out tables for this function: two locations (we
   // add one later) in a single block.
-  ValueIDNum InLocs[2], OutLocs[2];
-  ValueIDNum *InLocsPtr[1] = {&InLocs[0]};
-  ValueIDNum *OutLocsPtr[1] = {&OutLocs[0]};
+  FuncValueTable MOutLocs, MInLocs;
+  std::tie(MOutLocs, MInLocs) = allocValueTables(1, 2);
 
   // Transfer function: nothing.
   SmallVector<MLocTransferMap, 1> TransferFunc;
   TransferFunc.resize(1);
 
   // Try and build value maps...
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
 
   // The result should be that RSP is marked as a live-in-PHI -- this represents
   // an argument. And as there's no transfer function, the block live-out should
   // be the same.
-  EXPECT_EQ(InLocs[0], ValueIDNum(0, 0, RspLoc));
-  EXPECT_EQ(OutLocs[0], ValueIDNum(0, 0, RspLoc));
+  EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
+  EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
 
   // Try again, this time initialising the in-locs to be defined by an
   // instruction. The entry block should always be re-assigned to be the
   // arguments.
-  initValueArray(InLocsPtr, 1, 2);
-  initValueArray(OutLocsPtr, 1, 2);
-  InLocs[0] = ValueIDNum(0, 1, RspLoc);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0], ValueIDNum(0, 0, RspLoc));
-  EXPECT_EQ(OutLocs[0], ValueIDNum(0, 0, RspLoc));
+  initValueArray(MInLocs, 1, 2);
+  initValueArray(MOutLocs, 1, 2);
+  MInLocs[0][0] = ValueIDNum(0, 1, RspLoc);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
+  EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
 
   // Now insert something into the transfer function to assign to the single
   // machine location.
   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
-  initValueArray(InLocsPtr, 1, 2);
-  initValueArray(OutLocsPtr, 1, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0], ValueIDNum(0, 0, RspLoc));
-  EXPECT_EQ(OutLocs[0], ValueIDNum(0, 1, RspLoc));
+  initValueArray(MInLocs, 1, 2);
+  initValueArray(MOutLocs, 1, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
+  EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
   TransferFunc[0].clear();
 
   // Add a new register to be tracked, and insert it into the transfer function
@@ -941,13 +953,13 @@ TEST_F(InstrRefLDVTest, MLocSingleBlock) {
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
   TransferFunc[0].insert({RaxLoc, ValueIDNum(0, 0, RspLoc)});
-  initValueArray(InLocsPtr, 1, 2);
-  initValueArray(OutLocsPtr, 1, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0], ValueIDNum(0, 0, RspLoc));
-  EXPECT_EQ(InLocs[1], ValueIDNum(0, 0, RaxLoc));
-  EXPECT_EQ(OutLocs[0], ValueIDNum(0, 1, RspLoc));
-  EXPECT_EQ(OutLocs[1], ValueIDNum(0, 0, RspLoc)); // Rax contains RspLoc.
+  initValueArray(MInLocs, 1, 2);
+  initValueArray(MOutLocs, 1, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
+  EXPECT_EQ(MInLocs[0][1], ValueIDNum(0, 0, RaxLoc));
+  EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
+  EXPECT_EQ(MOutLocs[0][1], ValueIDNum(0, 0, RspLoc)); // Rax contains RspLoc.
   TransferFunc[0].clear();
 }
 
@@ -965,9 +977,8 @@ TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum InLocs[4][2], OutLocs[4][2];
-  ValueIDNum *InLocsPtr[4] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3]};
-  ValueIDNum *OutLocsPtr[4] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
 
   // Transfer function: start with nothing.
   SmallVector<MLocTransferMap, 1> TransferFunc;
@@ -987,52 +998,52 @@ TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
   // With no transfer function, the live-in values to the entry block should
   // propagate to all live-outs and the live-ins to the two successor blocks.
   // IN ADDITION: this checks that the exit block doesn't get a PHI put in it.
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
   // (Skipped writing out locations for $rax).
 
   // Check that a def of $rsp in the entry block will likewise reach all the
   // successors.
   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[0][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk0);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk0);
   TransferFunc[0].clear();
 
   // Def in one branch of the diamond means that we need a PHI in the ret block
   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
   // This value map: like above, where RspDefInBlk0 is propagated through one
   // branch of the diamond, but is def'ed in the live-outs of the other. The
   // ret / merging block should have a PHI in its live-ins.
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[0][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
 
@@ -1041,17 +1052,17 @@ TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[0][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspPHIInBlk3);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
   TransferFunc[2].clear();
@@ -1065,17 +1076,17 @@ TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
   TransferFunc[0].insert({RaxLoc, LiveInRsp});
   TransferFunc[1].insert({RspLoc, RaxLiveInBlk1});
   TransferFunc[2].insert({RspLoc, RaxLiveInBlk2});
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk0);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], RspDefInBlk0);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
   TransferFunc[2].clear();
@@ -1119,8 +1130,8 @@ TEST_F(InstrRefLDVTest, MLocDiamondSpills) {
   // There are other locations, for things like xmm0, which we're going to
   // ignore here.
 
-  ValueIDNum InLocs[4][10];
-  ValueIDNum *InLocsPtr[4] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(4, 10);
 
   // Transfer function: start with nothing.
   SmallVector<MLocTransferMap, 1> TransferFunc;
@@ -1155,16 +1166,15 @@ TEST_F(InstrRefLDVTest, MLocDiamondSpills) {
   // function.
   TransferFunc[1].insert({ALStackLoc, ALDefInBlk1});
   TransferFunc[1].insert({HAXStackLoc, HAXDefInBlk1});
-  initValueArray(InLocsPtr, 4, 10);
-  placeMLocPHIs(*MF, AllBlocks, InLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[3][ALStackLoc.asU64()], ALPHI);
-  EXPECT_EQ(InLocs[3][AXStackLoc.asU64()], AXPHI);
-  EXPECT_EQ(InLocs[3][EAXStackLoc.asU64()], EAXPHI);
-  EXPECT_EQ(InLocs[3][HAXStackLoc.asU64()], HAXPHI);
-  EXPECT_EQ(InLocs[3][RAXStackLoc.asU64()], RAXPHI);
+  initValueArray(MInLocs, 4, 10);
+  placeMLocPHIs(*MF, AllBlocks, MInLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[3][ALStackLoc.asU64()], ALPHI);
+  EXPECT_EQ(MInLocs[3][AXStackLoc.asU64()], AXPHI);
+  EXPECT_EQ(MInLocs[3][EAXStackLoc.asU64()], EAXPHI);
+  EXPECT_EQ(MInLocs[3][HAXStackLoc.asU64()], HAXPHI);
+  EXPECT_EQ(MInLocs[3][RAXStackLoc.asU64()], RAXPHI);
   // AH should be left untouched,
-  EXPECT_EQ(InLocs[3][AHStackLoc.asU64()], ValueIDNum::EmptyValue);
-
+  EXPECT_EQ(MInLocs[3][AHStackLoc.asU64()], ValueIDNum::EmptyValue);
 }
 
 TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
@@ -1182,9 +1192,8 @@ TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum InLocs[3][2], OutLocs[3][2];
-  ValueIDNum *InLocsPtr[3] = {InLocs[0], InLocs[1], InLocs[2]};
-  ValueIDNum *OutLocsPtr[3] = {OutLocs[0], OutLocs[1], OutLocs[2]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
 
   SmallVector<MLocTransferMap, 1> TransferFunc;
   TransferFunc.resize(3);
@@ -1200,15 +1209,15 @@ TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
   ValueIDNum RaxPHIInBlk2(RetBlk, 0, RaxLoc);
 
   // Begin test with all locations being live-through.
-  initValueArray(InLocsPtr, 3, 2);
-  initValueArray(OutLocsPtr, 3, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
+  initValueArray(MInLocs, 3, 2);
+  initValueArray(MOutLocs, 3, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
 
   // Add a def of $rsp to the loop block: it should be in the live-outs, but
   // should cause a PHI to be placed in the live-ins. Test the transfer function
@@ -1217,22 +1226,22 @@ TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
   TransferFunc[1].insert({RaxLoc, RspPHIInBlk1});
   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
-  initValueArray(InLocsPtr, 3, 2);
-  initValueArray(OutLocsPtr, 3, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk1);
+  initValueArray(MInLocs, 3, 2);
+  initValueArray(MOutLocs, 3, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
   // Check rax as well,
-  EXPECT_EQ(InLocs[0][1], LiveInRax);
-  EXPECT_EQ(InLocs[1][1], RaxPHIInBlk1);
-  EXPECT_EQ(InLocs[2][1], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[0][1], LiveInRax);
-  EXPECT_EQ(OutLocs[1][1], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][1], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[0][1], LiveInRax);
+  EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][1], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[0][1], LiveInRax);
+  EXPECT_EQ(MOutLocs[1][1], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
   TransferFunc[1].clear();
   TransferFunc[2].clear();
 
@@ -1243,22 +1252,22 @@ TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
   // to $rsp.
   TransferFunc[0].insert({RaxLoc, LiveInRsp});
   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
-  initValueArray(InLocsPtr, 3, 2);
-  initValueArray(OutLocsPtr, 3, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
+  initValueArray(MInLocs, 3, 2);
+  initValueArray(MOutLocs, 3, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
   // Check $rax's values.
-  EXPECT_EQ(InLocs[0][1], LiveInRax);
-  EXPECT_EQ(InLocs[1][1], LiveInRsp);
-  EXPECT_EQ(InLocs[2][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[0][1], LiveInRax);
+  EXPECT_EQ(MInLocs[1][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
 }
@@ -1282,11 +1291,8 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum InLocs[5][2], OutLocs[5][2];
-  ValueIDNum *InLocsPtr[5] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3],
-                              InLocs[4]};
-  ValueIDNum *OutLocsPtr[5] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3],
-                               OutLocs[4]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
 
   SmallVector<MLocTransferMap, 1> TransferFunc;
   TransferFunc.resize(5);
@@ -1305,56 +1311,56 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
 
   // Like the other tests: first ensure that if there's nothing in the transfer
   // function, then everything is live-through (check $rsp).
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(InLocs[4][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][0], LiveInRsp);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
 
   // A def in the inner loop means we should get PHIs at the heads of both
   // loops. Live-outs of the last three blocks will be the def, as it dominates
   // those.
   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk2);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk2);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
   TransferFunc[2].clear();
 
   // Adding a def to the outer loop header shouldn't affect this much -- the
   // live-out of block 1 changes.
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk2);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk2);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
   TransferFunc[1].clear();
   TransferFunc[2].clear();
 
@@ -1364,19 +1370,19 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk2);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[1].clear();
   TransferFunc[2].clear();
   TransferFunc[3].clear();
@@ -1385,19 +1391,19 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   // head and tail of the outer loop. The inner loop should be live-through.
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[1].clear();
   TransferFunc[3].clear();
 
@@ -1407,22 +1413,22 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   TransferFunc[1].insert({RaxLoc, RspDefInBlk1});
   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   // Look at raxes value in the relevant blocks,
-  EXPECT_EQ(InLocs[2][1], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[1][1], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[2][1], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[1][1], RspDefInBlk1);
   TransferFunc[1].clear();
   TransferFunc[2].clear();
   TransferFunc[3].clear();
@@ -1430,19 +1436,19 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   // If we have a single def in the tail of the outer loop, that should produce
   // a PHI at the loop head, and be live-through the inner loop.
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[3].clear();
 
   // And if we copy from $rsp to $rax in block 2, it should resolve to the PHI
@@ -1451,20 +1457,20 @@ TEST_F(InstrRefLDVTest, MLocNestedLoop) {
   // inner loop.
   TransferFunc[2].insert({RaxLoc, RspPHIInBlk2});
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
   // Examining the values of rax,
-  EXPECT_EQ(InLocs[0][1], LiveInRax);
-  EXPECT_EQ(InLocs[1][1], RaxPHIInBlk1);
-  EXPECT_EQ(InLocs[2][1], RaxPHIInBlk2);
-  EXPECT_EQ(InLocs[3][1], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[4][1], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[0][1], LiveInRax);
-  EXPECT_EQ(OutLocs[1][1], RaxPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][1], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[3][1], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[4][1], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[0][1], LiveInRax);
+  EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][1], RaxPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][1], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[4][1], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[0][1], LiveInRax);
+  EXPECT_EQ(MOutLocs[1][1], RaxPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[3][1], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[4][1], RspPHIInBlk1);
   TransferFunc[2].clear();
   TransferFunc[3].clear();
 }
@@ -1487,11 +1493,8 @@ TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum InLocs[5][2], OutLocs[5][2];
-  ValueIDNum *InLocsPtr[5] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3],
-                              InLocs[4]};
-  ValueIDNum *OutLocsPtr[5] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3],
-                               OutLocs[4]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
 
   SmallVector<MLocTransferMap, 1> TransferFunc;
   TransferFunc.resize(5);
@@ -1509,71 +1512,71 @@ TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
   ValueIDNum RaxPHIInBlk2(Head2Blk, 0, RaxLoc);
 
   // As ever, test that everything is live-through if there are no defs.
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(InLocs[4][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][0], LiveInRsp);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
 
   // Putting a def in the 'join' block will cause us to have two distinct
   // PHIs in each loop head, then on entry to the join block.
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[3].clear();
 
   // We should get the same behaviour if we put the def in either of the
   // loop heads -- it should force the other head to be a PHI.
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(InLocs[4][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspPHIInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
   TransferFunc[1].clear();
 
   // Check symmetry,
   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(InLocs[4][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspPHIInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
   TransferFunc[2].clear();
 
   // Test some scenarios where there _shouldn't_ be any PHIs created at heads.
@@ -1585,19 +1588,19 @@ TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
   TransferFunc[2].clear();
@@ -1609,19 +1612,19 @@ TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
   TransferFunc[0].insert({RaxLoc, LiveInRsp});
   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(InLocs[4][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][0], LiveInRsp);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
   TransferFunc[0].clear();
   TransferFunc[1].clear();
   TransferFunc[2].clear();
@@ -1646,11 +1649,8 @@ TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum InLocs[5][2], OutLocs[5][2];
-  ValueIDNum *InLocsPtr[5] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3],
-                              InLocs[4]};
-  ValueIDNum *OutLocsPtr[5] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3],
-                               OutLocs[4]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
 
   SmallVector<MLocTransferMap, 1> TransferFunc;
   TransferFunc.resize(5);
@@ -1667,55 +1667,55 @@ TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
   ValueIDNum RaxPHIInBlk3(Loop3Blk, 0, RaxLoc);
 
   // As ever, test that everything is live-through if there are no defs.
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], LiveInRsp);
-  EXPECT_EQ(InLocs[2][0], LiveInRsp);
-  EXPECT_EQ(InLocs[3][0], LiveInRsp);
-  EXPECT_EQ(InLocs[4][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][0], LiveInRsp);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
 
   // A def in loop3 should cause PHIs in every loop block: they're all
   // reachable from each other.
   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk3);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk3);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
   TransferFunc[3].clear();
 
   // A def in loop1 should cause a PHI in loop1, but not the other blocks.
   // loop2 and loop3 are dominated by the def in loop1, so they should have
   // that value live-through.
   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[3][0], RspDefInBlk1);
-  EXPECT_EQ(InLocs[4][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[3][0], RspDefInBlk1);
-  EXPECT_EQ(OutLocs[4][0], RspDefInBlk1);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
+  EXPECT_EQ(MInLocs[4][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[3][0], RspDefInBlk1);
+  EXPECT_EQ(MOutLocs[4][0], RspDefInBlk1);
   TransferFunc[1].clear();
 
   // As with earlier tricks: copy $rsp to $rax in the entry block, then $rax
@@ -1742,31 +1742,31 @@ TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
   // approach. PHIs will be left in $rsp on entry to each block.
   TransferFunc[0].insert({RaxLoc, LiveInRsp});
   TransferFunc[3].insert({RspLoc, RaxPHIInBlk3});
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
-  buildMLocValueMap(InLocsPtr, OutLocsPtr, TransferFunc);
-  EXPECT_EQ(InLocs[0][0], LiveInRsp);
-  EXPECT_EQ(InLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(InLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(InLocs[3][0], RspPHIInBlk3);
-  EXPECT_EQ(InLocs[4][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][0], RspPHIInBlk1);
-  EXPECT_EQ(OutLocs[2][0], RspPHIInBlk2);
-  EXPECT_EQ(OutLocs[3][0], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][0], LiveInRsp);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
+  buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
+  EXPECT_EQ(MInLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
+  EXPECT_EQ(MInLocs[4][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
+  EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
+  EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
   // Check $rax's value. It should have $rsps value from the entry block
   // onwards.
-  EXPECT_EQ(InLocs[0][1], LiveInRax);
-  EXPECT_EQ(InLocs[1][1], LiveInRsp);
-  EXPECT_EQ(InLocs[2][1], LiveInRsp);
-  EXPECT_EQ(InLocs[3][1], LiveInRsp);
-  EXPECT_EQ(InLocs[4][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[0][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[1][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[2][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[3][1], LiveInRsp);
-  EXPECT_EQ(OutLocs[4][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[0][1], LiveInRax);
+  EXPECT_EQ(MInLocs[1][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[2][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[3][1], LiveInRsp);
+  EXPECT_EQ(MInLocs[4][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[3][1], LiveInRsp);
+  EXPECT_EQ(MOutLocs[4][1], LiveInRsp);
 }
 
 TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
@@ -1782,10 +1782,10 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum OutLocs[4][2];
-  ValueIDNum *OutLocsPtr[4] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
 
-  initValueArray(OutLocsPtr, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
 
   unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
 
@@ -1809,15 +1809,15 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
     Preds.push_back(Pred);
 
   // Specify the live-outs around the joining block.
-  OutLocs[1][0] = LiveInRsp;
-  OutLocs[2][0] = LiveInRax;
+  MOutLocs[1][0] = LiveInRsp;
+  MOutLocs[2][0] = LiveInRax;
 
   Optional<ValueIDNum> Result;
 
   // Simple case: join two distinct values on entry to the block.
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   // Should have picked a PHI in $rsp in block 3.
   EXPECT_TRUE(Result);
   if (Result) {
@@ -1828,7 +1828,7 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
   // successfully join. The CFG merge would select the right values, but in
   // the wrong conditions.
   std::swap(VLiveOuts[1], VLiveOuts[2]);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Swap back,
@@ -1836,19 +1836,19 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
   // Setting one of these to being a constant should prohibit merging.
   VLiveOuts[1].Kind = DbgValue::Const;
   VLiveOuts[1].MO = MachineOperand::CreateImm(0);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Seeing both to being a constant -> still prohibit, it shouldn't become
   // a value in the register file anywhere.
   VLiveOuts[2] = VLiveOuts[1];
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // NoVals shouldn't join with anything else.
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // We might merge in another VPHI in such a join. Present pickVPHILoc with
@@ -1858,25 +1858,25 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
   EXPECT_EQ(VLiveOuts[2].ID, ValueIDNum::EmptyValue);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // However, if we know the value of the incoming VPHI, we can search for its
   // location. Use a PHI machine-value for doing this, as VPHIs should always
   // have PHI values, or they should have been eliminated.
-  OutLocs[2][0] = RspPHIInBlk2;
+  MOutLocs[2][0] = RspPHIInBlk2;
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
   VLiveOuts[2].ID = RspPHIInBlk2; // Set location where PHI happens.
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_TRUE(Result);
   if (Result) {
     EXPECT_EQ(*Result, RspPHIInBlk3);
   }
 
   // If that value isn't available from that block, don't join.
-  OutLocs[2][0] = LiveInRsp;
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[2][0] = LiveInRsp;
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Check that we don't pick values when the properties disagree, for example
@@ -1886,13 +1886,13 @@ TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
   DbgValueProperties PropsWithExpr(NewExpr, false);
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   DbgValueProperties PropsWithIndirect(EmptyExpr, true);
   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
-  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 }
 
@@ -1911,10 +1911,10 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
   Register RAX = getRegByName("RAX");
   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
 
-  ValueIDNum OutLocs[3][2];
-  ValueIDNum *OutLocsPtr[4] = {OutLocs[0], OutLocs[1], OutLocs[2]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
 
-  initValueArray(OutLocsPtr, 3, 2);
+  initValueArray(MOutLocs, 3, 2);
 
   unsigned EntryBlk = 0, LoopBlk = 1;
 
@@ -1937,15 +1937,15 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
     Preds.push_back(Pred);
 
   // Specify the live-outs around the joining block.
-  OutLocs[0][0] = LiveInRsp;
-  OutLocs[1][0] = LiveInRax;
+  MOutLocs[0][0] = LiveInRsp;
+  MOutLocs[1][0] = LiveInRax;
 
   Optional<ValueIDNum> Result;
 
   // See that we can merge as normal on a backedge.
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   // Should have picked a PHI in $rsp in block 1.
   EXPECT_TRUE(Result);
   if (Result) {
@@ -1953,22 +1953,22 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
   }
 
   // And that, if the desired values aren't available, we don't merge.
-  OutLocs[1][0] = LiveInRsp;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[1][0] = LiveInRsp;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Test the backedge behaviour: PHIs that feed back into themselves can
   // carry this variables value. Feed in LiveInRsp in both $rsp and $rax
   // from the entry block, but only put an appropriate backedge PHI in $rax.
   // Only the $rax location can form the correct PHI.
-  OutLocs[0][0] = LiveInRsp;
-  OutLocs[0][1] = LiveInRsp;
-  OutLocs[1][0] = RaxPHIInBlk1;
-  OutLocs[1][1] = RaxPHIInBlk1;
+  MOutLocs[0][0] = LiveInRsp;
+  MOutLocs[0][1] = LiveInRsp;
+  MOutLocs[1][0] = RaxPHIInBlk1;
+  MOutLocs[1][1] = RaxPHIInBlk1;
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   // Crucially, a VPHI originating in this block:
   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_TRUE(Result);
   if (Result) {
     EXPECT_EQ(*Result, RaxPHIInBlk1);
@@ -1976,16 +1976,16 @@ TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
 
   // Merging should not be permitted if there's a usable PHI on the backedge,
   // but it's in the wrong place. (Overwrite $rax).
-  OutLocs[1][1] = LiveInRax;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[1][1] = LiveInRax;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Additionally, if the VPHI coming back on the loop backedge isn't from
   // this block (block 1), we can't merge it.
-  OutLocs[1][1] = RaxPHIInBlk1;
+  MOutLocs[1][1] = RaxPHIInBlk1;
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 }
 
@@ -2011,10 +2011,10 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
   Register RBX = getRegByName("RBX");
   LocIdx RbxLoc = MTracker->lookupOrTrackRegister(RBX);
 
-  ValueIDNum OutLocs[5][3];
-  ValueIDNum *OutLocsPtr[5] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3], OutLocs[4]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(5, 3);
 
-  initValueArray(OutLocsPtr, 5, 3);
+  initValueArray(MOutLocs, 5, 3);
 
   unsigned EntryBlk = 0, Loop1Blk = 1;
 
@@ -2043,9 +2043,9 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
 
   // Specify the live-outs around the joining block. Incoming edges from the
   // entry block, self, and loop2.
-  OutLocs[0][0] = LiveInRsp;
-  OutLocs[1][0] = LiveInRax;
-  OutLocs[2][0] = LiveInRbx;
+  MOutLocs[0][0] = LiveInRsp;
+  MOutLocs[1][0] = LiveInRax;
+  MOutLocs[2][0] = LiveInRbx;
 
   Optional<ValueIDNum> Result;
 
@@ -2053,7 +2053,7 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
   VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   // Should have picked a PHI in $rsp in block 1.
   EXPECT_TRUE(Result);
   if (Result) {
@@ -2061,20 +2061,20 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
   }
 
   // Check too that permuting the live-out locations prevents merging
-  OutLocs[0][0] = LiveInRax;
-  OutLocs[1][0] = LiveInRbx;
-  OutLocs[2][0] = LiveInRsp;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[0][0] = LiveInRax;
+  MOutLocs[1][0] = LiveInRbx;
+  MOutLocs[2][0] = LiveInRsp;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
-  OutLocs[0][0] = LiveInRsp;
-  OutLocs[1][0] = LiveInRax;
-  OutLocs[2][0] = LiveInRbx;
+  MOutLocs[0][0] = LiveInRsp;
+  MOutLocs[1][0] = LiveInRax;
+  MOutLocs[2][0] = LiveInRbx;
 
   // Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
   // wants LiveInRax).
-  OutLocs[1][0] = RspPHIInBlk1;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[1][0] = RspPHIInBlk1;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // If the variables value on that edge is a VPHI feeding into itself, that's
@@ -2082,18 +2082,18 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
   VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_TRUE(Result);
   if (Result) {
     EXPECT_EQ(*Result, RspPHIInBlk1);
   }
 
   // Likewise: the other backedge being a VPHI from block 1 should be accepted.
-  OutLocs[2][0] = RspPHIInBlk1;
+  MOutLocs[2][0] = RspPHIInBlk1;
   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
   VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_TRUE(Result);
   if (Result) {
     EXPECT_EQ(*Result, RspPHIInBlk1);
@@ -2102,32 +2102,32 @@ TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
   // Here's where it becomes tricky: we should not merge if there are two
   // _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
   // and rax for example. We can only pick one location as the live-in.
-  OutLocs[2][0] = RaxPHIInBlk1;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[2][0] = RaxPHIInBlk1;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // The above test sources correct machine-PHI-value from two places. Now
   // try with one machine-PHI-value, but placed in two 
diff erent locations
   // on the backedge. Again, we can't merge a location here, there's no
   // location that works on all paths.
-  OutLocs[0][0] = LiveInRsp;
-  OutLocs[1][0] = RspPHIInBlk1;
-  OutLocs[2][0] = LiveInRsp;
-  OutLocs[2][1] = RspPHIInBlk1;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[0][0] = LiveInRsp;
+  MOutLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[2][0] = LiveInRsp;
+  MOutLocs[2][1] = RspPHIInBlk1;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_FALSE(Result);
 
   // Scatter various PHI values across the available locations. Only rbx (loc 2)
   // has the right value in both backedges -- that's the loc that should be
   // picked.
-  OutLocs[0][2] = LiveInRsp;
-  OutLocs[1][0] = RspPHIInBlk1;
-  OutLocs[1][1] = RaxPHIInBlk1;
-  OutLocs[1][2] = RbxPHIInBlk1;
-  OutLocs[2][0] = LiveInRsp;
-  OutLocs[2][1] = RspPHIInBlk1;
-  OutLocs[2][2] = RbxPHIInBlk1;
-  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, OutLocsPtr, Preds);
+  MOutLocs[0][2] = LiveInRsp;
+  MOutLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[1][1] = RaxPHIInBlk1;
+  MOutLocs[1][2] = RbxPHIInBlk1;
+  MOutLocs[2][0] = LiveInRsp;
+  MOutLocs[2][1] = RspPHIInBlk1;
+  MOutLocs[2][2] = RbxPHIInBlk1;
+  Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
   EXPECT_TRUE(Result);
   if (Result) {
     EXPECT_EQ(*Result, RbxPHIInBlk1);
@@ -2493,12 +2493,11 @@ TEST_F(InstrRefLDVTest, VLocSingleBlock) {
   ASSERT_TRUE(MTracker->getNumLocs() == 1);
   LocIdx RspLoc(0);
 
-  ValueIDNum InLocs[2], OutLocs[2];
-  ValueIDNum *InLocsPtr[1] = {&InLocs[0]};
-  ValueIDNum *OutLocsPtr[1] = {&OutLocs[0]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(1, 2);
 
   ValueIDNum LiveInRsp = ValueIDNum(0, 0, RspLoc);
-  InLocs[0] = OutLocs[0] = LiveInRsp;
+  MInLocs[0][0] = MOutLocs[0][0] = LiveInRsp;
 
   DebugVariable Var(FuncVariable, None, nullptr);
   DbgValueProperties EmptyProps(EmptyExpr, false);
@@ -2521,14 +2520,14 @@ TEST_F(InstrRefLDVTest, VLocSingleBlock) {
   // Test that, with no assignments at all, no mappings are created for the
   // variable in this function.
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output.size(), 0ul);
 
   // If we put an assignment in the transfer function, that should... well,
   // do nothing, because we don't store the live-outs.
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output.size(), 0ul);
 
   // There is pretty much nothing else of interest to test with a single block.
@@ -2554,12 +2553,11 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
   ValueIDNum RspPHIInBlk3 = ValueIDNum(RetBlk, 0, RspLoc);
 
-  ValueIDNum InLocs[4][2], OutLocs[4][2];
-  ValueIDNum *InLocsPtr[4] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3]};
-  ValueIDNum *OutLocsPtr[4] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
 
-  initValueArray(InLocsPtr, 4, 2);
-  initValueArray(OutLocsPtr, 4, 2);
+  initValueArray(MInLocs, 4, 2);
+  initValueArray(MOutLocs, 4, 2);
 
   DebugVariable Var(FuncVariable, None, nullptr);
   DbgValueProperties EmptyProps(EmptyExpr, false);
@@ -2584,8 +2582,8 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
 
   // Start off with LiveInRsp in every location.
   for (unsigned int I = 0; I < 4; ++I) {
-    InLocs[I][0] = InLocs[I][1] = LiveInRsp;
-    OutLocs[I][0] = OutLocs[I][1] = LiveInRsp;
+    MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
+    MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
   }
 
   auto ClearOutputs = [&]() {
@@ -2596,7 +2594,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
 
   // No assignments -> no values.
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2606,7 +2604,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   // produce any live-ins.
   VLocs[3].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2618,7 +2616,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   VLocs[3].Vars.clear();
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2628,7 +2626,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
 
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2640,7 +2638,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   // values through to all other blocks, as it dominates.
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2660,7 +2658,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   // values through to all other blocks, as it dominates.
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2679,7 +2677,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2695,7 +2693,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2714,7 +2712,7 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2729,11 +2727,11 @@ TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
 
   // But on the other hand, if there's a location in the register file where
   // those two values can be joined, do so.
-  OutLocs[1][0] = LiveInRax;
+  MOutLocs[1][0] = LiveInRax;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2772,12 +2770,11 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   ValueIDNum RspDefInBlk1 = ValueIDNum(LoopBlk, 1, RspLoc);
   ValueIDNum RaxPHIInBlk1 = ValueIDNum(LoopBlk, 0, RaxLoc);
 
-  ValueIDNum InLocs[3][2], OutLocs[3][2];
-  ValueIDNum *InLocsPtr[3] = {InLocs[0], InLocs[1], InLocs[2]};
-  ValueIDNum *OutLocsPtr[3] = {OutLocs[0], OutLocs[1], OutLocs[2]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
 
-  initValueArray(InLocsPtr, 3, 2);
-  initValueArray(OutLocsPtr, 3, 2);
+  initValueArray(MInLocs, 3, 2);
+  initValueArray(MOutLocs, 3, 2);
 
   DebugVariable Var(FuncVariable, None, nullptr);
   DbgValueProperties EmptyProps(EmptyExpr, false);
@@ -2797,8 +2794,8 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
 
   // Start off with LiveInRsp in every location.
   for (unsigned int I = 0; I < 3; ++I) {
-    InLocs[I][0] = InLocs[I][1] = LiveInRsp;
-    OutLocs[I][0] = OutLocs[I][1] = LiveInRsp;
+    MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
+    MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
   }
 
   auto ClearOutputs = [&]() {
@@ -2810,7 +2807,7 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   // Easy starter: a dominating assign should propagate to all blocks.
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2826,7 +2823,7 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -2838,7 +2835,7 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2855,7 +2852,7 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2867,12 +2864,12 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
 
   // Install a completely unrelated PHI value, that we should not join on. Try
   // with unrelated assign in loop block again.
-  InLocs[1][0] = RspPHIInBlk1;
-  OutLocs[1][0] = RspDefInBlk1;
+  MInLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[1][0] = RspDefInBlk1;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2884,12 +2881,12 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
 
   // Now, if we assign RspDefInBlk1 in the loop block, we should be able to
   // find the appropriate PHI.
-  InLocs[1][0] = RspPHIInBlk1;
-  OutLocs[1][0] = RspDefInBlk1;
+  MInLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[1][0] = RspDefInBlk1;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2903,14 +2900,14 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
 
   // If the PHI happens in a 
diff erent location, the live-in should happen
   // there.
-  InLocs[1][0] = LiveInRsp;
-  OutLocs[1][0] = LiveInRsp;
-  InLocs[1][1] = RaxPHIInBlk1;
-  OutLocs[1][1] = RspDefInBlk1;
+  MInLocs[1][0] = LiveInRsp;
+  MOutLocs[1][0] = LiveInRsp;
+  MInLocs[1][1] = RaxPHIInBlk1;
+  MOutLocs[1][1] = RspDefInBlk1;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2925,14 +2922,14 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   // The PHI happening in both places should be handled too. Exactly where
   // isn't important, but if the location picked changes, this test will let
   // you know.
-  InLocs[1][0] = RaxPHIInBlk1;
-  OutLocs[1][0] = RspDefInBlk1;
-  InLocs[1][1] = RaxPHIInBlk1;
-  OutLocs[1][1] = RspDefInBlk1;
+  MInLocs[1][0] = RaxPHIInBlk1;
+  MOutLocs[1][0] = RspDefInBlk1;
+  MInLocs[1][1] = RaxPHIInBlk1;
+  MOutLocs[1][1] = RspDefInBlk1;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2959,14 +2956,14 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
   // joined at some location by the control flow.
   // [This test input would never occur naturally, the machine-PHI would be
   //  eliminated]
-  InLocs[1][0] = RspPHIInBlk1;
-  OutLocs[1][0] = RspPHIInBlk1;
-  InLocs[1][1] = LiveInRax;
-  OutLocs[1][1] = LiveInRax;
+  MInLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[1][0] = RspPHIInBlk1;
+  MInLocs[1][1] = LiveInRax;
+  MOutLocs[1][1] = LiveInRax;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(RspPHIInBlk1, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -2980,12 +2977,12 @@ TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
 
   // Test that we can eliminate PHIs. A PHI will be placed at the loop head
   // because there's a def in in.
-  InLocs[1][0] = LiveInRsp;
-  OutLocs[1][0] = LiveInRsp;
+  MInLocs[1][0] = LiveInRsp;
+  MOutLocs[1][0] = LiveInRsp;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -3026,12 +3023,11 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   ValueIDNum RspPHIInBlk2 = ValueIDNum(Loop2Blk, 0, RspLoc);
   ValueIDNum RspDefInBlk2 = ValueIDNum(Loop2Blk, 1, RspLoc);
 
-  ValueIDNum InLocs[5][2], OutLocs[5][2];
-  ValueIDNum *InLocsPtr[5] = {InLocs[0], InLocs[1], InLocs[2], InLocs[3], InLocs[4]};
-  ValueIDNum *OutLocsPtr[5] = {OutLocs[0], OutLocs[1], OutLocs[2], OutLocs[3], OutLocs[4]};
+  FuncValueTable MInLocs, MOutLocs;
+  std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
 
-  initValueArray(InLocsPtr, 5, 2);
-  initValueArray(OutLocsPtr, 5, 2);
+  initValueArray(MInLocs, 5, 2);
+  initValueArray(MOutLocs, 5, 2);
 
   DebugVariable Var(FuncVariable, None, nullptr);
   DbgValueProperties EmptyProps(EmptyExpr, false);
@@ -3053,8 +3049,8 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
 
   // Start off with LiveInRsp in every location.
   for (unsigned int I = 0; I < 5; ++I) {
-    InLocs[I][0] = InLocs[I][1] = LiveInRsp;
-    OutLocs[I][0] = OutLocs[I][1] = LiveInRsp;
+    MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
+    MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
   }
 
   auto ClearOutputs = [&]() {
@@ -3066,7 +3062,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   // A dominating assign should propagate to all blocks.
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -3088,7 +3084,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -3106,7 +3102,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   // in dominated blocks.
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -3124,7 +3120,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[3].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -3139,7 +3135,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   ASSERT_EQ(Output[2].size(), 1ul);
@@ -3161,7 +3157,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 1ul);
   EXPECT_EQ(Output[2].size(), 1ul);
@@ -3183,8 +3179,8 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   // loop head, we could find a live-in location for the inner loop. But because
   // the outer loop has no PHI, we can't find a variable value for outer loop
   // head, so can't have a live-in value for the inner loop head.
-  InLocs[2][0] = RspPHIInBlk2;
-  OutLocs[2][0] = LiveInRax;
+  MInLocs[2][0] = RspPHIInBlk2;
+  MOutLocs[2][0] = LiveInRax;
   // NB: all other machine locations are LiveInRsp, disallowing a PHI in block
   // one. Even though RspPHIInBlk2 isn't available later in the function, we
   // should still produce a live-in value. The fact it's unavailable is a
@@ -3192,7 +3188,7 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   EXPECT_EQ(Output[1].size(), 0ul);
   EXPECT_EQ(Output[2].size(), 0ul);
@@ -3209,16 +3205,16 @@ TEST_F(InstrRefLDVTest, VLocNestedLoop) {
   // Have an assignment in inner loop that can have a PHI resolved; and add a
   // machine value PHI to the outer loop head, so that we can find a location
   // all the way through the function.
-  InLocs[1][0] = RspPHIInBlk1;
-  OutLocs[1][0] = RspPHIInBlk1;
-  InLocs[2][0] = RspPHIInBlk2;
-  OutLocs[2][0] = RspDefInBlk2;
-  InLocs[3][0] = RspDefInBlk2;
-  OutLocs[3][0] = RspDefInBlk2;
+  MInLocs[1][0] = RspPHIInBlk1;
+  MOutLocs[1][0] = RspPHIInBlk1;
+  MInLocs[2][0] = RspPHIInBlk2;
+  MOutLocs[2][0] = RspDefInBlk2;
+  MInLocs[3][0] = RspDefInBlk2;
+  MOutLocs[3][0] = RspDefInBlk2;
   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
   VLocs[2].Vars.insert({Var, DbgValue(RspDefInBlk2, EmptyProps, DbgValue::Def)});
   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
-                    OutLocsPtr, InLocsPtr, VLocs);
+                    MOutLocs, MInLocs, VLocs);
   EXPECT_EQ(Output[0].size(), 0ul);
   ASSERT_EQ(Output[1].size(), 1ul);
   ASSERT_EQ(Output[2].size(), 1ul);


        


More information about the llvm-commits mailing list