summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp')
-rw-r--r--contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp159
1 files changed, 110 insertions, 49 deletions
diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index 418971d..6c3d247 100644
--- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -13,7 +13,9 @@
//
//===----------------------------------------------------------------------===//
+#include "ARMRegisterInfo.h"
#include "ARMUnwindOp.h"
+#include "ARMUnwindOpAsm.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAsmBackend.h"
@@ -26,6 +28,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
@@ -33,11 +36,15 @@
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+static std::string GetAEABIUnwindPersonalityName(unsigned Index) {
+ assert(Index < NUM_PERSONALITY_INDEX && "Invalid personality index");
+ return (Twine("__aeabi_unwind_cpp_pr") + Twine(Index)).str();
+}
+
namespace {
/// Extend the generic ELFStreamer class so that it can emit mapping symbols at
@@ -57,8 +64,9 @@ public:
ARMELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS,
MCCodeEmitter *Emitter, bool IsThumb)
: MCELFStreamer(SK_ARMELFStreamer, Context, TAB, OS, Emitter),
- IsThumb(IsThumb), MappingSymbolCounter(0), LastEMS(EMS_None), ExTab(0),
- FnStart(0), Personality(0), CantUnwind(false) {}
+ IsThumb(IsThumb), MappingSymbolCounter(0), LastEMS(EMS_None) {
+ Reset();
+ }
~ARMELFStreamer() {}
@@ -75,14 +83,15 @@ public:
virtual void EmitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool isVector);
- virtual void ChangeSection(const MCSection *Section) {
+ virtual void ChangeSection(const MCSection *Section,
+ const MCExpr *Subsection) {
// We have to keep track of the mapping symbol state of any sections we
// use. Each one should start off as EMS_None, which is provided as the
// default constructor by DenseMap::lookup.
- LastMappingSymbols[getPreviousSection()] = LastEMS;
+ LastMappingSymbols[getPreviousSection().first] = LastEMS;
LastEMS = LastMappingSymbols.lookup(Section);
- MCELFStreamer::ChangeSection(Section);
+ MCELFStreamer::ChangeSection(Section, Subsection);
}
/// This function is the one used to emit instruction data into the ELF
@@ -175,7 +184,7 @@ private:
MCELF::SetType(SD, ELF::STT_NOTYPE);
MCELF::SetBinding(SD, ELF::STB_LOCAL);
SD.setExternal(false);
- Symbol->setSection(*getCurrentSection());
+ Symbol->setSection(*getCurrentSection().first);
const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext());
Symbol->setVariableValue(Value);
@@ -194,6 +203,7 @@ private:
void Reset();
void EmitPersonalityFixup(StringRef Name);
+ void CollectUnwindOpcodes();
void SwitchToEHSection(const char *Prefix, unsigned Type, unsigned Flags,
SectionKind Kind, const MCSymbol &Fn);
@@ -210,9 +220,16 @@ 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;
+ bool UsedFP;
bool CantUnwind;
+ UnwindOpcodeAssembler UnwindOpAsm;
};
-}
+} // end anonymous namespace
inline void ARMELFStreamer::SwitchToEHSection(const char *Prefix,
unsigned Type,
@@ -238,7 +255,7 @@ inline void ARMELFStreamer::SwitchToEHSection(const char *Prefix,
} else {
EHSection = getContext().getELFSection(EHSecName, Type, Flags, Kind);
}
- assert(EHSection);
+ assert(EHSection && "Failed to get the required EH section");
// Switch to .ARM.extab or .ARM.exidx section
SwitchSection(EHSection);
@@ -262,10 +279,20 @@ 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);
+ FPOffset = 0;
+ SPOffset = 0;
+ UsedFP = false;
CantUnwind = false;
+
+ UnwindOpAsm.Reset();
}
// Add the R_ARM_NONE fixup at the same position
@@ -284,6 +311,18 @@ 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();
@@ -294,35 +333,29 @@ void ARMELFStreamer::EmitFnEnd() {
assert(FnStart && ".fnstart must preceeds .fnend");
// Emit unwind opcodes if there is no .handlerdata directive
- int PersonalityIndex = -1;
if (!ExTab && !CantUnwind) {
- // For __aeabi_unwind_cpp_pr1, we have to emit opcodes in .ARM.extab.
- SwitchToExTabSection(*FnStart);
-
- // Create .ARM.extab label for offset in .ARM.exidx
- ExTab = getContext().CreateTempSymbol();
- EmitLabel(ExTab);
-
- PersonalityIndex = 1;
-
- uint32_t Entry = 0;
- uint32_t NumExtraEntryWords = 0;
- Entry |= NumExtraEntryWords << 24;
- Entry |= (EHT_COMPACT | PersonalityIndex) << 16;
-
- // TODO: This should be generated according to .save, .vsave, .setfp
- // directives. Currently, we are simply generating FINISH opcode.
- Entry |= UNWIND_OPCODE_FINISH << 8;
- Entry |= UNWIND_OPCODE_FINISH;
-
- EmitIntValue(Entry, 4, 0);
+ 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);
+ }
}
// Emit the exception index table entry
SwitchToExIdxSection(*FnStart);
- if (PersonalityIndex == 1)
- EmitPersonalityFixup("__aeabi_unwind_cpp_pr1");
+ unsigned PersonalityIndex = UnwindOpAsm.getPersonalityIndex();
+ if (PersonalityIndex < NUM_PERSONALITY_INDEX)
+ EmitPersonalityFixup(GetAEABIUnwindPersonalityName(PersonalityIndex));
const MCSymbolRefExpr *FnStartRef =
MCSymbolRefExpr::Create(FnStart,
@@ -333,12 +366,22 @@ void ARMELFStreamer::EmitFnEnd() {
if (CantUnwind) {
EmitIntValue(EXIDX_CANTUNWIND, 4, 0);
- } else {
+ } else if (ExTab) {
+ // Emit a reference to the unwind opcodes in the ".ARM.extab" section.
const MCSymbolRefExpr *ExTabEntryRef =
MCSymbolRefExpr::Create(ExTab,
MCSymbolRefExpr::VK_ARM_PREL31,
getContext());
EmitValue(ExTabEntryRef, 4, 0);
+ } else {
+ // For the __aeabi_unwind_cpp_pr0, we have to emit the unwind opcodes in
+ // the second word of exception index table entry. The size of the unwind
+ // 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 &&
+ "Unwind opcode size for __aeabi_cpp_unwind_pr0 must be equal to 4");
+ EmitBytes(UnwindOpAsm.data(), 0);
}
// Clean exception handling frame information
@@ -368,36 +411,54 @@ void ARMELFStreamer::EmitHandlerData() {
EmitValue(PersonalityRef, 4, 0);
// Emit unwind opcodes
- uint32_t Entry = 0;
- uint32_t NumExtraEntryWords = 0;
-
- // TODO: This should be generated according to .save, .vsave, .setfp
- // directives. Currently, we are simply generating FINISH opcode.
- Entry |= NumExtraEntryWords << 24;
- Entry |= UNWIND_OPCODE_FINISH << 16;
- Entry |= UNWIND_OPCODE_FINISH << 8;
- Entry |= UNWIND_OPCODE_FINISH;
-
- EmitIntValue(Entry, 4, 0);
+ CollectUnwindOpcodes();
+ EmitBytes(UnwindOpAsm.data(), 0);
}
void ARMELFStreamer::EmitPersonality(const MCSymbol *Per) {
Personality = Per;
+ UnwindOpAsm.setPersonality(Per);
}
-void ARMELFStreamer::EmitSetFP(unsigned NewFpReg,
- unsigned NewSpReg,
+void ARMELFStreamer::EmitSetFP(unsigned NewFPReg,
+ unsigned NewSPReg,
int64_t Offset) {
- // TODO: Not implemented
+ 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) &&
+ "the operand of .setfp directive should be either $sp or $fp");
+
+ UsedFP = true;
+ FPReg = NewFPRegEncVal;
+ FPOffset = Offset;
}
void ARMELFStreamer::EmitPad(int64_t Offset) {
- // TODO: Not implemented
+ SPOffset += Offset;
}
void ARMELFStreamer::EmitRegSave(const SmallVectorImpl<unsigned> &RegList,
bool IsVector) {
- // TODO: Not implemented
+ 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;
+ }
}
namespace llvm {
OpenPOWER on IntegriCloud