Subzero: Ignore variables with no actual uses.

Liveness analysis uses a pair of bit vectors in each CFG node.  The early bits correspond to "global" variables that are referenced in more than one block, and the latter bits correspond to "local" variables that are referenced in only that particular single block.

Due to an oversight, variables that have no uses are conservatively classified as global, and consume space in every liveness bit vector.

This CL improves memory usage by reducing liveness bit vector size:

1. Identify variables with no actual uses and exclude them from the bit vectors.

2. Don't do liveness analysis on rematerializable variables, because they have no need to be involved in register allocation or dead code elimination.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4366
R=jpp@chromium.org

Review URL: https://codereview.chromium.org/1844713004 .
diff --git a/src/IceOperand.h b/src/IceOperand.h
index 327c348..d80bede 100644
--- a/src/IceOperand.h
+++ b/src/IceOperand.h
@@ -661,7 +661,9 @@
   void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; }
 
   void setIgnoreLiveness() { IgnoreLiveness = true; }
-  bool getIgnoreLiveness() const { return IgnoreLiveness; }
+  bool getIgnoreLiveness() const {
+    return IgnoreLiveness || IsRematerializable;
+  }
 
   int32_t getStackOffset() const { return StackOffset; }
   void setStackOffset(int32_t Offset) { StackOffset = Offset; }
@@ -863,8 +865,6 @@
 /// VariableTracking tracks the metadata for a single variable.  It is
 /// only meant to be used internally by VariablesMetadata.
 class VariableTracking {
-  VariableTracking &operator=(const VariableTracking &) = delete;
-
 public:
   enum MultiDefState {
     // TODO(stichnot): Consider using just a simple counter.
@@ -873,9 +873,16 @@
     MDS_MultiDefSingleBlock,
     MDS_MultiDefMultiBlock
   };
-  enum MultiBlockState { MBS_Unknown, MBS_SingleBlock, MBS_MultiBlock };
+  enum MultiBlockState {
+    MBS_Unknown,     // Not yet initialized, so be conservative
+    MBS_NoUses,      // Known to have no uses
+    MBS_SingleBlock, // All uses in are in a single block
+    MBS_MultiBlock   // Several uses across several blocks
+  };
   VariableTracking() = default;
   VariableTracking(const VariableTracking &) = default;
+  VariableTracking &operator=(const VariableTracking &) = default;
+  VariableTracking(MultiBlockState MultiBlock) : MultiBlock(MultiBlock) {}
   MultiDefState getMultiDef() const { return MultiDef; }
   MultiBlockState getMultiBlock() const { return MultiBlock; }
   const Inst *getFirstDefinitionSingleBlock() const;
@@ -948,6 +955,7 @@
   /// always considered multi-block because they are live coming into the entry
   /// block.
   bool isMultiBlock(const Variable *Var) const;
+  bool isSingleBlock(const Variable *Var) const;
   /// Returns the node that the given Variable is used in, assuming
   /// isMultiBlock() returns false. Otherwise, nullptr is returned.
   CfgNode *getLocalUseNode(const Variable *Var) const;