Implement cfi_rel_offset

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@129306 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 5eb772e..8af4ac6 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -80,6 +80,10 @@
   SourceMgr &SrcMgr;
   MCAsmParserExtension *GenericParser;
   MCAsmParserExtension *PlatformParser;
+
+  // FIXME: This is not the best place to store this. To handle a (for example)
+  // .cfi_rel_offset before a .cfi_def_cfa_offset we need to know the initial
+  // frame state.
   int64_t LastOffset;
 
   /// This is the current buffer index we're lexing from as managed by the
@@ -145,6 +149,9 @@
     LastOffset += Adjustment;
     return LastOffset;
   }
+  int64_t getLastOffset() {
+    return LastOffset;
+  }
   void setLastOffset(int64_t Offset) {
     LastOffset = Offset;
   }
@@ -266,6 +273,8 @@
                                                        ".cfi_def_cfa_register");
     AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIOffset>(
                                                                  ".cfi_offset");
+    AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIRelOffset>(
+                                                             ".cfi_rel_offset");
     AddDirectiveHandler<
      &GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda>(".cfi_personality");
     AddDirectiveHandler<
@@ -301,6 +310,7 @@
   bool ParseDirectiveCFIAdjustCfaOffset(StringRef, SMLoc DirectiveLoc);
   bool ParseDirectiveCFIDefCfaRegister(StringRef, SMLoc DirectiveLoc);
   bool ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc);
+  bool ParseDirectiveCFIRelOffset(StringRef, SMLoc DirectiveLoc);
   bool ParseDirectiveCFIPersonalityOrLsda(StringRef, SMLoc DirectiveLoc);
   bool ParseDirectiveCFIRememberState(StringRef, SMLoc DirectiveLoc);
   bool ParseDirectiveCFIRestoreState(StringRef, SMLoc DirectiveLoc);
@@ -2351,7 +2361,7 @@
 }
 
 /// ParseDirectiveCFIOffset
-/// ::= .cfi_off register, offset
+/// ::= .cfi_offset register, offset
 bool GenericAsmParser::ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc) {
   int64_t Register = 0;
   int64_t Offset = 0;
@@ -2369,6 +2379,28 @@
   return getStreamer().EmitCFIOffset(Register, Offset);
 }
 
+/// ParseDirectiveCFIRelOffset
+/// ::= .cfi_rel_offset register, offset
+bool GenericAsmParser::ParseDirectiveCFIRelOffset(StringRef,
+                                                  SMLoc DirectiveLoc) {
+  int64_t Register = 0;
+
+  if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc))
+    return true;
+
+  if (getLexer().isNot(AsmToken::Comma))
+    return TokError("unexpected token in directive");
+  Lex();
+
+  int64_t Offset = 0;
+  if (getParser().ParseAbsoluteExpression(Offset))
+    return true;
+
+  Offset -= getParser().getLastOffset();
+
+  return getStreamer().EmitCFIOffset(Register, Offset);
+}
+
 static bool isValidEncoding(int64_t Encoding) {
   if (Encoding & ~0xff)
     return false;