From c24a374331fc97dd215937c8f0a9bf5271f39657 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Fri, 10 May 2013 16:17:24 +0000 Subject: Implement AsmParser for ARM unwind directives. This commit implements the AsmParser for fnstart, fnend, cantunwind, personality, handlerdata, pad, setfp, save, and vsave directives. This commit fixes some minor issue in the ARMELFStreamer: * The switch back to corresponding section after the .fnend directive. * Emit the unwind opcode while processing .fnend directive if there is no .handlerdata directive. * Emit the unwind opcode to .ARM.extab while processing .handlerdata even if .personality directive does not exist. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181603 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 56 ++++++++++++++------------ 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp') diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 6c3d247..82d296f 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -204,6 +204,7 @@ private: void EmitPersonalityFixup(StringRef Name); void CollectUnwindOpcodes(); + void FlushUnwindOpcodes(bool AllowCompactModel0); void SwitchToEHSection(const char *Prefix, unsigned Type, unsigned Flags, SectionKind Kind, const MCSymbol &Fn); @@ -333,22 +334,8 @@ void ARMELFStreamer::EmitFnEnd() { assert(FnStart && ".fnstart must preceeds .fnend"); // Emit unwind opcodes if there is no .handlerdata directive - if (!ExTab && !CantUnwind) { - CollectUnwindOpcodes(); - - unsigned PersonalityIndex = UnwindOpAsm.getPersonalityIndex(); - if (PersonalityIndex == AEABI_UNWIND_CPP_PR1 || - PersonalityIndex == AEABI_UNWIND_CPP_PR2) { - // For the __aeabi_unwind_cpp_pr1 and __aeabi_unwind_cpp_pr2, we have to - // emit the unwind opcodes in the corresponding ".ARM.extab" section, and - // then emit a reference to these unwind opcodes in the second word of - // the exception index table entry. - SwitchToExTabSection(*FnStart); - ExTab = getContext().CreateTempSymbol(); - EmitLabel(ExTab); - EmitBytes(UnwindOpAsm.data(), 0); - } - } + if (!ExTab && !CantUnwind) + FlushUnwindOpcodes(true); // Emit the exception index table entry SwitchToExIdxSection(*FnStart); @@ -384,6 +371,9 @@ void ARMELFStreamer::EmitFnEnd() { EmitBytes(UnwindOpAsm.data(), 0); } + // Switch to the section containing FnStart + SwitchSection(&FnStart->getSection()); + // Clean exception handling frame information Reset(); } @@ -392,7 +382,18 @@ void ARMELFStreamer::EmitCantUnwind() { CantUnwind = true; } -void ARMELFStreamer::EmitHandlerData() { +void ARMELFStreamer::FlushUnwindOpcodes(bool AllowCompactModel0) { + // Collect and finalize the unwind opcodes + CollectUnwindOpcodes(); + + // For compact model 0, we have to emit the unwind opcodes in the .ARM.exidx + // section. Thus, we don't have to create an entry in the .ARM.extab + // section. + if (AllowCompactModel0 && + UnwindOpAsm.getPersonalityIndex() == AEABI_UNWIND_CPP_PR0) + return; + + // Switch to .ARM.extab section. SwitchToExTabSection(*FnStart); // Create .ARM.extab label for offset in .ARM.exidx @@ -400,21 +401,24 @@ void ARMELFStreamer::EmitHandlerData() { ExTab = getContext().CreateTempSymbol(); EmitLabel(ExTab); - // Emit Personality - assert(Personality && ".personality directive must preceed .handlerdata"); - - const MCSymbolRefExpr *PersonalityRef = - MCSymbolRefExpr::Create(Personality, - MCSymbolRefExpr::VK_ARM_PREL31, - getContext()); + // Emit personality + if (Personality) { + const MCSymbolRefExpr *PersonalityRef = + MCSymbolRefExpr::Create(Personality, + MCSymbolRefExpr::VK_ARM_PREL31, + getContext()); - EmitValue(PersonalityRef, 4, 0); + EmitValue(PersonalityRef, 4, 0); + } // Emit unwind opcodes - CollectUnwindOpcodes(); EmitBytes(UnwindOpAsm.data(), 0); } +void ARMELFStreamer::EmitHandlerData() { + FlushUnwindOpcodes(false); +} + void ARMELFStreamer::EmitPersonality(const MCSymbol *Per) { Personality = Per; UnwindOpAsm.setPersonality(Per); -- cgit v1.1 From 18cba562c8016f8095643b5dd8c4b34b294b62dd Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Sun, 9 Jun 2013 12:22:30 +0000 Subject: Fix ARM unwind opcode assembler in several cases. Changes to ARM unwind opcode assembler: * Fix multiple .save or .vsave directives. Besides, the order is preserved now. * For the directives which will generate multiple opcodes, such as ".save {r0-r11}", the order of the unwind opcode is fixed now, i.e. the registers with less encoding value are popped first. * Fix the $sp offset calculation. Now, we can use the .setfp, .pad, .save, and .vsave directives at any order. Changes to test cases: * Add test cases to check the order of multiple opcodes for the .save directive. * Fix the incorrect $sp offset in the test case. The stack pointer offset specified in the test case was incorrect. (Changed test cases: ehabi-mc-section.ll and ehabi-mc.ll) * The opcode to restore $sp are slightly reordered. The behavior are not changed, and the new output is same as the output of GNU as. (Changed test cases: eh-directive-pad.s and eh-directive-setfp.s) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183627 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 124 ++++++++++++++----------- 1 file changed, 71 insertions(+), 53 deletions(-) (limited to 'lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp') diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 82d296f..d83567c 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -203,7 +203,7 @@ private: void Reset(); void EmitPersonalityFixup(StringRef Name); - void CollectUnwindOpcodes(); + void FlushPendingOffset(); void FlushUnwindOpcodes(bool AllowCompactModel0); void SwitchToEHSection(const char *Prefix, unsigned Type, unsigned Flags, @@ -221,13 +221,14 @@ private: MCSymbol *ExTab; MCSymbol *FnStart; const MCSymbol *Personality; - uint32_t VFPRegSave; // Register mask for {d31-d0} - uint32_t RegSave; // Register mask for {r15-r0} - int64_t SPOffset; - uint16_t FPReg; - int64_t FPOffset; + unsigned PersonalityIndex; + unsigned FPReg; // Frame pointer register + int64_t FPOffset; // Offset: (final frame pointer) - (initial $sp) + int64_t SPOffset; // Offset: (final $sp) - (initial $sp) + int64_t PendingOffset; // Offset: (final $sp) - (emitted $sp) bool UsedFP; bool CantUnwind; + SmallVector Opcodes; UnwindOpcodeAssembler UnwindOpAsm; }; } // end anonymous namespace @@ -280,19 +281,18 @@ inline void ARMELFStreamer::SwitchToExIdxSection(const MCSymbol &FnStart) { } void ARMELFStreamer::Reset() { - const MCRegisterInfo &MRI = getContext().getRegisterInfo(); - ExTab = NULL; FnStart = NULL; Personality = NULL; - VFPRegSave = 0; - RegSave = 0; - FPReg = MRI.getEncodingValue(ARM::SP); + PersonalityIndex = NUM_PERSONALITY_INDEX; + FPReg = ARM::SP; FPOffset = 0; SPOffset = 0; + PendingOffset = 0; UsedFP = false; CantUnwind = false; + Opcodes.clear(); UnwindOpAsm.Reset(); } @@ -312,18 +312,6 @@ void ARMELFStreamer::EmitPersonalityFixup(StringRef Name) { MCFixup::getKindForSize(4, false))); } -void ARMELFStreamer::CollectUnwindOpcodes() { - if (UsedFP) { - UnwindOpAsm.EmitSetFP(FPReg); - UnwindOpAsm.EmitSPOffset(-FPOffset); - } else { - UnwindOpAsm.EmitSPOffset(SPOffset); - } - UnwindOpAsm.EmitVFPRegSave(VFPRegSave); - UnwindOpAsm.EmitRegSave(RegSave); - UnwindOpAsm.Finalize(); -} - void ARMELFStreamer::EmitFnStart() { assert(FnStart == 0); FnStart = getContext().CreateTempSymbol(); @@ -340,7 +328,6 @@ void ARMELFStreamer::EmitFnEnd() { // Emit the exception index table entry SwitchToExIdxSection(*FnStart); - unsigned PersonalityIndex = UnwindOpAsm.getPersonalityIndex(); if (PersonalityIndex < NUM_PERSONALITY_INDEX) EmitPersonalityFixup(GetAEABIUnwindPersonalityName(PersonalityIndex)); @@ -366,9 +353,10 @@ void ARMELFStreamer::EmitFnEnd() { // opcodes should always be 4 bytes. assert(PersonalityIndex == AEABI_UNWIND_CPP_PR0 && "Compact model must use __aeabi_cpp_unwind_pr0 as personality"); - assert(UnwindOpAsm.size() == 4u && + assert(Opcodes.size() == 4u && "Unwind opcode size for __aeabi_cpp_unwind_pr0 must be equal to 4"); - EmitBytes(UnwindOpAsm.data(), 0); + EmitBytes(StringRef(reinterpret_cast(Opcodes.data()), + Opcodes.size()), 0); } // Switch to the section containing FnStart @@ -382,15 +370,31 @@ void ARMELFStreamer::EmitCantUnwind() { CantUnwind = true; } +void ARMELFStreamer::FlushPendingOffset() { + if (PendingOffset != 0) { + UnwindOpAsm.EmitSPOffset(-PendingOffset); + PendingOffset = 0; + } +} + void ARMELFStreamer::FlushUnwindOpcodes(bool AllowCompactModel0) { - // Collect and finalize the unwind opcodes - CollectUnwindOpcodes(); + // Emit the unwind opcode to restore $sp. + if (UsedFP) { + const MCRegisterInfo &MRI = getContext().getRegisterInfo(); + int64_t LastRegSaveSPOffset = SPOffset - PendingOffset; + UnwindOpAsm.EmitSPOffset(LastRegSaveSPOffset - FPOffset); + UnwindOpAsm.EmitSetSP(MRI.getEncodingValue(FPReg)); + } else { + FlushPendingOffset(); + } + + // Finalize the unwind opcode sequence + UnwindOpAsm.Finalize(PersonalityIndex, Opcodes); // For compact model 0, we have to emit the unwind opcodes in the .ARM.exidx // section. Thus, we don't have to create an entry in the .ARM.extab // section. - if (AllowCompactModel0 && - UnwindOpAsm.getPersonalityIndex() == AEABI_UNWIND_CPP_PR0) + if (AllowCompactModel0 && PersonalityIndex == AEABI_UNWIND_CPP_PR0) return; // Switch to .ARM.extab section. @@ -412,7 +416,8 @@ void ARMELFStreamer::FlushUnwindOpcodes(bool AllowCompactModel0) { } // Emit unwind opcodes - EmitBytes(UnwindOpAsm.data(), 0); + EmitBytes(StringRef(reinterpret_cast(Opcodes.data()), + Opcodes.size()), 0); } void ARMELFStreamer::EmitHandlerData() { @@ -427,42 +432,55 @@ void ARMELFStreamer::EmitPersonality(const MCSymbol *Per) { void ARMELFStreamer::EmitSetFP(unsigned NewFPReg, unsigned NewSPReg, int64_t Offset) { - assert(SPOffset == 0 && - "Current implementation assumes .setfp precedes .pad"); - - const MCRegisterInfo &MRI = getContext().getRegisterInfo(); - - uint16_t NewFPRegEncVal = MRI.getEncodingValue(NewFPReg); -#ifndef NDEBUG - uint16_t NewSPRegEncVal = MRI.getEncodingValue(NewSPReg); -#endif - - assert((NewSPReg == ARM::SP || NewSPRegEncVal == FPReg) && + assert((NewSPReg == ARM::SP || NewSPReg == FPReg) && "the operand of .setfp directive should be either $sp or $fp"); UsedFP = true; - FPReg = NewFPRegEncVal; - FPOffset = Offset; + FPReg = NewFPReg; + + if (NewSPReg == ARM::SP) + FPOffset = SPOffset + Offset; + else + FPOffset += Offset; } void ARMELFStreamer::EmitPad(int64_t Offset) { - SPOffset += Offset; + // Track the change of the $sp offset + SPOffset -= Offset; + + // To squash multiple .pad directives, we should delay the unwind opcode + // until the .save, .vsave, .handlerdata, or .fnend directives. + PendingOffset -= Offset; } void ARMELFStreamer::EmitRegSave(const SmallVectorImpl &RegList, bool IsVector) { + // Collect the registers in the register list + unsigned Count = 0; + uint32_t Mask = 0; const MCRegisterInfo &MRI = getContext().getRegisterInfo(); - -#ifndef NDEBUG - unsigned Max = IsVector ? 32 : 16; -#endif - uint32_t &RegMask = IsVector ? VFPRegSave : RegSave; - for (size_t i = 0; i < RegList.size(); ++i) { unsigned Reg = MRI.getEncodingValue(RegList[i]); - assert(Reg < Max && "Register encoded value out of range"); - RegMask |= 1u << Reg; + assert(Reg < (IsVector ? 32 : 16) && "Register out of range"); + unsigned Bit = (1u << Reg); + if ((Mask & Bit) == 0) { + Mask |= Bit; + ++Count; + } } + + // Track the change the $sp offset: For the .save directive, the + // corresponding push instruction will decrease the $sp by (4 * Count). + // For the .vsave directive, the corresponding vpush instruction will + // decrease $sp by (8 * Count). + SPOffset -= Count * (IsVector ? 8 : 4); + + // Emit the opcode + FlushPendingOffset(); + if (IsVector) + UnwindOpAsm.EmitVFPRegSave(Mask); + else + UnwindOpAsm.EmitRegSave(Mask); } namespace llvm { -- cgit v1.1 From 6c1bd2919ee76ef4953136f0b73192fbef3a69ab Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Mon, 10 Jun 2013 16:45:40 +0000 Subject: Silencing an MSVC warning about comparing signed and unsigned values. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183682 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp') diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index d83567c..679d3c4 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -461,7 +461,7 @@ void ARMELFStreamer::EmitRegSave(const SmallVectorImpl &RegList, const MCRegisterInfo &MRI = getContext().getRegisterInfo(); for (size_t i = 0; i < RegList.size(); ++i) { unsigned Reg = MRI.getEncodingValue(RegList[i]); - assert(Reg < (IsVector ? 32 : 16) && "Register out of range"); + assert(Reg < (IsVector ? 32U : 16U) && "Register out of range"); unsigned Bit = (1u << Reg); if ((Mask & Bit) == 0) { Mask |= Bit; -- cgit v1.1