Revert 122011, 122012, 122013, 122023 adding back an important optimization.
[oota-llvm.git] / lib / MC / MCExpr.cpp
index 5d2c7070685a3fb136790819260d6cb7e20594d7..47b81407d99e4282d68ad93defa6205542d3aa50 100644 (file)
@@ -290,6 +290,25 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
   return true;
 }
 
+/// \brief Helper method for \see EvaluateSymbolAdd().
+static void AttemptToFoldSymbolOffsetDifference(const MCAsmLayout *Layout,
+                                                const MCSymbolRefExpr *&A,
+                                                const MCSymbolRefExpr *&B,
+                                                int64_t &Addend) {
+  const MCAssembler &Asm = Layout->getAssembler();
+
+  if (A && B &&
+      Asm.getWriter().IsSymbolRefDifferenceFullyResolved(Asm, A, B)) {
+    // Eagerly evaluate.
+    Addend += (Layout->getSymbolOffset(&Asm.getSymbolData(A->getSymbol())) -
+               Layout->getSymbolOffset(&Asm.getSymbolData(B->getSymbol())));
+
+    // Clear the symbol expr pointers to indicate we have folded these
+    // operands.
+    A = B = 0;
+  }
+}
+
 /// \brief Evaluate the result of an add between (conceptually) two MCValues.
 ///
 /// This routine conceptually attempts to construct an MCValue:
@@ -304,6 +323,11 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
 ///
 /// \returns True on success, false if the result is not representable in an
 /// MCValue.
+
+/// NOTE: It is really important to have both the Asm and Layout arguments.
+/// They might look redundant, but this function can be used before layout
+/// is done (see the object streamer for example) and having the Asm argument
+/// lets us avoid relocations.
 static bool EvaluateSymbolicAdd(const MCAssembler *Asm,
                                 const MCAsmLayout *Layout,
                                 const SectionAddrMap *Addrs,
@@ -320,25 +344,43 @@ static bool EvaluateSymbolicAdd(const MCAssembler *Asm,
   // Fold the result constant immediately.
   int64_t Result_Cst = LHS_Cst + RHS_Cst;
 
+  // If we have a layout, we can fold resolved differences.
+  if (Layout) {
+    // First, fold out any differences which are fully resolved. By
+    // reassociating terms in
+    //   Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
+    // we have the four possible differences:
+    //   (LHS_A - LHS_B),
+    //   (LHS_A - RHS_B),
+    //   (RHS_A - LHS_B),
+    //   (RHS_A - RHS_B).
+    // Since we are attempting to be as aggresive as possible about folding, we
+    // attempt to evaluate each possible alternative.
+    AttemptToFoldSymbolOffsetDifference(Layout, LHS_A, LHS_B, Result_Cst);
+    AttemptToFoldSymbolOffsetDifference(Layout, LHS_A, RHS_B, Result_Cst);
+    AttemptToFoldSymbolOffsetDifference(Layout, RHS_A, LHS_B, Result_Cst);
+    AttemptToFoldSymbolOffsetDifference(Layout, RHS_A, RHS_B, Result_Cst);
+  }
+
   // We can't represent the addition or subtraction of two symbols.
   if ((LHS_A && RHS_A) || (LHS_B && RHS_B))
     return false;
 
+  // At this point, we have at most one additive symbol and one subtractive
+  // symbol -- find them.
   const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A;
   const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B;
-  if (B) {
-    // If we have a negated symbol, then we must have also have a non-negated
-    // symbol in order to encode the expression. We can do this check later to
-    // permit expressions which eventually fold to a representable form -- such
-    // as (a + (0 - b)) -- if necessary.
-    if (!A)
-      return false;
-  }
+
+  // If we have a negated symbol, then we must have also have a non-negated
+  // symbol in order to encode the expression.
+  if (B && !A)
+    return false;
 
   // Absolutize symbol differences between defined symbols when we have a
   // layout object and the target requests it.
 
-  assert(!(Layout && !Asm));
+  assert((!Layout || Asm) &&
+         "Must have an assembler object if layout is given!");
 
   if (Asm && A && B) {
     const MCSymbol &SA = A->getSymbol();