diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h
--- a/llvm/include/llvm/MC/MCExpr.h
+++ b/llvm/include/llvm/MC/MCExpr.h
@@ -56,7 +56,8 @@
   bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
                                  const MCAsmLayout *Layout,
                                  const MCFixup *Fixup,
-                                 const SectionAddrMap *Addrs, bool InSet) const;
+                                 const SectionAddrMap *Addrs, bool InSet,
+                                 bool IsCond) const;
 
 public:
   MCExpr(const MCExpr &) = delete;
@@ -93,6 +94,7 @@
   bool evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const;
   bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const;
   bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
+  bool evaluateIfCondAsAbsolute(int64_t &Res, const MCAssembler *Asm) const;
 
   bool evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const;
 
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
--- a/llvm/lib/MC/MCExpr.cpp
+++ b/llvm/lib/MC/MCExpr.cpp
@@ -481,6 +481,28 @@
   return evaluateAsAbsolute(Res, Asm, nullptr, nullptr, false);
 }
 
+bool MCExpr::evaluateIfCondAsAbsolute(int64_t &Res,
+                                      const MCAssembler *Asm) const {
+  MCValue Value;
+
+  // Fast path constants.
+  if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(this)) {
+    Res = CE->getValue();
+    return true;
+  }
+
+  // Setting IsCond causes us to absolutize differences of symbols in consective
+  // MCDataFragments, e.g. dot symbol and foo in the following example:
+  // foo:instr; .if . - foo; instr; .endif
+  bool IsRelocatable = evaluateAsRelocatableImpl(Value, Asm, nullptr, nullptr,
+                                                 nullptr, /* InSet */ false, /* IsCond */ true);
+
+  // Record the current value.
+  Res = Value.getConstant();
+
+  return IsRelocatable && Value.isAbsolute();
+}
+
 bool MCExpr::evaluateKnownAbsolute(int64_t &Res,
                                    const MCAsmLayout &Layout) const {
   return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr,
@@ -498,8 +520,8 @@
     return true;
   }
 
-  bool IsRelocatable =
-      evaluateAsRelocatableImpl(Value, Asm, Layout, nullptr, Addrs, InSet);
+  bool IsRelocatable = evaluateAsRelocatableImpl(Value, Asm, Layout, nullptr,
+                                                 Addrs, InSet, /* IsCond */ false);
 
   // Record the current value.
   Res = Value.getConstant();
@@ -511,7 +533,7 @@
 static void AttemptToFoldSymbolOffsetDifference(
     const MCAssembler *Asm, const MCAsmLayout *Layout,
     const SectionAddrMap *Addrs, bool InSet, const MCSymbolRefExpr *&A,
-    const MCSymbolRefExpr *&B, int64_t &Addend) {
+    const MCSymbolRefExpr *&B, int64_t &Addend, bool IsCond) {
   if (!A || !B)
     return;
 
@@ -524,10 +546,7 @@
   if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet))
     return;
 
-  if (SA.getFragment() == SB.getFragment() && !SA.isVariable() &&
-      !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) {
-    Addend += (SA.getOffset() - SB.getOffset());
-
+  auto FinalizeFolding = [&]() {
     // Pointers to Thumb symbols need to have their low-bit set to allow
     // for interworking.
     if (Asm->isThumbFunc(&SA))
@@ -541,37 +560,53 @@
     // Clear the symbol expr pointers to indicate we have folded these
     // operands.
     A = B = nullptr;
-    return;
-  }
+  };
 
-  if (!Layout)
+  const MCFragment *FragA = SA.getFragment();
+  const MCFragment *FragB = SB.getFragment();
+  // If both symbols are in the same fragment, return the difference of their
+  // offsets
+  if (FragA == FragB && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() &&
+      !SB.isUnset()) {
+
+    Addend += (SA.getOffset() - SB.getOffset());
+
+    FinalizeFolding();
     return;
+  }
 
-  const MCSection &SecA = *SA.getFragment()->getParent();
-  const MCSection &SecB = *SB.getFragment()->getParent();
+  const MCSection &SecA = *FragA->getParent();
+  const MCSection &SecB = *FragB->getParent();
 
   if ((&SecA != &SecB) && !Addrs)
     return;
 
+  if (!Layout) {
+    // When there is no layout our ability to resolve differences between symbols is
+    // limited. In specific cases where the symbols are both defined in consecutive
+    // MCDataFragments the difference can be calculated. This is important for an
+    // idiom like foo:instr; .if . - foo; instr; .endif
+    // We cannot handle any kind of case where the difference may change due to
+    // layout.
+    // FIXME: can we resolve .if conditions while finalizing layout?
+    if (IsCond && SecB.getFragmentList().getNextNode(*FragB) == FragA &&
+        isa<MCDataFragment>(FragA) && isa<MCDataFragment>(FragB)) {
+      Addend += (SA.getOffset() +
+                 (cast<MCDataFragment>(FragB))->getContents().size() -
+                 SB.getOffset());
+
+      FinalizeFolding();
+    }
+    return;
+  }
+
   // Eagerly evaluate.
   Addend += Layout->getSymbolOffset(A->getSymbol()) -
             Layout->getSymbolOffset(B->getSymbol());
   if (Addrs && (&SecA != &SecB))
     Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB));
 
-  // Pointers to Thumb symbols need to have their low-bit set to allow
-  // for interworking.
-  if (Asm->isThumbFunc(&SA))
-    Addend |= 1;
-
-  // If symbol is labeled as micromips, we set low-bit to ensure
-  // correct offset in .gcc_except_table
-  if (Asm->getBackend().isMicroMips(&SA))
-    Addend |= 1;
-
-  // Clear the symbol expr pointers to indicate we have folded these
-  // operands.
-  A = B = nullptr;
+  FinalizeFolding();
 }
 
 static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A,
@@ -615,7 +650,7 @@
 EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout,
                     const SectionAddrMap *Addrs, bool InSet, const MCValue &LHS,
                     const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B,
-                    int64_t RHS_Cst, MCValue &Res) {
+                    int64_t RHS_Cst, MCValue &Res, bool IsCond) {
   // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy
   // about dealing with modifiers. This will ultimately bite us, one day.
   const MCSymbolRefExpr *LHS_A = LHS.getSymA();
@@ -644,13 +679,13 @@
     // Since we are attempting to be as aggressive as possible about folding, we
     // attempt to evaluate each possible alternative.
     AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B,
-                                        Result_Cst);
+                                        Result_Cst, IsCond);
     AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B,
-                                        Result_Cst);
+                                        Result_Cst, IsCond);
     AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B,
-                                        Result_Cst);
+                                        Result_Cst, IsCond);
     AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B,
-                                        Result_Cst);
+                                        Result_Cst, IsCond);
   }
 
   // We can't represent the addition or subtraction of two symbols.
@@ -671,13 +706,13 @@
                                    const MCFixup *Fixup) const {
   MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr;
   return evaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr,
-                                   false);
+                                   /* InSet */ false, /* IsCond */ false);
 }
 
 bool MCExpr::evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const {
   MCAssembler *Assembler = &Layout.getAssembler();
   return evaluateAsRelocatableImpl(Res, Assembler, &Layout, nullptr, nullptr,
-                                   true);
+                                   /* InSet */ true, /* IsCond */ false);
 }
 
 static bool canExpand(const MCSymbol &Sym, bool InSet) {
@@ -696,8 +731,8 @@
 bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
                                        const MCAsmLayout *Layout,
                                        const MCFixup *Fixup,
-                                       const SectionAddrMap *Addrs,
-                                       bool InSet) const {
+                                       const SectionAddrMap *Addrs, bool InSet,
+                                       bool IsCond) const {
   ++stats::MCExprEvaluate;
 
   switch (getKind()) {
@@ -718,7 +753,7 @@
         canExpand(Sym, InSet)) {
       bool IsMachO = SRE->hasSubsectionsViaSymbols();
       if (Sym.getVariableValue()->evaluateAsRelocatableImpl(
-              Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO)) {
+              Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO, IsCond)) {
         if (!IsMachO)
           return true;
 
@@ -748,7 +783,7 @@
     MCValue Value;
 
     if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, Layout, Fixup,
-                                                      Addrs, InSet))
+                                                      Addrs, InSet, IsCond))
       return false;
 
     switch (AUE->getOpcode()) {
@@ -784,9 +819,9 @@
     MCValue LHSValue, RHSValue;
 
     if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup,
-                                                  Addrs, InSet) ||
+                                                  Addrs, InSet, IsCond) ||
         !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup,
-                                                  Addrs, InSet)) {
+                                                  Addrs, InSet, IsCond)) {
       // Check if both are Target Expressions, see if we can compare them.
       if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(ABE->getLHS()))
         if (const MCTargetExpr *R = cast<MCTargetExpr>(ABE->getRHS())) {
@@ -812,14 +847,14 @@
       case MCBinaryExpr::Sub:
         // Negate RHS and add.
         // The cast avoids undefined behavior if the constant is INT64_MIN.
-        return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
-                                   RHSValue.getSymB(), RHSValue.getSymA(),
-                                   -(uint64_t)RHSValue.getConstant(), Res);
+        return EvaluateSymbolicAdd(
+            Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymB(),
+            RHSValue.getSymA(), -(uint64_t)RHSValue.getConstant(), Res, IsCond);
 
       case MCBinaryExpr::Add:
         return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
                                    RHSValue.getSymA(), RHSValue.getSymB(),
-                                   RHSValue.getConstant(), Res);
+                                   RHSValue.getConstant(), Res, IsCond);
       }
     }
 
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -254,6 +254,7 @@
   bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,
                              SMLoc &EndLoc) override;
   bool parseAbsoluteExpression(int64_t &Res) override;
+  bool parseAbsoluteIfCond(int64_t &Res);
 
   /// Parse a floating point expression using the float \p Semantics
   /// and set \p Res to the value.
@@ -1485,6 +1486,19 @@
   return false;
 }
 
+bool AsmParser::parseAbsoluteIfCond(int64_t &Res) {
+  const MCExpr *Expr;
+
+  SMLoc StartLoc = Lexer.getLoc();
+  if (parseExpression(Expr))
+    return true;
+
+  if (!Expr->evaluateIfCondAsAbsolute(Res, getStreamer().getAssemblerPtr()))
+    return Error(StartLoc, "expected absolute expression");
+
+  return false;
+}
+
 static unsigned getDarwinBinOpPrecedence(AsmToken::TokenKind K,
                                          MCBinaryExpr::Opcode &Kind,
                                          bool ShouldUseLogicalShr) {
@@ -5040,7 +5054,7 @@
     eatToEndOfStatement();
   } else {
     int64_t ExprValue;
-    if (parseAbsoluteExpression(ExprValue) ||
+    if (parseAbsoluteIfCond(ExprValue) ||
         parseToken(AsmToken::EndOfStatement,
                    "unexpected token in '.if' directive"))
       return true;
diff --git a/llvm/test/MC/ARM/directive_if_offset.s b/llvm/test/MC/ARM/directive_if_offset.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/ARM/directive_if_offset.s
@@ -0,0 +1,12 @@
+@ RUN: llvm-mc -triple armv7a-linux-gnueabihf %s -filetype=obj -o /dev/null 2>&1 | FileCheck --allow-empty %s
+@ RUN: llvm-mc -triple armv7a-linux-gnueabihf %s -filetype=obj -o %t | llvm-objdump -d %t | FileCheck --check-prefix=CHECK-ASM %s
+
+nop
+.arch_extension sec
+9997:
+.if . - 9997b == 0 ;
+// CHECK-NOT: error: expected absolute expression
+orr r1, r1, #1 ;
+.else ; orr r1, r1, #2;
+.endif;
+// CHECK-ASM: orr r1, r1, #1
diff --git a/llvm/test/MC/ARM/directive_if_offset_error.s b/llvm/test/MC/ARM/directive_if_offset_error.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/ARM/directive_if_offset_error.s
@@ -0,0 +1,15 @@
+@ RUN: not llvm-mc -filetype=obj -triple arm-linux-gnueabihf %s -o /dev/null 2>&1 | FileCheck %s
+
+9997: nop ;
+      .align 4
+      nop
+.if . - 9997b == 4 ;
+// CHECK: error: expected absolute expression
+.endif
+
+9997: nop ;
+      .space 4
+      nop
+.if . - 9997b == 4 ;
+// CHECK: error: expected absolute expression
+.endif