From 7a38b33decb80eff92060b7ad95ff1b877f685c3 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 30 Jan 2014 04:46:24 +0000 Subject: [PATCH] ARM IAS: support .movsp .movsp is an ARM unwinding directive that indicates to the unwinder that a register contains an offset from the current stack pointer. If the offset is unspecified, it defaults to zero. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200449 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCStreamer.h | 1 + lib/Target/ARM/ARMAsmPrinter.cpp | 6 +- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 72 ++++++++++++- .../ARM/MCTargetDesc/ARMELFStreamer.cpp | 30 ++++++ test/MC/ARM/eh-directive-movsp-diagnostics.s | 102 ++++++++++++++++++ test/MC/ARM/eh-directive-movsp.s | 44 ++++++++ 6 files changed, 249 insertions(+), 6 deletions(-) create mode 100644 test/MC/ARM/eh-directive-movsp-diagnostics.s create mode 100644 test/MC/ARM/eh-directive-movsp.s diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index bb4adfcf862..f272572bb62 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -93,6 +93,7 @@ public: virtual void emitHandlerData() = 0; virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0) = 0; + virtual void emitMovSP(unsigned Reg, int64_t Offset = 0) = 0; virtual void emitPad(int64_t Offset) = 0; virtual void emitRegSave(const SmallVectorImpl &RegList, bool isVector) = 0; diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 46bd34fe392..d0aad327c40 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -1091,11 +1091,11 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) { // instruction. ATS.emitPad(Offset); } else { - MI->dump(); - llvm_unreachable("Unsupported opcode for unwinding information"); + // Move of SP to a register. Positive values correspond to an "add" + // instruction. + ATS.emitMovSP(DstReg, -Offset); } } else if (DstReg == ARM::SP) { - // FIXME: .movsp goes here MI->dump(); llvm_unreachable("Unsupported opcode for unwinding information"); } diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 2b4eaf0f15c..531e2cc906a 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -127,7 +127,7 @@ class UnwindContext { int FPReg; public: - UnwindContext(MCAsmParser &P) : Parser(P), FPReg(-1) {} + UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {} bool hasFnStart() const { return !FnStartLocs.empty(); } bool cantUnwind() const { return !CantUnwindLocs.empty(); } @@ -182,7 +182,7 @@ public: PersonalityLocs = Locs(); HandlerDataLocs = Locs(); PersonalityIndexLocs = Locs(); - FPReg = -1; + FPReg = ARM::SP; } }; @@ -297,6 +297,7 @@ class ARMAsmParser : public MCTargetAsmParser { bool parseDirectivePersonalityIndex(SMLoc L); bool parseDirectiveUnwindRaw(SMLoc L); bool parseDirectiveTLSDescSeq(SMLoc L); + bool parseDirectiveMovSP(SMLoc L); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -8087,6 +8088,8 @@ bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { return parseDirectiveUnwindRaw(DirectiveID.getLoc()); else if (IDVal == ".tlsdescseq") return parseDirectiveTLSDescSeq(DirectiveID.getLoc()); + else if (IDVal == ".movsp") + return parseDirectiveMovSP(DirectiveID.getLoc()); return true; } @@ -8616,7 +8619,7 @@ bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) { } // Consume comma - if (!Parser.getTok().is(AsmToken::Comma)) { + if (Parser.getTok().isNot(AsmToken::Comma)) { Error(Parser.getTok().getLoc(), "comma expected"); return false; } @@ -9028,6 +9031,69 @@ bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) { return false; } +/// parseDirectiveMovSP +/// ::= .movsp reg [, #offset] +bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) { + if (!UC.hasFnStart()) { + Parser.eatToEndOfStatement(); + Error(L, ".fnstart must precede .movsp directives"); + return false; + } + if (UC.getFPReg() != ARM::SP) { + Parser.eatToEndOfStatement(); + Error(L, "unexpected .movsp directive"); + return false; + } + + SMLoc SPRegLoc = Parser.getTok().getLoc(); + int SPReg = tryParseRegister(); + if (SPReg == -1) { + Parser.eatToEndOfStatement(); + Error(SPRegLoc, "register expected"); + return false; + } + + if (SPReg == ARM::SP || SPReg == ARM::PC) { + Parser.eatToEndOfStatement(); + Error(SPRegLoc, "sp and pc are not permitted in .movsp directive"); + return false; + } + + int64_t Offset = 0; + if (Parser.getTok().is(AsmToken::Comma)) { + Parser.Lex(); + + if (Parser.getTok().isNot(AsmToken::Hash)) { + Error(Parser.getTok().getLoc(), "expected #constant"); + Parser.eatToEndOfStatement(); + return false; + } + Parser.Lex(); + + const MCExpr *OffsetExpr; + SMLoc OffsetLoc = Parser.getTok().getLoc(); + if (Parser.parseExpression(OffsetExpr)) { + Parser.eatToEndOfStatement(); + Error(OffsetLoc, "malformed offset expression"); + return false; + } + + const MCConstantExpr *CE = dyn_cast(OffsetExpr); + if (!CE) { + Parser.eatToEndOfStatement(); + Error(OffsetLoc, "offset must be an immediate constant"); + return false; + } + + Offset = CE->getValue(); + } + + getTargetStreamer().emitMovSP(SPReg, Offset); + UC.saveFPReg(SPReg); + + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterMCAsmParser X(TheARMTarget); diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index c2e3503278b..151d48df63e 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -123,6 +123,7 @@ class ARMTargetAsmStreamer : public ARMTargetStreamer { virtual void emitPersonalityIndex(unsigned Index); virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0); + virtual void emitMovSP(unsigned Reg, int64_t Offset = 0); virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl &RegList, bool isVector); @@ -172,6 +173,16 @@ void ARMTargetAsmStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, OS << ", #" << Offset; OS << '\n'; } +void ARMTargetAsmStreamer::emitMovSP(unsigned Reg, int64_t Offset) { + assert((Reg != ARM::SP && Reg != ARM::PC) && + "the operand of .movsp cannot be either sp or pc"); + + OS << "\t.movsp\t"; + InstPrinter.printRegName(OS, Reg); + if (Offset) + OS << ", #" << Offset; + OS << '\n'; +} void ARMTargetAsmStreamer::emitPad(int64_t Offset) { OS << "\t.pad\t#" << Offset << '\n'; } @@ -387,6 +398,7 @@ private: virtual void emitPersonalityIndex(unsigned Index); virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset = 0); + virtual void emitMovSP(unsigned Reg, int64_t Offset = 0); virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl &RegList, bool isVector); @@ -448,6 +460,7 @@ public: void emitPersonalityIndex(unsigned index); void emitHandlerData(); void emitSetFP(unsigned NewFpReg, unsigned NewSpReg, int64_t Offset = 0); + void emitMovSP(unsigned Reg, int64_t Offset = 0); void emitPad(int64_t Offset); void emitRegSave(const SmallVectorImpl &RegList, bool isVector); void emitUnwindRaw(int64_t Offset, const SmallVectorImpl &Opcodes); @@ -657,6 +670,9 @@ void ARMTargetELFStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, int64_t Offset) { getStreamer().emitSetFP(FpReg, SpReg, Offset); } +void ARMTargetELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) { + getStreamer().emitMovSP(Reg, Offset); +} void ARMTargetELFStreamer::emitPad(int64_t Offset) { getStreamer().emitPad(Offset); } @@ -1203,6 +1219,20 @@ void ARMELFStreamer::emitSetFP(unsigned NewFPReg, unsigned NewSPReg, FPOffset += Offset; } +void ARMELFStreamer::emitMovSP(unsigned Reg, int64_t Offset) { + assert((Reg != ARM::SP && Reg != ARM::PC) && + "the operand of .movsp cannot be either sp or pc"); + assert(FPReg == ARM::SP && "current FP must be SP"); + + FlushPendingOffset(); + + FPReg = Reg; + FPOffset = SPOffset + Offset; + + const MCRegisterInfo *MRI = getContext().getRegisterInfo(); + UnwindOpAsm.EmitSetSP(MRI->getEncodingValue(FPReg)); +} + void ARMELFStreamer::emitPad(int64_t Offset) { // Track the change of the $sp offset SPOffset -= Offset; diff --git a/test/MC/ARM/eh-directive-movsp-diagnostics.s b/test/MC/ARM/eh-directive-movsp-diagnostics.s new file mode 100644 index 00000000000..519e7d742f3 --- /dev/null +++ b/test/MC/ARM/eh-directive-movsp-diagnostics.s @@ -0,0 +1,102 @@ +@ RUN: not llvm-mc -triple armv7-eabi -filetype asm -o /dev/null 2>&1 %s \ +@ RUN: | FileCheck %s + + .syntax unified + .thumb + + .global false_start + .type false_start,%function + .thumb_func +false_start: + .movsp r7 + +@ CHECK: error: .fnstart must precede .movsp directive +@ CHECK: .movsp r7 +@ CHECK: ^ + + .global beyond_saving + .type beyond_saving,%function + .thumb_func +beyond_saving: + .fnstart + .setfp r11, sp, #8 + add r11, sp, #8 + .movsp r7 + mov r7, r11 + .fnend + +@ CHECK: error: unexpected .movsp directive +@ CHECK: .movsp r7 +@ CHECK: ^ + + + .global sp_invalid + .type sp_invalid,%function + .thumb_func +sp_invalid: + .fnstart + .movsp r13 + mov sp, sp + .fnend + +@ CHECK: error: sp and pc are not permitted in .movsp directive +@ CHECK: .movsp r13 +@ CHECK: ^ + + + .global pc_invalid + .type pc_invalid,%function + .thumb_func +pc_invalid: + .fnstart + .movsp r15 + mov sp, pc + .fnend + +@ CHECK: error: sp and pc are not permitted in .movsp directive +@ CHECK: .movsp r15 +@ CHECK: ^ + + + .global constant_required + .type constant_required,%function + .thumb_func +constant_required: + .fnstart + .movsp r11, + mov sp, r11 + .fnend + +@ CHECK: error: expected #constant +@ CHECK: .movsp r11, +@ CHECK: ^ + + + .global constant_constant + .type constant_constant,%function + .thumb_func +constant_constant: + .fnstart + .movsp r11, #constant + mov sp, r11 + .fnend + +@ CHECK: error: offset must be an immediate constant +@ CHECK: .movsp r11, #constant +@ CHECK: ^ + + + .arm + + .global register_required + .type register_required,%function +register_required: + .fnstart + .movsp #42 + mov sp, #42 + .fnend + +@ CHECK: error: register expected +@ CHECK: .movsp #42 +@ CHECK: ^ + diff --git a/test/MC/ARM/eh-directive-movsp.s b/test/MC/ARM/eh-directive-movsp.s new file mode 100644 index 00000000000..620f5b769d4 --- /dev/null +++ b/test/MC/ARM/eh-directive-movsp.s @@ -0,0 +1,44 @@ +@ RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s | llvm-readobj -s -sd \ +@ RUN: | FileCheck %s + + .syntax unified + .thumb + + .section .duplicate + + .global duplicate + .type duplicate,%function +duplicate: + .fnstart + .setfp sp, sp, #8 + add sp, sp, #8 + .movsp r11 + mov r11, sp + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.duplicate +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 B09B9B80 +@ CHECK: ) +@ CHECK: } + + + .section .squash + + .global squash + .type squash,%function +squash: + .fnstart + .movsp ip + mov ip, sp + .save {fp, ip, lr} + stmfd sp!, {fp, ip, lr} + .fnend + +@ CHECK: Section { +@ CHECK: Name: .ARM.exidx.squash +@ CHECK: SectionData ( +@ CHECK: 0000: 00000000 9C808580 +@ CHECK: ) +@ CHECK: } -- 2.34.1