diff options
Diffstat (limited to 'llvm/lib/MC/MCExpr.cpp')
-rw-r--r-- | llvm/lib/MC/MCExpr.cpp | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp index 4465104bfe5..41feaa83757 100644 --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -271,6 +271,25 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout, 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: @@ -300,20 +319,37 @@ static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, // 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. |