From 7a38b33decb80eff92060b7ad95ff1b877f685c3 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 30 Jan 2014 04:46:24 +0000 Subject: 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 --- lib/Target/ARM/ARMAsmPrinter.cpp | 6 +-- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 72 ++++++++++++++++++++++++-- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 30 +++++++++++ 3 files changed, 102 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 46bd34fe39..d0aad327c4 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 2b4eaf0f15..531e2cc906 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 c2e3503278..151d48df63 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; -- cgit v1.2.3