#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
Asm->OutContext);
}
+int WinException::getFrameIndexOffset(int FrameIndex) {
+ const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();
+ unsigned UnusedReg;
+ if (Asm->MAI->usesWindowsCFI())
+ return TFI.getFrameIndexReferenceFromSP(*Asm->MF, FrameIndex, UnusedReg);
+ return TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);
+}
+
namespace {
/// Information describing an invoke range.
struct InvokeRange {
/// imagerel32 LabelStart;
/// imagerel32 LabelEnd;
/// imagerel32 FilterOrFinally; // One means catch-all.
-/// imagerel32 LabelLPad; // Zero means __finally.
+/// imagerel32 ExceptOrNull; // Zero means __finally.
/// } Entries[NumEntries];
/// };
void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
// the actions that would be taken in that state. This means our tables are
// slightly bigger, which is OK.
for (const auto &MBB : *MF) {
+ // Break out before we enter into a finally funclet.
+ // FIXME: We need to emit separate EH tables for cleanups.
+ if (MBB.isEHFuncletEntry() && &MBB != MF->begin())
+ break;
+
for (InvokeRange &I : invoke_ranges(FuncInfo, MBB)) {
// If this invoke is in the same state as the last invoke and there were
// no non-throwing calls between it, extend the range to include both
// If this invoke ends a previous one, emit all the actions for this
// state.
- if (LastEHState != -1) {
- assert(LastBeginLabel && LastEndLabel);
- for (int State = LastEHState; State != -1;) {
- SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
- const MCExpr *FilterOrFinally;
- const MCExpr *ExceptOrNull;
- auto *Handler = UME.Handler.get<MachineBasicBlock *>();
- if (UME.IsFinally) {
- FilterOrFinally = create32bitRef(Handler->getSymbol());
- ExceptOrNull = MCConstantExpr::create(0, Ctx);
- } else {
- // For an except, the filter can be 1 (catch-all) or a function
- // label.
- FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
- : MCConstantExpr::create(1, Ctx);
- ExceptOrNull = create32bitRef(Handler->getSymbol());
- }
-
- OS.EmitValue(getLabelPlusOne(LastBeginLabel), 4);
- OS.EmitValue(getLabelPlusOne(LastEndLabel), 4);
- OS.EmitValue(FilterOrFinally, 4);
- OS.EmitValue(ExceptOrNull, 4);
-
- State = UME.ToState;
- }
- }
+ if (LastEHState != -1)
+ emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel,
+ LastEHState);
LastBeginLabel = I.BeginLabel;
LastEndLabel = I.EndLabel;
LastEHState = I.State;
}
}
+
+ if (LastEndLabel)
+ emitSEHActionsForRange(FuncInfo, LastBeginLabel, LastEndLabel,
+ LastEHState);
+
OS.EmitLabel(TableEnd);
return;
}
}
}
+void WinException::emitSEHActionsForRange(WinEHFuncInfo &FuncInfo,
+ MCSymbol *BeginLabel,
+ MCSymbol *EndLabel, int State) {
+ auto &OS = *Asm->OutStreamer;
+ MCContext &Ctx = Asm->OutContext;
+
+ assert(BeginLabel && EndLabel);
+ while (State != -1) {
+ // struct Entry {
+ // imagerel32 LabelStart;
+ // imagerel32 LabelEnd;
+ // imagerel32 FilterOrFinally; // One means catch-all.
+ // imagerel32 ExceptOrNull; // Zero means __finally.
+ // };
+ SEHUnwindMapEntry &UME = FuncInfo.SEHUnwindMap[State];
+ const MCExpr *FilterOrFinally;
+ const MCExpr *ExceptOrNull;
+ auto *Handler = UME.Handler.get<MachineBasicBlock *>();
+ if (UME.IsFinally) {
+ FilterOrFinally = create32bitRef(getMCSymbolForMBBOrGV(Asm, Handler));
+ ExceptOrNull = MCConstantExpr::create(0, Ctx);
+ } else {
+ // For an except, the filter can be 1 (catch-all) or a function
+ // label.
+ FilterOrFinally = UME.Filter ? create32bitRef(UME.Filter)
+ : MCConstantExpr::create(1, Ctx);
+ ExceptOrNull = create32bitRef(Handler->getSymbol());
+ }
+
+ OS.EmitValue(getLabelPlusOne(BeginLabel), 4);
+ OS.EmitValue(getLabelPlusOne(EndLabel), 4);
+ OS.EmitValue(FilterOrFinally, 4);
+ OS.EmitValue(ExceptOrNull, 4);
+
+ assert(UME.ToState < State && "states should decrease");
+ State = UME.ToState;
+ }
+}
+
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
const Function *F = MF->getFunction();
auto &OS = *Asm->OutStreamer;
emitEHRegistrationOffsetLabel(FuncInfo, FuncLinkageName);
}
+ int UnwindHelpOffset = 0;
+ if (Asm->MAI->usesWindowsCFI())
+ UnwindHelpOffset = getFrameIndexOffset(FuncInfo.UnwindHelpFrameIdx);
+
MCSymbol *UnwindMapXData = nullptr;
MCSymbol *TryBlockMapXData = nullptr;
MCSymbol *IPToStateXData = nullptr;
OS.EmitIntValue(IPToStateTable.size(), 4); // IPMapEntries
OS.EmitValue(create32bitRef(IPToStateXData), 4); // IPToStateMap
if (Asm->MAI->usesWindowsCFI())
- OS.EmitIntValue(FuncInfo.UnwindHelpFrameOffset, 4); // UnwindHelp
+ OS.EmitIntValue(UnwindHelpOffset, 4); // UnwindHelp
OS.EmitIntValue(0, 4); // ESTypeList
OS.EmitIntValue(1, 4); // EHFlags
FuncLinkageName, HT.CatchObjRecoverIdx);
FrameAllocOffsetRef = MCSymbolRefExpr::create(
FrameAllocOffset, MCSymbolRefExpr::VK_None, Asm->OutContext);
- } else if (HT.CatchObj.FrameOffset != INT_MAX) {
- int Offset = HT.CatchObj.FrameOffset;
+ } else if (HT.CatchObj.FrameIndex != INT_MAX) {
+ int Offset = getFrameIndexOffset(HT.CatchObj.FrameIndex);
// For 32-bit, the catch object offset is relative to the end of the
// EH registration node. For 64-bit, it's relative to SP at the end of
// the prologue.
// Emit an entry indicating that PCs after 'Label' have this EH state.
if (I.State != LastEHState)
IPToStateTable.push_back(
- std::make_pair(create32bitRef(I.BeginLabel), I.State));
+ std::make_pair(getLabelPlusOne(I.BeginLabel), I.State));
LastEHState = I.State;
LastEndLabel = I.EndLabel;
}
for (SEHUnwindMapEntry &UME : FuncInfo.SEHUnwindMap) {
MCSymbol *ExceptOrFinally =
UME.Handler.get<MachineBasicBlock *>()->getSymbol();
- OS.EmitIntValue(UME.ToState, 4); // ToState
+ // -1 is usually the base state for "unwind to caller", but for
+ // _except_handler4 it's -2. Do that replacement here if necessary.
+ int ToState = UME.ToState == -1 ? BaseState : UME.ToState;
+ OS.EmitIntValue(ToState, 4); // ToState
OS.EmitValue(create32bitRef(UME.Filter), 4); // Filter
OS.EmitValue(create32bitRef(ExceptOrFinally), 4); // Except/Finally
}