[llvm] r199707 - ARM IAS: add support for .unwind_raw directive

Saleem Abdulrasool compnerd at compnerd.org
Mon Jan 20 18:33:10 PST 2014


Author: compnerd
Date: Mon Jan 20 20:33:10 2014
New Revision: 199707

URL: http://llvm.org/viewvc/llvm-project?rev=199707&view=rev
Log:
ARM IAS: add support for .unwind_raw directive

This implements the unwind_raw directive for the ARM IAS.  The unwind_raw
directive takes the form of a stack offset value followed by one or more bytes
representing the opcodes to be emitted.  The opcode emitted will interpreted as
if it were assembled by the opcode assembler via the standard unwinding
directives.

Thanks to Logan Chien for an extra test!

Added:
    llvm/trunk/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s
    llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s
Modified:
    llvm/trunk/include/llvm/MC/MCStreamer.h
    llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
    llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
    llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h

Modified: llvm/trunk/include/llvm/MC/MCStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCStreamer.h?rev=199707&r1=199706&r2=199707&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCStreamer.h Mon Jan 20 20:33:10 2014
@@ -92,6 +92,8 @@ public:
   virtual void emitPad(int64_t Offset) = 0;
   virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
                            bool isVector) = 0;
+  virtual void emitUnwindRaw(int64_t StackOffset,
+                             const SmallVectorImpl<uint8_t> &Opcodes) = 0;
 
   virtual void switchVendor(StringRef Vendor) = 0;
   virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0;

Modified: llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp?rev=199707&r1=199706&r2=199707&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Mon Jan 20 20:33:10 2014
@@ -295,6 +295,7 @@ class ARMAsmParser : public MCTargetAsmP
   bool parseDirectiveLtorg(SMLoc L);
   bool parseDirectiveEven(SMLoc L);
   bool parseDirectivePersonalityIndex(SMLoc L);
+  bool parseDirectiveUnwindRaw(SMLoc L);
 
   StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
                           bool &CarrySetting, unsigned &ProcessorIMod,
@@ -8081,6 +8082,8 @@ bool ARMAsmParser::ParseDirective(AsmTok
     return parseDirectiveEven(DirectiveID.getLoc());
   else if (IDVal == ".personalityindex")
     return parseDirectivePersonalityIndex(DirectiveID.getLoc());
+  else if (IDVal == ".unwind_raw")
+    return parseDirectiveUnwindRaw(DirectiveID.getLoc());
   return true;
 }
 
@@ -8915,6 +8918,87 @@ bool ARMAsmParser::parseDirectivePersona
   return false;
 }
 
+/// parseDirectiveUnwindRaw
+///   ::= .unwind_raw offset, opcode [, opcode...]
+bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) {
+  if (!UC.hasFnStart()) {
+    Parser.eatToEndOfStatement();
+    Error(L, ".fnstart must precede .unwind_raw directives");
+    return false;
+  }
+
+  int64_t StackOffset;
+
+  const MCExpr *OffsetExpr;
+  SMLoc OffsetLoc = getLexer().getLoc();
+  if (getLexer().is(AsmToken::EndOfStatement) ||
+      getParser().parseExpression(OffsetExpr)) {
+    Error(OffsetLoc, "expected expression");
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+
+  const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
+  if (!CE) {
+    Error(OffsetLoc, "offset must be a constant");
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+
+  StackOffset = CE->getValue();
+
+  if (getLexer().isNot(AsmToken::Comma)) {
+    Error(getLexer().getLoc(), "expected comma");
+    Parser.eatToEndOfStatement();
+    return false;
+  }
+  Parser.Lex();
+
+  SmallVector<uint8_t, 16> Opcodes;
+  for (;;) {
+    const MCExpr *OE;
+
+    SMLoc OpcodeLoc = getLexer().getLoc();
+    if (getLexer().is(AsmToken::EndOfStatement) || Parser.parseExpression(OE)) {
+      Error(OpcodeLoc, "expected opcode expression");
+      Parser.eatToEndOfStatement();
+      return false;
+    }
+
+    const MCConstantExpr *OC = dyn_cast<MCConstantExpr>(OE);
+    if (!OC) {
+      Error(OpcodeLoc, "opcode value must be a constant");
+      Parser.eatToEndOfStatement();
+      return false;
+    }
+
+    const int64_t Opcode = OC->getValue();
+    if (Opcode & ~0xff) {
+      Error(OpcodeLoc, "invalid opcode");
+      Parser.eatToEndOfStatement();
+      return false;
+    }
+
+    Opcodes.push_back(uint8_t(Opcode));
+
+    if (getLexer().is(AsmToken::EndOfStatement))
+      break;
+
+    if (getLexer().isNot(AsmToken::Comma)) {
+      Error(getLexer().getLoc(), "unexpected token in directive");
+      Parser.eatToEndOfStatement();
+      return false;
+    }
+
+    Parser.Lex();
+  }
+
+  getTargetStreamer().emitUnwindRaw(StackOffset, Opcodes);
+
+  Parser.Lex();
+  return false;
+}
+
 /// Force static initialization.
 extern "C" void LLVMInitializeARMAsmParser() {
   RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);

Modified: llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp?rev=199707&r1=199706&r2=199707&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp (original)
+++ llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp Mon Jan 20 20:33:10 2014
@@ -123,6 +123,8 @@ class ARMTargetAsmStreamer : public ARMT
   virtual void emitPad(int64_t Offset);
   virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
                            bool isVector);
+  virtual void emitUnwindRaw(int64_t Offset,
+                             const SmallVectorImpl<uint8_t> &Opcodes);
 
   virtual void switchVendor(StringRef Vendor);
   virtual void emitAttribute(unsigned Attribute, unsigned Value);
@@ -242,6 +244,16 @@ void ARMTargetAsmStreamer::emitInst(uint
   OS << "\t0x" << utohexstr(Inst) << "\n";
 }
 
+void ARMTargetAsmStreamer::emitUnwindRaw(int64_t Offset,
+                                      const SmallVectorImpl<uint8_t> &Opcodes) {
+  OS << "\t.unwind_raw " << Offset;
+  for (SmallVectorImpl<uint8_t>::const_iterator OCI = Opcodes.begin(),
+                                                OCE = Opcodes.end();
+       OCI != OCE; ++OCI)
+    OS << ", 0x" << utohexstr(*OCI);
+  OS << '\n';
+}
+
 class ARMTargetELFStreamer : public ARMTargetStreamer {
 private:
   // This structure holds all attributes, accounting for
@@ -367,6 +379,8 @@ private:
   virtual void emitPad(int64_t Offset);
   virtual void emitRegSave(const SmallVectorImpl<unsigned> &RegList,
                            bool isVector);
+  virtual void emitUnwindRaw(int64_t Offset,
+                             const SmallVectorImpl<uint8_t> &Opcodes);
 
   virtual void switchVendor(StringRef Vendor);
   virtual void emitAttribute(unsigned Attribute, unsigned Value);
@@ -425,6 +439,7 @@ public:
   void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0);
   void emitPad(int64_t Offset);
   void emitRegSave(const SmallVectorImpl<unsigned> &RegList, bool isVector);
+  void emitUnwindRaw(int64_t Offset, const SmallVectorImpl<uint8_t> &Opcodes);
 
   virtual void ChangeSection(const MCSection *Section,
                              const MCExpr *Subsection) {
@@ -637,6 +652,10 @@ void ARMTargetELFStreamer::emitRegSave(c
                                        bool isVector) {
   getStreamer().emitRegSave(RegList, isVector);
 }
+void ARMTargetELFStreamer::emitUnwindRaw(int64_t Offset,
+                                      const SmallVectorImpl<uint8_t> &Opcodes) {
+  getStreamer().emitUnwindRaw(Offset, Opcodes);
+}
 void ARMTargetELFStreamer::switchVendor(StringRef Vendor) {
   assert(!Vendor.empty() && "Vendor cannot be empty.");
 
@@ -1202,6 +1221,13 @@ void ARMELFStreamer::emitRegSave(const S
     UnwindOpAsm.EmitRegSave(Mask);
 }
 
+void ARMELFStreamer::emitUnwindRaw(int64_t Offset,
+                                   const SmallVectorImpl<uint8_t> &Opcodes) {
+  FlushPendingOffset();
+  SPOffset = SPOffset - Offset;
+  UnwindOpAsm.EmitRaw(Opcodes);
+}
+
 namespace llvm {
 
 MCStreamer *createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,

Modified: llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h?rev=199707&r1=199706&r2=199707&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h (original)
+++ llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMUnwindOpAsm.h Mon Jan 20 20:33:10 2014
@@ -61,6 +61,12 @@ public:
   /// Emit unwind opcodes to add $sp with an offset.
   void EmitSPOffset(int64_t Offset);
 
+  /// Emit unwind raw opcodes
+  void EmitRaw(const SmallVectorImpl<uint8_t> &Opcodes) {
+    Ops.insert(Ops.end(), Opcodes.begin(), Opcodes.end());
+    OpBegins.push_back(OpBegins.back() + Opcodes.size());
+  }
+
   /// Finalize the unwind opcode sequence for EmitBytes()
   void Finalize(unsigned &PersonalityIndex,
                 SmallVectorImpl<uint8_t> &Result);

Added: llvm/trunk/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s?rev=199707&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s (added)
+++ llvm/trunk/test/MC/ARM/eh-directive-unwind_raw-diagnostics.s Mon Jan 20 20:33:10 2014
@@ -0,0 +1,73 @@
+@ RUN: not llvm-mc -triple armv7-linux-eabi -filetype asm -o /dev/null 2>&1 %s \
+@ RUN:   | FileCheck %s
+
+	.syntax unified
+
+	.type require_fnstart,%function
+require_fnstart:
+	.unwind_raw 0, 0
+
+@ CHECK: error: .fnstart must precede .unwind_raw directive
+@ CHECK: 	.unwind_raw 0, 0
+@ CHECK:        ^
+
+	.type check_arguments,%function
+check_arguments:
+	.fnstart
+	.unwind_raw
+	.fnend
+
+@ CHECK: error: expected expression
+@ CHECK: 	.unwind_raw
+@ CHECK:                   ^
+
+	.type check_stack_offset,%function
+check_stack_offset:
+	.fnstart
+	.unwind_raw ., 0
+	.fnend
+
+@ CHECK: error: offset must be a constant
+@ CHECK: 	.unwind_raw ., 0
+@ CHECK:                    ^
+
+	.type comma_check,%function
+comma_check:
+	.fnstart
+	.unwind_raw 0
+	.fnend
+
+@ CHECK: error: expected comma
+@ CHECK: 	.unwind_raw 0
+@ CHECK:                     ^
+
+	.type require_opcode,%function
+require_opcode:
+	.fnstart
+	.unwind_raw 0,
+	.fnend
+
+@ CHECK: error: expected opcode expression
+@ CHECK: 	.unwind_raw 0,
+@ CHECK:                      ^
+
+	.type require_opcode_constant,%function
+require_opcode_constant:
+	.fnstart
+	.unwind_raw 0, .
+	.fnend
+
+@ CHECK: error: opcode value must be a constant
+@ CHECK: 	.unwind_raw 0, .
+@ CHECK:                       ^
+
+	.type check_opcode_range,%function
+check_opcode_range:
+	.fnstart
+	.unwind_raw 0, 0x100
+	.fnend
+
+@ CHECK: error: invalid opcode
+@ CHECK: 	.unwind_raw 0, 0x100
+@ CHECK:                       ^
+

Added: llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s?rev=199707&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s (added)
+++ llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s Mon Jan 20 20:33:10 2014
@@ -0,0 +1,113 @@
+@ RUN: llvm-mc -triple armv7-linux-eabi -filetype obj -o - %s | llvm-readobj -u \
+@ RUN:   | FileCheck %s
+
+	.syntax unified
+
+	.type save,%function
+	.thumb_func
+save:
+	.fnstart
+	.unwind_raw 4, 0xb1, 0x01
+	push {r0}
+	pop {r0}
+	bx lr
+	.fnend
+
+	.type empty,%function
+	.thumb_func
+empty:
+	.fnstart
+	.unwind_raw 0, 0xb0
+	bx lr
+	.fnend
+
+	.type extended,%function
+	.thumb_func
+extended:
+	.fnstart
+	.unwind_raw 12, 0x9b, 0x40, 0x84, 0x80, 0xb0, 0xb0
+	@ .save {fp, lr}
+	stmfd sp!, {fp, lr}
+	@ .setfp fp, sp, #4
+	add fp, sp, #4
+	@ .pad #8
+	sub sp, sp, #8
+	add sp, sp, #8
+	sub fp, sp, #4
+	ldmfd sp!, {fp, lr}
+	bx lr
+	.fnend
+
+	.type refuse,%function
+	.thumb_func
+refuse:
+	.fnstart
+	.unwind_raw 0, 0x80, 0x00
+	bx lr
+	.fnend
+
+	.type stack_adjust,%function
+	.thumb_func
+stack_adjust:
+	.fnstart
+	.setfp fp, sp, #32
+	.unwind_raw 24, 0xc2
+	.fnend
+
+@ CHECK: UnwindInformation {
+@ CHECK:   UnwindIndexTable {
+@ CHECK:     SectionName: .ARM.exidx
+@ CHECK:     Entries [
+@ CHECK:       Entry {
+@ CHECK:         Model: Compact (Inline)
+@ CHECK:         PersonalityIndex: 0
+@ CHECK:         Opcodes [
+@ CHECK:           Opcode: 0xB1
+@ CHECK:           Opcode: 0x1
+@ CHECK:           Opcode: 0xB0
+@ CHECK:         ]
+@ CHECK:       }
+@ CHECK:       Entry {
+@ CHECK:         Model: Compact (Inline)
+@ CHECK:         PersonalityIndex: 0
+@ CHECK:         Opcodes [
+@ CHECK:           Opcode: 0xB0
+@ CHECK:           Opcode: 0xB0
+@ CHECK:           Opcode: 0xB0
+@ CHECK:         ]
+@ CHECK:       }
+@ CHECK:       Entry {
+@ CHECK:         ExceptionHandlingTable: .ARM.extab
+@ CHECK:         Model: Compact
+@ CHECK:         PersonalityIndex: 1
+@ CHECK:         Opcodes [
+@ CHECK:           Opcode: 0x9B
+@ CHECK:           Opcode: 0x40
+@ CHECK:           Opcode: 0x84
+@ CHECK:           Opcode: 0x80
+@ CHECK:           Opcode: 0xB0
+@ CHECK:           Opcode: 0xB0
+@ CHECK:         ]
+@ CHECK:       }
+@ CHECK:       Entry {
+@ CHECK:         Model: Compact (Inline)
+@ CHECK:         PersonalityIndex: 0
+@ CHECK:         Opcodes [
+@ CHECK:           Opcode: 0x80
+@ CHECK:           Opcode: 0x0
+@ CHECK:           Opcode: 0xB0
+@ CHECK:         ]
+@ CHECK:       }
+@ CHECK:       Entry {
+@ CHECK:         Model: Compact (Inline)
+@ CHECK:         PersonalityIndex: 0
+@ CHECK:         Opcodes [
+@ CHECK:           Opcode: 0x9B
+@ CHECK:           Opcode: 0x4D
+@ CHECK:           Opcode: 0xC2
+@ CHECK:         ]
+@ CHECK:       }
+@ CHECK:     ]
+@ CHECK:   }
+@ CHECK: }
+





More information about the llvm-commits mailing list