mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-06 10:58:44 +00:00
[ARM64][Windows] MCLayer support for exception handling
Add ARM64 unwind codes to MCLayer, as well SEH directives that will be emitted by the frame lowering patch to follow. We only emit unwind codes into object object files for now. Differential Revision: https://reviews.llvm.org/D50166 llvm-svn: 345450
This commit is contained in:
parent
a12c9f13c1
commit
b45305d59c
@ -198,10 +198,6 @@ class MCStreamer {
|
||||
|
||||
WinEH::FrameInfo *CurrentWinFrameInfo;
|
||||
|
||||
/// Retreive the current frame info if one is available and it is not yet
|
||||
/// closed. Otherwise, issue an error and return null.
|
||||
WinEH::FrameInfo *EnsureValidWinFrameInfo(SMLoc Loc);
|
||||
|
||||
/// Tracks an index to represent the order a symbol was emitted in.
|
||||
/// Zero means we did not emit that symbol.
|
||||
DenseMap<const MCSymbol *, unsigned> SymbolOrdering;
|
||||
@ -224,10 +220,6 @@ protected:
|
||||
virtual void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame);
|
||||
virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame);
|
||||
|
||||
/// When emitting an object file, create and emit a real label. When emitting
|
||||
/// textual assembly, this should do nothing to avoid polluting our output.
|
||||
virtual MCSymbol *EmitCFILabel();
|
||||
|
||||
WinEH::FrameInfo *getCurrentWinFrameInfo() {
|
||||
return CurrentWinFrameInfo;
|
||||
}
|
||||
@ -266,6 +258,14 @@ public:
|
||||
return TargetStreamer.get();
|
||||
}
|
||||
|
||||
/// When emitting an object file, create and emit a real label. When emitting
|
||||
/// textual assembly, this should do nothing to avoid polluting our output.
|
||||
virtual MCSymbol *EmitCFILabel();
|
||||
|
||||
/// Retreive the current frame info if one is available and it is not yet
|
||||
/// closed. Otherwise, issue an error and return null.
|
||||
WinEH::FrameInfo *EnsureValidWinFrameInfo(SMLoc Loc);
|
||||
|
||||
unsigned getNumFrameInfos() { return DwarfFrameInfos.size(); }
|
||||
ArrayRef<MCDwarfFrameInfo> getDwarfFrameInfos() const {
|
||||
return DwarfFrameInfos;
|
||||
@ -899,6 +899,11 @@ public:
|
||||
|
||||
virtual void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
|
||||
virtual void EmitWinCFIEndProc(SMLoc Loc = SMLoc());
|
||||
/// This is used on platforms, such as Windows on ARM64, that require function
|
||||
/// or funclet sizes to be emitted in .xdata before the End marker is emitted
|
||||
/// for the frame. We cannot use the End marker, as it is not set at the
|
||||
/// point of emitting .xdata, in order to indicate that the frame is active.
|
||||
virtual void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc = SMLoc());
|
||||
virtual void EmitWinCFIStartChained(SMLoc Loc = SMLoc());
|
||||
virtual void EmitWinCFIEndChained(SMLoc Loc = SMLoc());
|
||||
virtual void EmitWinCFIPushReg(unsigned Register, SMLoc Loc = SMLoc());
|
||||
|
@ -56,6 +56,14 @@ public:
|
||||
void Emit(MCStreamer &Streamer) const override;
|
||||
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI) const override;
|
||||
};
|
||||
|
||||
class ARM64UnwindEmitter : public WinEH::UnwindEmitter {
|
||||
public:
|
||||
void Emit(MCStreamer &Streamer) const override;
|
||||
void EmitUnwindInfo(MCStreamer &Streamer,
|
||||
WinEH::FrameInfo *FI) const override;
|
||||
};
|
||||
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_MC_MCWINEH_H
|
||||
#define LLVM_MC_MCWINEH_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
@ -20,9 +21,9 @@ class MCSymbol;
|
||||
namespace WinEH {
|
||||
struct Instruction {
|
||||
const MCSymbol *Label;
|
||||
const unsigned Offset;
|
||||
const unsigned Register;
|
||||
const unsigned Operation;
|
||||
unsigned Offset;
|
||||
unsigned Register;
|
||||
unsigned Operation;
|
||||
|
||||
Instruction(unsigned Op, MCSymbol *L, unsigned Reg, unsigned Off)
|
||||
: Label(L), Offset(Off), Register(Reg), Operation(Op) {}
|
||||
@ -31,6 +32,7 @@ struct Instruction {
|
||||
struct FrameInfo {
|
||||
const MCSymbol *Begin = nullptr;
|
||||
const MCSymbol *End = nullptr;
|
||||
const MCSymbol *FuncletOrFuncEnd = nullptr;
|
||||
const MCSymbol *ExceptionHandler = nullptr;
|
||||
const MCSymbol *Function = nullptr;
|
||||
const MCSymbol *PrologEnd = nullptr;
|
||||
@ -43,6 +45,7 @@ struct FrameInfo {
|
||||
int LastFrameInst = -1;
|
||||
const FrameInfo *ChainedParent = nullptr;
|
||||
std::vector<Instruction> Instructions;
|
||||
MapVector<MCSymbol*, std::vector<Instruction>> EpilogMap;
|
||||
|
||||
FrameInfo() = default;
|
||||
FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel)
|
||||
|
@ -33,7 +33,24 @@ enum UnwindOpcodes {
|
||||
UOP_SaveNonVolBig,
|
||||
UOP_SaveXMM128 = 8,
|
||||
UOP_SaveXMM128Big,
|
||||
UOP_PushMachFrame
|
||||
UOP_PushMachFrame,
|
||||
// The following set of unwind opcodes is for ARM64. They are documented at
|
||||
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
UOP_AllocMedium,
|
||||
UOP_SaveFPLRX,
|
||||
UOP_SaveFPLR,
|
||||
UOP_SaveReg,
|
||||
UOP_SaveRegX,
|
||||
UOP_SaveRegP,
|
||||
UOP_SaveRegPX,
|
||||
UOP_SaveFReg,
|
||||
UOP_SaveFRegX,
|
||||
UOP_SaveFRegP,
|
||||
UOP_SaveFRegPX,
|
||||
UOP_SetFP,
|
||||
UOP_AddFP,
|
||||
UOP_Nop,
|
||||
UOP_End
|
||||
};
|
||||
|
||||
/// UnwindCode - This union describes a single operation in a function prolog,
|
||||
|
@ -42,6 +42,7 @@ WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
|
||||
// MSVC's EH tables are always composed of 32-bit words. All known 64-bit
|
||||
// platforms use an imagerel32 relocation to refer to symbols.
|
||||
useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
|
||||
isAArch64 = Asm->TM.getTargetTriple().isAArch64();
|
||||
}
|
||||
|
||||
WinException::~WinException() {}
|
||||
@ -242,6 +243,17 @@ void WinException::endFunclet() {
|
||||
if (F.hasPersonalityFn())
|
||||
Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts());
|
||||
|
||||
// On funclet exit, we emit a fake "function" end marker, so that the call
|
||||
// to EmitWinEHHandlerData below can calculate the size of the funclet or
|
||||
// function.
|
||||
if (isAArch64) {
|
||||
Asm->OutStreamer->SwitchSection(CurrentFuncletTextSection);
|
||||
Asm->OutStreamer->EmitWinCFIFuncletOrFuncEnd();
|
||||
MCSection *XData = Asm->OutStreamer->getAssociatedXDataSection(
|
||||
Asm->OutStreamer->getCurrentSectionOnly());
|
||||
Asm->OutStreamer->SwitchSection(XData);
|
||||
}
|
||||
|
||||
// Emit an UNWIND_INFO struct describing the prologue.
|
||||
Asm->OutStreamer->EmitWinEHHandlerData();
|
||||
|
||||
@ -286,7 +298,10 @@ const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
|
||||
return create32bitRef(Asm->getSymbol(GV));
|
||||
}
|
||||
|
||||
const MCExpr *WinException::getLabelPlusOne(const MCSymbol *Label) {
|
||||
const MCExpr *WinException::getLabel(const MCSymbol *Label) {
|
||||
if (isAArch64)
|
||||
return MCSymbolRefExpr::create(Label, MCSymbolRefExpr::VK_COFF_IMGREL32,
|
||||
Asm->OutContext);
|
||||
return MCBinaryExpr::createAdd(create32bitRef(Label),
|
||||
MCConstantExpr::create(1, Asm->OutContext),
|
||||
Asm->OutContext);
|
||||
@ -588,7 +603,6 @@ void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,
|
||||
const MCSymbol *EndLabel, int State) {
|
||||
auto &OS = *Asm->OutStreamer;
|
||||
MCContext &Ctx = Asm->OutContext;
|
||||
|
||||
bool VerboseAsm = OS.isVerboseAsm();
|
||||
auto AddComment = [&](const Twine &Comment) {
|
||||
if (VerboseAsm)
|
||||
@ -613,9 +627,9 @@ void WinException::emitSEHActionsForRange(const WinEHFuncInfo &FuncInfo,
|
||||
}
|
||||
|
||||
AddComment("LabelStart");
|
||||
OS.EmitValue(getLabelPlusOne(BeginLabel), 4);
|
||||
OS.EmitValue(getLabel(BeginLabel), 4);
|
||||
AddComment("LabelEnd");
|
||||
OS.EmitValue(getLabelPlusOne(EndLabel), 4);
|
||||
OS.EmitValue(getLabel(EndLabel), 4);
|
||||
AddComment(UME.IsFinally ? "FinallyFunclet" : UME.Filter ? "FilterFunction"
|
||||
: "CatchAll");
|
||||
OS.EmitValue(FilterOrFinally, 4);
|
||||
@ -799,7 +813,7 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||
// TypeDescriptor *Type;
|
||||
// int32_t CatchObjOffset;
|
||||
// void (*Handler)();
|
||||
// int32_t ParentFrameOffset; // x64 only
|
||||
// int32_t ParentFrameOffset; // x64 and AArch64 only
|
||||
// };
|
||||
OS.EmitLabel(HandlerMapXData);
|
||||
for (const WinEHHandlerType &HT : TBME.HandlerArray) {
|
||||
@ -901,7 +915,7 @@ void WinException::computeIP2StateTable(
|
||||
ChangeLabel = StateChange.PreviousEndLabel;
|
||||
// Emit an entry indicating that PCs after 'Label' have this EH state.
|
||||
IPToStateTable.push_back(
|
||||
std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState));
|
||||
std::make_pair(getLabel(ChangeLabel), StateChange.NewState));
|
||||
// FIXME: assert that NewState is between CatchLow and CatchHigh.
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer {
|
||||
/// True if this is a 64-bit target and we should use image relative offsets.
|
||||
bool useImageRel32 = false;
|
||||
|
||||
/// True if we are generating exception handling on Windows for ARM64.
|
||||
bool isAArch64 = false;
|
||||
|
||||
/// Pointer to the current funclet entry BB.
|
||||
const MachineBasicBlock *CurrentFuncletEntry = nullptr;
|
||||
|
||||
@ -72,7 +75,7 @@ class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer {
|
||||
|
||||
const MCExpr *create32bitRef(const MCSymbol *Value);
|
||||
const MCExpr *create32bitRef(const GlobalValue *GV);
|
||||
const MCExpr *getLabelPlusOne(const MCSymbol *Label);
|
||||
const MCExpr *getLabel(const MCSymbol *Label);
|
||||
const MCExpr *getOffset(const MCSymbol *OffsetOf, const MCSymbol *OffsetFrom);
|
||||
const MCExpr *getOffsetPlusOne(const MCSymbol *OffsetOf,
|
||||
const MCSymbol *OffsetFrom);
|
||||
|
@ -289,6 +289,7 @@ public:
|
||||
|
||||
void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
|
||||
void EmitWinCFIEndProc(SMLoc Loc) override;
|
||||
void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
|
||||
void EmitWinCFIStartChained(SMLoc Loc) override;
|
||||
void EmitWinCFIEndChained(SMLoc Loc) override;
|
||||
void EmitWinCFIPushReg(unsigned Register, SMLoc Loc) override;
|
||||
@ -1589,6 +1590,10 @@ void MCAsmStreamer::EmitWinCFIEndProc(SMLoc Loc) {
|
||||
EmitEOL();
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
void MCAsmStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
|
||||
}
|
||||
|
||||
void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) {
|
||||
MCStreamer::EmitWinCFIStartChained(Loc);
|
||||
|
||||
|
@ -627,6 +627,17 @@ void MCStreamer::EmitWinCFIEndProc(SMLoc Loc) {
|
||||
CurFrame->End = Label;
|
||||
}
|
||||
|
||||
void MCStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
|
||||
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
|
||||
if (!CurFrame)
|
||||
return;
|
||||
if (CurFrame->ChainedParent)
|
||||
getContext().reportError(Loc, "Not all chained regions terminated!");
|
||||
|
||||
MCSymbol *Label = EmitCFILabel();
|
||||
CurFrame->FuncletOrFuncEnd = Label;
|
||||
}
|
||||
|
||||
void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) {
|
||||
WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
|
||||
if (!CurFrame)
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCObjectStreamer.h"
|
||||
#include "llvm/MC/MCSectionCOFF.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Win64EH.h"
|
||||
@ -23,6 +26,8 @@ static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
|
||||
uint8_t Count = 0;
|
||||
for (const auto &I : Insns) {
|
||||
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported unwind code");
|
||||
case Win64EH::UOP_PushNonVol:
|
||||
case Win64EH::UOP_AllocSmall:
|
||||
case Win64EH::UOP_SetFPReg:
|
||||
@ -60,6 +65,8 @@ static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
|
||||
uint16_t w;
|
||||
b2 = (inst.Operation & 0x0F);
|
||||
switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported unwind code");
|
||||
case Win64EH::UOP_PushNonVol:
|
||||
EmitAbsDifference(streamer, inst.Label, begin);
|
||||
b2 |= (inst.Register & 0x0F) << 4;
|
||||
@ -242,3 +249,343 @@ void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(
|
||||
::EmitUnwindInfo(Streamer, info);
|
||||
}
|
||||
|
||||
static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
|
||||
const MCSymbol *RHS) {
|
||||
MCContext &Context = Streamer.getContext();
|
||||
const MCExpr *Diff =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
|
||||
MCSymbolRefExpr::create(RHS, Context), Context);
|
||||
MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
|
||||
int64_t value;
|
||||
Diff->evaluateAsAbsolute(value, OS->getAssembler());
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
|
||||
uint32_t Count = 0;
|
||||
for (const auto &I : Insns) {
|
||||
switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported ARM64 unwind code");
|
||||
case Win64EH::UOP_AllocSmall:
|
||||
Count += 1;
|
||||
break;
|
||||
case Win64EH::UOP_AllocMedium:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_AllocLarge:
|
||||
Count += 4;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFPLRX:
|
||||
Count += 1;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFPLR:
|
||||
Count += 1;
|
||||
break;
|
||||
case Win64EH::UOP_SaveReg:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegP:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegPX:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegX:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFReg:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegP:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegX:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegPX:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_SetFP:
|
||||
Count += 1;
|
||||
break;
|
||||
case Win64EH::UOP_AddFP:
|
||||
Count += 2;
|
||||
break;
|
||||
case Win64EH::UOP_Nop:
|
||||
Count += 1;
|
||||
break;
|
||||
case Win64EH::UOP_End:
|
||||
Count += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
// Unwind opcode encodings and restrictions are documented at
|
||||
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
|
||||
WinEH::Instruction &inst) {
|
||||
uint8_t b, reg;
|
||||
switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported ARM64 unwind code");
|
||||
case Win64EH::UOP_AllocSmall:
|
||||
b = (inst.Offset >> 4) & 0x1F;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_AllocMedium: {
|
||||
uint16_t hw = (inst.Offset >> 4) & 0x7FF;
|
||||
b = 0xC0;
|
||||
b |= (hw >> 8);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = hw & 0xFF;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
}
|
||||
case Win64EH::UOP_AllocLarge: {
|
||||
uint32_t w;
|
||||
b = 0xE0;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
w = inst.Offset >> 4;
|
||||
b = (w & 0x00FF0000) >> 16;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = (w & 0x0000FF00) >> 8;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = w & 0x000000FF;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
}
|
||||
case Win64EH::UOP_SetFP:
|
||||
b = 0xE1;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_AddFP:
|
||||
b = 0xE2;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = (inst.Offset >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_Nop:
|
||||
b = 0xE3;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFPLRX:
|
||||
b = 0x80;
|
||||
b |= ((inst.Offset - 1) >> 3) & 0x3F;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFPLR:
|
||||
b = 0x40;
|
||||
b |= (inst.Offset >> 3) & 0x3F;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveReg:
|
||||
assert(inst.Register >= 19 && "Saved reg must be >= 19");
|
||||
reg = inst.Register - 19;
|
||||
b = 0xD0 | ((reg & 0xC) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegX:
|
||||
assert(inst.Register >= 19 && "Saved reg must be >= 19");
|
||||
reg = inst.Register - 19;
|
||||
b = 0xD4 | ((reg & 0x8) >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegP:
|
||||
assert(inst.Register >= 19 && "Saved registers must be >= 19");
|
||||
reg = inst.Register - 19;
|
||||
b = 0xC8 | ((reg & 0xC) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveRegPX:
|
||||
assert(inst.Register >= 19 && "Saved registers must be >= 19");
|
||||
reg = inst.Register - 19;
|
||||
b = 0xCC | ((reg & 0xC) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFReg:
|
||||
assert(inst.Register >= 8 && "Saved dreg must be >= 8");
|
||||
reg = inst.Register - 8;
|
||||
b = 0xDC | ((reg & 0x4) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegX:
|
||||
assert(inst.Register >= 8 && "Saved dreg must be >= 8");
|
||||
reg = inst.Register - 8;
|
||||
b = 0xDE;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegP:
|
||||
assert(inst.Register >= 8 && "Saved dregs must be >= 8");
|
||||
reg = inst.Register - 8;
|
||||
b = 0xD8 | ((reg & 0x4) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_SaveFRegPX:
|
||||
assert(inst.Register >= 8 && "Saved dregs must be >= 8");
|
||||
reg = inst.Register - 8;
|
||||
b = 0xDA | ((reg & 0x4) >> 2);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
case Win64EH::UOP_End:
|
||||
b = 0xE4;
|
||||
streamer.EmitIntValue(b, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the .xdata section. The format of .xdata on ARM64 is documented at
|
||||
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
|
||||
// If this UNWIND_INFO already has a symbol, it's already been emitted.
|
||||
if (info->Symbol)
|
||||
return;
|
||||
|
||||
MCContext &context = streamer.getContext();
|
||||
MCSymbol *Label = context.createTempSymbol();
|
||||
|
||||
streamer.EmitValueToAlignment(4);
|
||||
streamer.EmitLabel(Label);
|
||||
info->Symbol = Label;
|
||||
|
||||
uint32_t FuncLength = 0x0;
|
||||
FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd,
|
||||
info->Begin);
|
||||
if (FuncLength)
|
||||
FuncLength /= 4;
|
||||
uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
|
||||
uint32_t TotalCodeBytes = PrologCodeBytes;
|
||||
|
||||
// Process epilogs.
|
||||
MapVector<MCSymbol *, uint32_t> EpilogInfo;
|
||||
for (auto &I : info->EpilogMap) {
|
||||
MCSymbol *EpilogStart = I.first;
|
||||
auto &EpilogInstrs = I.second;
|
||||
uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
|
||||
EpilogInfo[EpilogStart] = TotalCodeBytes;
|
||||
TotalCodeBytes += CodeBytes;
|
||||
}
|
||||
|
||||
// Code Words, Epilog count, E, X, Vers, Function Length
|
||||
uint32_t row1 = 0x0;
|
||||
uint8_t CodeWords = TotalCodeBytes / 4;
|
||||
uint8_t CodeWordsMod = TotalCodeBytes % 4;
|
||||
if (CodeWordsMod)
|
||||
CodeWords++;
|
||||
uint32_t EpilogCount = info->EpilogMap.size();
|
||||
bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
|
||||
if (!ExtensionWord) {
|
||||
row1 |= (EpilogCount & 0x1F) << 22;
|
||||
row1 |= (CodeWords & 0x1F) << 27;
|
||||
}
|
||||
// E is always 0 right now, TODO: packed epilog setup
|
||||
if (info->HandlesExceptions) // X
|
||||
row1 |= 1 << 20;
|
||||
row1 |= FuncLength & 0x3FFFF;
|
||||
streamer.EmitIntValue(row1, 4);
|
||||
|
||||
// Extended Code Words, Extended Epilog Count
|
||||
if (ExtensionWord) {
|
||||
uint32_t row2 = 0x0;
|
||||
row2 |= (CodeWords & 0xFF) << 16;
|
||||
row2 |= (EpilogCount & 0xFFFF);
|
||||
streamer.EmitIntValue(row2, 4);
|
||||
}
|
||||
|
||||
// Epilog Start Index, Epilog Start Offset
|
||||
for (auto &I : EpilogInfo) {
|
||||
MCSymbol *EpilogStart = I.first;
|
||||
uint32_t EpilogIndex = I.second;
|
||||
uint32_t EpilogOffset =
|
||||
(uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
|
||||
if (EpilogOffset)
|
||||
EpilogOffset /= 4;
|
||||
uint32_t row3 = EpilogOffset;
|
||||
row3 |= (EpilogIndex & 0x3FF) << 22;
|
||||
streamer.EmitIntValue(row3, 4);
|
||||
}
|
||||
|
||||
// Emit prolog unwind instructions (in reverse order).
|
||||
uint8_t numInst = info->Instructions.size();
|
||||
for (uint8_t c = 0; c < numInst; ++c) {
|
||||
WinEH::Instruction inst = info->Instructions.back();
|
||||
info->Instructions.pop_back();
|
||||
ARM64EmitUnwindCode(streamer, info->Begin, inst);
|
||||
}
|
||||
|
||||
// Emit epilog unwind instructions
|
||||
for (auto &I : info->EpilogMap) {
|
||||
auto &EpilogInstrs = I.second;
|
||||
for (uint32_t i = 0; i < EpilogInstrs.size(); i++) {
|
||||
WinEH::Instruction inst = EpilogInstrs[i];
|
||||
ARM64EmitUnwindCode(streamer, info->Begin, inst);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
|
||||
assert(BytesMod >= 0);
|
||||
for (int i = 0; i < BytesMod; i++)
|
||||
streamer.EmitIntValue(0xE3, 1);
|
||||
|
||||
if (info->HandlesExceptions)
|
||||
streamer.EmitValue(
|
||||
MCSymbolRefExpr::create(info->ExceptionHandler,
|
||||
MCSymbolRefExpr::VK_COFF_IMGREL32, context),
|
||||
4);
|
||||
}
|
||||
|
||||
static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
|
||||
const WinEH::FrameInfo *info) {
|
||||
MCContext &context = streamer.getContext();
|
||||
|
||||
streamer.EmitValueToAlignment(4);
|
||||
EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
|
||||
streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
|
||||
MCSymbolRefExpr::VK_COFF_IMGREL32,
|
||||
context),
|
||||
4);
|
||||
}
|
||||
|
||||
void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
|
||||
// Emit the unwind info structs first.
|
||||
for (const auto &CFI : Streamer.getWinFrameInfos()) {
|
||||
MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
|
||||
Streamer.SwitchSection(XData);
|
||||
ARM64EmitUnwindInfo(Streamer, CFI.get());
|
||||
}
|
||||
|
||||
// Now emit RUNTIME_FUNCTION entries.
|
||||
for (const auto &CFI : Streamer.getWinFrameInfos()) {
|
||||
MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
|
||||
Streamer.SwitchSection(PData);
|
||||
ARM64EmitRuntimeFunction(Streamer, CFI.get());
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(
|
||||
MCStreamer &Streamer, WinEH::FrameInfo *info) const {
|
||||
// Switch sections (the static function above is meant to be called from
|
||||
// here and from Emit().
|
||||
MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
|
||||
Streamer.SwitchSection(XData);
|
||||
ARM64EmitUnwindInfo(Streamer, info);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "InstPrinter/AArch64InstPrinter.h"
|
||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||
#include "MCTargetDesc/AArch64MCTargetDesc.h"
|
||||
#include "MCTargetDesc/AArch64TargetStreamer.h"
|
||||
#include "Utils/AArch64BaseInfo.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -665,6 +666,8 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
OutStreamer->EmitLabel(LOHLabel);
|
||||
}
|
||||
|
||||
AArch64TargetStreamer *TS =
|
||||
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
|
||||
// Do any manual lowerings.
|
||||
switch (MI->getOpcode()) {
|
||||
default:
|
||||
@ -817,6 +820,100 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
case TargetOpcode::PATCHABLE_TAIL_CALL:
|
||||
LowerPATCHABLE_TAIL_CALL(*MI);
|
||||
return;
|
||||
|
||||
case AArch64::SEH_StackAlloc:
|
||||
TS->EmitARM64WinCFIAllocStack(MI->getOperand(0).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFPLR:
|
||||
TS->EmitARM64WinCFISaveFPLR(MI->getOperand(0).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFPLR_X:
|
||||
assert(MI->getOperand(0).getImm() < 0 &&
|
||||
"Pre increment SEH opcode must have a negative offset");
|
||||
TS->EmitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveReg:
|
||||
TS->EmitARM64WinCFISaveReg(MI->getOperand(0).getImm(),
|
||||
MI->getOperand(1).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveReg_X:
|
||||
assert(MI->getOperand(1).getImm() < 0 &&
|
||||
"Pre increment SEH opcode must have a negative offset");
|
||||
TS->EmitARM64WinCFISaveRegX(MI->getOperand(0).getImm(),
|
||||
-MI->getOperand(1).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveRegP:
|
||||
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
|
||||
"Non-consecutive registers not allowed for save_regp");
|
||||
TS->EmitARM64WinCFISaveRegP(MI->getOperand(0).getImm(),
|
||||
MI->getOperand(2).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveRegP_X:
|
||||
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
|
||||
"Non-consecutive registers not allowed for save_regp_x");
|
||||
assert(MI->getOperand(2).getImm() < 0 &&
|
||||
"Pre increment SEH opcode must have a negative offset");
|
||||
TS->EmitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(),
|
||||
-MI->getOperand(2).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFReg:
|
||||
TS->EmitARM64WinCFISaveFReg(MI->getOperand(0).getImm(),
|
||||
MI->getOperand(1).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFReg_X:
|
||||
assert(MI->getOperand(1).getImm() < 0 &&
|
||||
"Pre increment SEH opcode must have a negative offset");
|
||||
TS->EmitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(),
|
||||
-MI->getOperand(1).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFRegP:
|
||||
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
|
||||
"Non-consecutive registers not allowed for save_regp");
|
||||
TS->EmitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(),
|
||||
MI->getOperand(2).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SaveFRegP_X:
|
||||
assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) &&
|
||||
"Non-consecutive registers not allowed for save_regp_x");
|
||||
assert(MI->getOperand(2).getImm() < 0 &&
|
||||
"Pre increment SEH opcode must have a negative offset");
|
||||
TS->EmitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(),
|
||||
-MI->getOperand(2).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_SetFP:
|
||||
TS->EmitARM64WinCFISetFP();
|
||||
return;
|
||||
|
||||
case AArch64::SEH_AddFP:
|
||||
TS->EmitARM64WinCFIAddFP(MI->getOperand(0).getImm());
|
||||
return;
|
||||
|
||||
case AArch64::SEH_Nop:
|
||||
TS->EmitARM64WinCFINop();
|
||||
return;
|
||||
|
||||
case AArch64::SEH_PrologEnd:
|
||||
TS->EmitARM64WinCFIPrologEnd();
|
||||
return;
|
||||
|
||||
case AArch64::SEH_EpilogStart:
|
||||
TS->EmitARM64WinCFIEpilogStart();
|
||||
return;
|
||||
|
||||
case AArch64::SEH_EpilogEnd:
|
||||
TS->EmitARM64WinCFIEpilogEnd();
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, do the automated lowerings for everything else.
|
||||
|
@ -3138,6 +3138,28 @@ def F128CSEL : Pseudo<(outs FPR128:$Rd),
|
||||
let hasNoSchedulingInfo = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instructions used for emitting unwind opcodes on ARM64 Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
let isPseudo = 1 in {
|
||||
def SEH_StackAlloc : Pseudo<(outs), (ins i32imm:$size), []>, Sched<[]>;
|
||||
def SEH_SaveFPLR : Pseudo<(outs), (ins i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveFPLR_X : Pseudo<(outs), (ins i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveReg : Pseudo<(outs), (ins i32imm:$reg, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveReg_X : Pseudo<(outs), (ins i32imm:$reg, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveRegP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveRegP_X : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveFReg : Pseudo<(outs), (ins i32imm:$reg, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveFReg_X : Pseudo<(outs), (ins i32imm:$reg, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveFRegP : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SaveFRegP_X : Pseudo<(outs), (ins i32imm:$reg0, i32imm:$reg1, i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_SetFP : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
def SEH_AddFP : Pseudo<(outs), (ins i32imm:$offs), []>, Sched<[]>;
|
||||
def SEH_Nop : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
def SEH_PrologEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
def SEH_EpilogStart : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Floating point immediate move.
|
||||
|
@ -60,16 +60,6 @@ void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) {
|
||||
OS << "\t.inst\t0x" << Twine::utohexstr(Inst) << "\n";
|
||||
}
|
||||
|
||||
class AArch64TargetELFStreamer : public AArch64TargetStreamer {
|
||||
private:
|
||||
AArch64ELFStreamer &getStreamer();
|
||||
|
||||
void emitInst(uint32_t Inst) override;
|
||||
|
||||
public:
|
||||
AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
|
||||
};
|
||||
|
||||
/// Extend the generic ELFStreamer class so that it can emit mapping symbols at
|
||||
/// the appropriate points in the object files. These symbols are defined in the
|
||||
/// AArch64 ELF ABI:
|
||||
@ -197,6 +187,8 @@ private:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() {
|
||||
return static_cast<AArch64ELFStreamer &>(Streamer);
|
||||
}
|
||||
@ -205,8 +197,6 @@ void AArch64TargetELFStreamer::emitInst(uint32_t Inst) {
|
||||
getStreamer().emitInst(Inst);
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S,
|
||||
formatted_raw_ostream &OS,
|
||||
MCInstPrinter *InstPrint,
|
||||
@ -226,14 +216,4 @@ MCELFStreamer *createAArch64ELFStreamer(MCContext &Context,
|
||||
return S;
|
||||
}
|
||||
|
||||
MCTargetStreamer *
|
||||
createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
|
||||
const Triple &TT = STI.getTargetTriple();
|
||||
if (TT.isOSBinFormatELF())
|
||||
return new AArch64TargetELFStreamer(S);
|
||||
if (TT.isOSBinFormatCOFF())
|
||||
return new AArch64TargetWinCOFFStreamer(S);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -115,6 +115,7 @@ AArch64MCAsmInfoMicrosoftCOFF::AArch64MCAsmInfoMicrosoftCOFF() {
|
||||
|
||||
CommentString = ";";
|
||||
ExceptionsType = ExceptionHandling::WinEH;
|
||||
WinEHEncodingType = WinEH::EncodingType::Itanium;
|
||||
}
|
||||
|
||||
AArch64MCAsmInfoGNUCOFF::AArch64MCAsmInfoGNUCOFF() {
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "AArch64TargetStreamer.h"
|
||||
#include "llvm/MC/ConstantPools.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -52,3 +53,17 @@ void AArch64TargetStreamer::emitInst(uint32_t Inst) {
|
||||
|
||||
getStreamer().EmitBytes(StringRef(Buffer, 4));
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
MCTargetStreamer *
|
||||
createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
|
||||
const Triple &TT = STI.getTargetTriple();
|
||||
if (TT.isOSBinFormatELF())
|
||||
return new AArch64TargetELFStreamer(S);
|
||||
if (TT.isOSBinFormatCOFF())
|
||||
return new AArch64TargetWinCOFFStreamer(S);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -12,6 +12,10 @@
|
||||
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
|
||||
namespace {
|
||||
class AArch64ELFStreamer;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AArch64TargetStreamer : public MCTargetStreamer {
|
||||
@ -33,10 +37,75 @@ public:
|
||||
/// Callback used to implement the .inst directive.
|
||||
virtual void emitInst(uint32_t Inst);
|
||||
|
||||
virtual void EmitARM64WinCFIAllocStack(unsigned Size) {}
|
||||
virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveFPLRX(int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) {}
|
||||
virtual void EmitARM64WinCFISetFP() {}
|
||||
virtual void EmitARM64WinCFIAddFP(unsigned Size) {}
|
||||
virtual void EmitARM64WinCFINop() {}
|
||||
virtual void EmitARM64WinCFIPrologEnd() {}
|
||||
virtual void EmitARM64WinCFIEpilogStart() {}
|
||||
virtual void EmitARM64WinCFIEpilogEnd() {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AssemblerConstantPools> ConstantPools;
|
||||
};
|
||||
|
||||
class AArch64TargetELFStreamer : public AArch64TargetStreamer {
|
||||
private:
|
||||
AArch64ELFStreamer &getStreamer();
|
||||
|
||||
void emitInst(uint32_t Inst) override;
|
||||
|
||||
public:
|
||||
AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
|
||||
};
|
||||
|
||||
class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
|
||||
private:
|
||||
// True if we are processing SEH directives in an epilogue.
|
||||
bool InEpilogCFI = false;
|
||||
|
||||
// Symbol of the current epilog for which we are processing SEH directives.
|
||||
MCSymbol *CurrentEpilog = nullptr;
|
||||
public:
|
||||
AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S)
|
||||
: AArch64TargetStreamer(S) {}
|
||||
|
||||
// The unwind codes on ARM64 Windows are documented at
|
||||
// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
void EmitARM64WinCFIAllocStack(unsigned Size) override;
|
||||
void EmitARM64WinCFISaveFPLR(int Offset) override;
|
||||
void EmitARM64WinCFISaveFPLRX(int Offset) override;
|
||||
void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) override;
|
||||
void EmitARM64WinCFISetFP() override;
|
||||
void EmitARM64WinCFIAddFP(unsigned Size) override;
|
||||
void EmitARM64WinCFINop() override;
|
||||
void EmitARM64WinCFIPrologEnd() override;
|
||||
void EmitARM64WinCFIEpilogStart() override;
|
||||
void EmitARM64WinCFIEpilogEnd() override;
|
||||
private:
|
||||
void EmitARM64WinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
|
||||
};
|
||||
|
||||
MCTargetStreamer *
|
||||
createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
|
@ -11,12 +11,16 @@
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCWin64EH.h"
|
||||
#include "llvm/MC/MCWinCOFFStreamer.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class AArch64WinCOFFStreamer : public MCWinCOFFStreamer {
|
||||
Win64EH::ARM64UnwindEmitter EHStreamer;
|
||||
|
||||
public:
|
||||
friend class AArch64TargetWinCOFFStreamer;
|
||||
|
||||
@ -25,17 +29,168 @@ public:
|
||||
std::unique_ptr<MCObjectWriter> OW)
|
||||
: MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
|
||||
|
||||
void EmitWinEHHandlerData(SMLoc Loc) override;
|
||||
void EmitWindowsUnwindTables() override;
|
||||
void FinishImpl() override;
|
||||
};
|
||||
|
||||
void AArch64WinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) {
|
||||
MCStreamer::EmitWinEHHandlerData(Loc);
|
||||
|
||||
// We have to emit the unwind info now, because this directive
|
||||
// actually switches to the .xdata section!
|
||||
EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo());
|
||||
}
|
||||
|
||||
void AArch64WinCOFFStreamer::EmitWindowsUnwindTables() {
|
||||
if (!getNumWinFrameInfos())
|
||||
return;
|
||||
EHStreamer.Emit(*this);
|
||||
}
|
||||
|
||||
void AArch64WinCOFFStreamer::FinishImpl() {
|
||||
EmitFrames(nullptr);
|
||||
EmitWindowsUnwindTables();
|
||||
|
||||
MCWinCOFFStreamer::FinishImpl();
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Helper function to common out unwind code setup for those codes that can
|
||||
// belong to both prolog and epilog.
|
||||
// There are three types of Windows ARM64 SEH codes. They can
|
||||
// 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd
|
||||
// 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X
|
||||
// 3) take a register and an offset/size: all others
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinUnwindCode(unsigned UnwindCode,
|
||||
int Reg,
|
||||
int Offset) {
|
||||
auto &S = getStreamer();
|
||||
WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
|
||||
if (!CurFrame)
|
||||
return;
|
||||
MCSymbol *Label = S.EmitCFILabel();
|
||||
auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
|
||||
if (InEpilogCFI)
|
||||
CurFrame->EpilogMap[CurrentEpilog].push_back(Inst);
|
||||
else
|
||||
CurFrame->Instructions.push_back(Inst);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAllocStack(unsigned Size) {
|
||||
unsigned Op = Win64EH::UOP_AllocSmall;
|
||||
if (Size >= 16384)
|
||||
Op = Win64EH::UOP_AllocLarge;
|
||||
else if (Size >= 512)
|
||||
Op = Win64EH::UOP_AllocMedium;
|
||||
EmitARM64WinUnwindCode(Op, -1, Size);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLR(int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR, -1, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLRX(int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLRX, -1, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveReg(unsigned Reg,
|
||||
int Offset) {
|
||||
assert(Offset >= 0 && Offset <= 504 &&
|
||||
"Offset for save reg should be >= 0 && <= 504");
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveReg, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegX(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegX, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegP(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegP, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegPX(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFReg(unsigned Reg,
|
||||
int Offset) {
|
||||
assert(Offset >= 0 && Offset <= 504 &&
|
||||
"Offset for save reg should be >= 0 && <= 504");
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFReg, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegX(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegP(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegPX(unsigned Reg,
|
||||
int Offset) {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX, Reg, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISetFP() {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_SetFP, -1, 0);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAddFP(unsigned Offset) {
|
||||
assert(Offset <= 2040 && "UOP_AddFP must have offset <= 2040");
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_AddFP, -1, Offset);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFINop() {
|
||||
EmitARM64WinUnwindCode(Win64EH::UOP_Nop, -1, 0);
|
||||
}
|
||||
|
||||
// The functions below handle opcodes that can end up in either a prolog or
|
||||
// an epilog, but not both.
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIPrologEnd() {
|
||||
auto &S = getStreamer();
|
||||
WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
|
||||
if (!CurFrame)
|
||||
return;
|
||||
|
||||
MCSymbol *Label = S.EmitCFILabel();
|
||||
CurFrame->PrologEnd = Label;
|
||||
WinEH::Instruction Inst = WinEH::Instruction(Win64EH::UOP_End, Label, -1, 0);
|
||||
auto it = CurFrame->Instructions.begin();
|
||||
CurFrame->Instructions.insert(it, Inst);
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogStart() {
|
||||
auto &S = getStreamer();
|
||||
WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
|
||||
if (!CurFrame)
|
||||
return;
|
||||
|
||||
InEpilogCFI = true;
|
||||
CurrentEpilog = S.EmitCFILabel();
|
||||
}
|
||||
|
||||
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogEnd() {
|
||||
auto &S = getStreamer();
|
||||
WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
|
||||
if (!CurFrame)
|
||||
return;
|
||||
|
||||
InEpilogCFI = false;
|
||||
MCSymbol *Label = S.EmitCFILabel();
|
||||
WinEH::Instruction Inst = WinEH::Instruction(Win64EH::UOP_End, Label, -1, 0);
|
||||
CurFrame->EpilogMap[CurrentEpilog].push_back(Inst);
|
||||
CurrentEpilog = nullptr;
|
||||
}
|
||||
|
||||
MCWinCOFFStreamer *createAArch64WinCOFFStreamer(
|
||||
MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
|
||||
std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter,
|
||||
|
@ -17,20 +17,6 @@
|
||||
#include "AArch64TargetStreamer.h"
|
||||
#include "llvm/MC/MCWinCOFFStreamer.h"
|
||||
|
||||
namespace {
|
||||
class AArch64WinCOFFStreamer;
|
||||
|
||||
class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
|
||||
private:
|
||||
AArch64WinCOFFStreamer &getStreamer();
|
||||
|
||||
public:
|
||||
AArch64TargetWinCOFFStreamer(llvm::MCStreamer &S)
|
||||
: AArch64TargetStreamer(S) {}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
MCWinCOFFStreamer *createAArch64WinCOFFStreamer(
|
||||
|
120
test/CodeGen/AArch64/wineh1.mir
Normal file
120
test/CodeGen/AArch64/wineh1.mir
Normal file
@ -0,0 +1,120 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog -filetype=obj -disable-post-ra \
|
||||
# RUN: | llvm-readobj -unwind | FileCheck %s
|
||||
# This test case checks the basic validity of the .xdata section. It's
|
||||
# documented at:
|
||||
# https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
|
||||
|
||||
# We expect to see the following in the .xdata section:
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 92
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 28
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xc808 ; stp x19, x20, [sp, #64]
|
||||
# CHECK-NEXT: 0xd0c7 ; str x22, [sp, #56]
|
||||
# CHECK-NEXT: 0xd086 ; str x21, [sp, #48]
|
||||
# CHECK-NEXT: 0xc904 ; stp x23, x24, [sp, #32]
|
||||
# CHECK-NEXT: 0xc982 ; stp x25, x26, [sp, #16]
|
||||
# CHECK-NEXT: 0xce09 ; stp x27, x28, [sp, #-80]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 15
|
||||
# CHECK-NEXT: EpilogueStartIndex: 13
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64]
|
||||
# CHECK-NEXT: 0xd086 ; ldr x21, [sp, #48]
|
||||
# CHECK-NEXT: 0xe3 ; nop
|
||||
# CHECK-NEXT: 0xd0c7 ; ldr x22, [sp, #56]
|
||||
# CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32]
|
||||
# CHECK-NEXT: 0xc982 ; ldp x25, x26, [sp, #16]
|
||||
# CHECK-NEXT: 0xce09 ; ldp x27, x28, [sp], #80
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
...
|
||||
---
|
||||
name: test
|
||||
alignment: 2
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
liveins:
|
||||
- { reg: '$w0' }
|
||||
frameInfo:
|
||||
stackSize: 80
|
||||
maxAlignment: 8
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: true
|
||||
stack:
|
||||
- { id: 0, type: spill-slot, offset: -8, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x19' }
|
||||
- { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x20' }
|
||||
- { id: 2, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x21' }
|
||||
- { id: 3, type: spill-slot, offset: -32, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x22' }
|
||||
- { id: 4, type: spill-slot, offset: -40, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x23' }
|
||||
- { id: 5, type: spill-slot, offset: -48, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x24' }
|
||||
- { id: 6, type: spill-slot, offset: -56, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x25' }
|
||||
- { id: 7, type: spill-slot, offset: -64, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x26' }
|
||||
- { id: 8, type: spill-slot, offset: -72, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x27' }
|
||||
- { id: 9, type: spill-slot, offset: -80, size: 8, alignment: 8, stack-id: 0,
|
||||
callee-saved-register: '$x28' }
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1, $x27, $x28, $x25, $x26, $x23, $x24, $x21, $x22, $x19, $x20
|
||||
early-clobber $sp = frame-setup STPXpre killed $x27, killed $x28, $sp, -10 :: (store 8 into %stack.8), (store 8 into %stack.9)
|
||||
frame-setup SEH_SaveRegP_X 27, 28, -80
|
||||
frame-setup STPXi killed $x25, killed $x26, $sp, 2 :: (store 8 into %stack.6), (store 8 into %stack.7)
|
||||
frame-setup SEH_SaveRegP 25, 26, 16
|
||||
frame-setup STPXi killed $x23, killed $x24, $sp, 4 :: (store 8 into %stack.4), (store 8 into %stack.5)
|
||||
frame-setup SEH_SaveRegP 23, 24, 32
|
||||
frame-setup STRXui killed $x21, $sp, 6 :: (store 8 into %stack.2)
|
||||
frame-setup SEH_SaveReg 21, 48
|
||||
frame-setup STRXui killed $x22, $sp, 7 :: (store 8 into %stack.3)
|
||||
frame-setup SEH_SaveReg 22, 56
|
||||
frame-setup STPXi killed $x19, killed $x20, $sp, 8 :: (store 8 into %stack.0), (store 8 into %stack.1)
|
||||
frame-setup SEH_SaveRegP 19, 20, 64
|
||||
frame-setup SEH_PrologEnd
|
||||
$x19 = ADDXrr $x0, killed $x1
|
||||
$x20 = ADDXrr $x19, killed $x0
|
||||
$x21 = ADDXrr $x20, killed $x19
|
||||
$x22 = ADDXrr $x21, killed $x20
|
||||
$x23 = ADDXrr $x22, killed $x21
|
||||
$x24 = ADDXrr $x23, killed $x22
|
||||
$x25 = ADDXrr $x24, killed $x23
|
||||
$x26 = ADDXrr $x25, killed $x24
|
||||
$x27 = ADDXrr $x26, killed $x25
|
||||
$x28 = ADDXrr $x27, killed $x26
|
||||
frame-destroy SEH_EpilogStart
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 8 :: (load 8 from %stack.0), (load 8 from %stack.1)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 64
|
||||
$x21 = frame-destroy LDRXui $sp, 6 :: (load 8 from %stack.2)
|
||||
frame-destroy SEH_SaveReg 21, 48
|
||||
$x0 = COPY $x28
|
||||
frame-destroy SEH_Nop
|
||||
$x21 = frame-destroy LDRXui $sp, 6 :: (load 8 from %stack.2)
|
||||
frame-destroy SEH_SaveReg 22, 56
|
||||
$x23, $x24 = frame-destroy LDPXi $sp, 4 :: (load 8 from %stack.4), (load 8 from %stack.5)
|
||||
frame-destroy SEH_SaveRegP 23, 24, 32
|
||||
$x25, $x26 = frame-destroy LDPXi $sp, 2 :: (load 8 from %stack.6), (load 8 from %stack.7)
|
||||
frame-destroy SEH_SaveRegP 25, 26, 16
|
||||
early-clobber $sp, $x27, $x28 = frame-destroy LDPXpost $sp, 10 :: (load 8 from %stack.8), (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveRegP_X 27, 28, -80
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $x0
|
||||
|
||||
...
|
185
test/CodeGen/AArch64/wineh2.mir
Normal file
185
test/CodeGen/AArch64/wineh2.mir
Normal file
@ -0,0 +1,185 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -disable-post-ra -filetype=obj | llvm-readobj -unwind | FileCheck %s
|
||||
# Test that the pre/post increment save of a flating point register is correct.
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 136
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 40
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xc80e ; stp x19, x20, [sp, #112]
|
||||
# CHECK-NEXT: 0xc88c ; stp x21, x22, [sp, #96]
|
||||
# CHECK-NEXT: 0xc90a ; stp x23, x24, [sp, #80]
|
||||
# CHECK-NEXT: 0xc988 ; stp x25, x26, [sp, #64]
|
||||
# CHECK-NEXT: 0xca06 ; stp x27, x28, [sp, #48]
|
||||
# CHECK-NEXT: 0xdc45 ; str d9, [sp, #40]
|
||||
# CHECK-NEXT: 0xdc04 ; str d8, [sp, #32]
|
||||
# CHECK-NEXT: 0xd882 ; stp d10, d11, [sp, #16]
|
||||
# CHECK-NEXT: 0xde8f ; str d12, [sp, #-128]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 25
|
||||
# CHECK-NEXT: EpilogueStartIndex: 19
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112]
|
||||
# CHECK-NEXT: 0xc88c ; ldp x21, x22, [sp, #96]
|
||||
# CHECK-NEXT: 0xc90a ; ldp x23, x24, [sp, #80]
|
||||
# CHECK-NEXT: 0xc988 ; ldp x25, x26, [sp, #64]
|
||||
# CHECK-NEXT: 0xca06 ; ldp x27, x28, [sp, #48]
|
||||
# CHECK-NEXT: 0xdc04 ; ldr d8, [sp, #32]
|
||||
# CHECK-NEXT: 0xdc45 ; ldr d9, [sp, #40]
|
||||
# CHECK-NEXT: 0xd882 ; ldp d10, d11, [sp, #16]
|
||||
# CHECK-NEXT: 0xde8f ; ldr d12, [sp], #128
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
...
|
||||
---
|
||||
name: test
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 128
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 16
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: true
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 0
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x19', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x20', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x21', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x22', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 4, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x23', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 5, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x24', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -56, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x25', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 7, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x26', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 8, name: '', type: spill-slot, offset: -72, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x27', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 9, name: '', type: spill-slot, offset: -80, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x28', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 10, name: '', type: spill-slot, offset: -88, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d8', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 11, name: '', type: spill-slot, offset: -96, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d9', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 12, name: '', type: spill-slot, offset: -104, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d10', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 13, name: '', type: spill-slot, offset: -112, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d11', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 14, name: '', type: spill-slot, offset: -128, size: 8, alignment: 16,
|
||||
stack-id: 0, callee-saved-register: '$d12', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1, $d0, $d1, $d8, $d9, $d10, $d11, $d12, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27, $x28
|
||||
|
||||
early-clobber $sp = frame-setup STRDpre killed $d12, $sp, -128 :: (store 8 into %stack.14)
|
||||
frame-setup SEH_SaveFReg_X 12, -128
|
||||
frame-setup STPDi killed $d10, killed $d11, $sp, 2 :: (store 8 into %stack.12), (store 8 into %stack.13)
|
||||
frame-setup SEH_SaveFRegP 10, 11, 16
|
||||
frame-setup STRDui killed $d8, $sp, 4 :: (store 8 into %stack.10)
|
||||
frame-setup SEH_SaveFReg 8, 32
|
||||
frame-setup STRDui killed $d9, $sp, 5 :: (store 8 into %stack.11)
|
||||
frame-setup SEH_SaveFReg 9, 40
|
||||
frame-setup STPXi killed $x27, killed $x28, $sp, 6 :: (store 8 into %stack.8), (store 8 into %stack.9)
|
||||
frame-setup SEH_SaveRegP 27, 28, 48
|
||||
frame-setup STPXi killed $x25, killed $x26, $sp, 8 :: (store 8 into %stack.6), (store 8 into %stack.7)
|
||||
frame-setup SEH_SaveRegP 25, 26, 64
|
||||
frame-setup STPXi killed $x23, killed $x24, $sp, 10 :: (store 8 into %stack.4), (store 8 into %stack.5)
|
||||
frame-setup SEH_SaveRegP 23, 24, 80
|
||||
frame-setup STPXi killed $x21, killed $x22, $sp, 12 :: (store 8 into %stack.2), (store 8 into %stack.3)
|
||||
frame-setup SEH_SaveRegP 21, 22, 96
|
||||
frame-setup STPXi killed $x19, killed $x20, $sp, 14 :: (store 8 into %stack.0), (store 8 into %stack.1)
|
||||
frame-setup SEH_SaveRegP 19, 20, 112
|
||||
frame-setup SEH_PrologEnd
|
||||
$x19 = ADDXrr $x0, killed $x1
|
||||
$d8 = FADDDrr killed $d0, $d1
|
||||
$d9 = FADDDrr $d8, $d1
|
||||
$d10 = FADDDrr $d9, $d8
|
||||
$d11 = FADDDrr killed $d9, $d10
|
||||
$d12 = FADDDrr killed $d10, killed $d11
|
||||
$x20 = ADDXrr $x19, killed $x0
|
||||
$x21 = ADDXrr $x20, killed $x19
|
||||
$x22 = ADDXrr $x21, killed $x20
|
||||
$x23 = ADDXrr $x22, killed $x21
|
||||
$x24 = ADDXrr $x23, killed $x22
|
||||
$x25 = ADDXrr $x24, killed $x23
|
||||
$x26 = ADDXrr $x25, killed $x24
|
||||
$x27 = ADDXrr $x26, killed $x25
|
||||
$x28 = ADDXrr $x27, killed $x26
|
||||
$x0 = COPY $d12
|
||||
$x0 = ADDXrr $x0, killed $x28
|
||||
frame-destroy SEH_EpilogStart
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 14 :: (load 8 from %stack.0), (load 8 from %stack.1)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 112
|
||||
$x21, $x22 = frame-destroy LDPXi $sp, 12 :: (load 8 from %stack.2), (load 8 from %stack.3)
|
||||
frame-destroy SEH_SaveRegP 21, 22, 96
|
||||
$x23, $x24 = frame-destroy LDPXi $sp, 10 :: (load 8 from %stack.4), (load 8 from %stack.5)
|
||||
frame-destroy SEH_SaveRegP 23, 24, 80
|
||||
$x25, $x26 = frame-destroy LDPXi $sp, 8 :: (load 8 from %stack.6), (load 8 from %stack.7)
|
||||
frame-destroy SEH_SaveRegP 25, 26, 64
|
||||
$x27, $x28 = frame-destroy LDPXi $sp, 6 :: (load 8 from %stack.8), (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveRegP 27, 28, 48
|
||||
$d8 = frame-destroy LDRDui $sp, 4 :: (load 8 from %stack.10)
|
||||
frame-destroy SEH_SaveFReg 8, 32
|
||||
$d9 = frame-destroy LDRDui $sp, 5 :: (load 8 from %stack.11)
|
||||
frame-destroy SEH_SaveFReg 9, 40
|
||||
$d10, $d11 = frame-destroy LDPDi $sp, 2 :: (load 8 from %stack.12), (load 8 from %stack.13)
|
||||
frame-destroy SEH_SaveFRegP 10, 11, 16
|
||||
early-clobber $sp, $d12 = frame-destroy LDRDpost $sp, 128 :: (load 8 from %stack.14)
|
||||
frame-destroy SEH_SaveFReg_X 12, -128
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $x0
|
||||
|
||||
...
|
171
test/CodeGen/AArch64/wineh3.mir
Normal file
171
test/CodeGen/AArch64/wineh3.mir
Normal file
@ -0,0 +1,171 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -disable-post-ra -filetype=obj | llvm-readobj -unwind | FileCheck %s
|
||||
# Test that the register pairing of both general purpose and floating point
|
||||
# registers is correctly saved in the .xdata section, as well as the pre/post
|
||||
# increment of floating point register pairs.
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 124
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 32
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xc80c ; stp x19, x20, [sp, #96]
|
||||
# CHECK-NEXT: 0xc88a ; stp x21, x22, [sp, #80]
|
||||
# CHECK-NEXT: 0xc908 ; stp x23, x24, [sp, #64]
|
||||
# CHECK-NEXT: 0xc986 ; stp x25, x26, [sp, #48]
|
||||
# CHECK-NEXT: 0xca04 ; stp x27, x28, [sp, #32]
|
||||
# CHECK-NEXT: 0xd802 ; stp d8, d9, [sp, #16]
|
||||
# CHECK-NEXT: 0xda8d ; stp d10, d11, [sp, #-112]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 23
|
||||
# CHECK-NEXT: EpilogueStartIndex: 15
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xc80c ; ldp x19, x20, [sp, #96]
|
||||
# CHECK-NEXT: 0xc88a ; ldp x21, x22, [sp, #80]
|
||||
# CHECK-NEXT: 0xc908 ; ldp x23, x24, [sp, #64]
|
||||
# CHECK-NEXT: 0xc986 ; ldp x25, x26, [sp, #48]
|
||||
# CHECK-NEXT: 0xca04 ; ldp x27, x28, [sp, #32]
|
||||
# CHECK-NEXT: 0xd802 ; ldp d8, d9, [sp, #16]
|
||||
# CHECK-NEXT: 0xda8d ; ldp d10, d11, [sp], #112
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
...
|
||||
---
|
||||
name: test
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 112
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: true
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 0
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x19', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x20', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x21', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x22', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 4, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x23', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 5, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x24', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -56, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x25', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 7, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x26', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 8, name: '', type: spill-slot, offset: -72, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x27', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 9, name: '', type: spill-slot, offset: -80, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x28', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 10, name: '', type: spill-slot, offset: -88, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d8', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 11, name: '', type: spill-slot, offset: -96, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d9', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 12, name: '', type: spill-slot, offset: -104, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d10', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 13, name: '', type: spill-slot, offset: -112, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d11', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1, $d0, $d1, $d10, $d11, $d8, $d9, $x27, $x28, $x25, $x26, $x23, $x24, $x21, $x22, $x19, $x20
|
||||
|
||||
early-clobber $sp = frame-setup STPDpre killed $d10, killed $d11, $sp, -14 :: (store 8 into %stack.12), (store 8 into %stack.13)
|
||||
frame-setup SEH_SaveFRegP_X 10, 11, -112
|
||||
frame-setup STPDi killed $d8, killed $d9, $sp, 2 :: (store 8 into %stack.10), (store 8 into %stack.11)
|
||||
frame-setup SEH_SaveFRegP 8, 9, 16
|
||||
frame-setup STPXi killed $x27, killed $x28, $sp, 4 :: (store 8 into %stack.8), (store 8 into %stack.9)
|
||||
frame-setup SEH_SaveRegP 27, 28, 32
|
||||
frame-setup STPXi killed $x25, killed $x26, $sp, 6 :: (store 8 into %stack.6), (store 8 into %stack.7)
|
||||
frame-setup SEH_SaveRegP 25, 26, 48
|
||||
frame-setup STPXi killed $x23, killed $x24, $sp, 8 :: (store 8 into %stack.4), (store 8 into %stack.5)
|
||||
frame-setup SEH_SaveRegP 23, 24, 64
|
||||
frame-setup STPXi killed $x21, killed $x22, $sp, 10 :: (store 8 into %stack.2), (store 8 into %stack.3)
|
||||
frame-setup SEH_SaveRegP 21, 22, 80
|
||||
frame-setup STPXi killed $x19, killed $x20, $sp, 12 :: (store 8 into %stack.0), (store 8 into %stack.1)
|
||||
frame-setup SEH_SaveRegP 19, 20, 96
|
||||
frame-setup SEH_PrologEnd
|
||||
$x19 = ADDXrr $x0, killed $x1
|
||||
$d8 = FADDDrr killed $d0, $d1
|
||||
$d9 = FADDDrr $d8, $d1
|
||||
$d10 = FADDDrr $d9, $d8
|
||||
$d11 = FADDDrr killed $d9, $d10
|
||||
$x20 = ADDXrr $x19, killed $x0
|
||||
$x21 = ADDXrr $x20, killed $x19
|
||||
$x22 = ADDXrr $x21, killed $x20
|
||||
$x23 = ADDXrr $x22, killed $x21
|
||||
$x24 = ADDXrr $x23, killed $x22
|
||||
$x25 = ADDXrr $x24, killed $x23
|
||||
$x26 = ADDXrr $x25, killed $x24
|
||||
$x27 = ADDXrr $x26, killed $x25
|
||||
$x28 = ADDXrr $x27, killed $x26
|
||||
$x0 = COPY $d11
|
||||
$x0 = ADDXrr $x0, killed $x28
|
||||
frame-destroy SEH_EpilogStart
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 12 :: (load 8 from %stack.0), (load 8 from %stack.1)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 96
|
||||
$x21, $x22 = frame-destroy LDPXi $sp, 10 :: (load 8 from %stack.2), (load 8 from %stack.3)
|
||||
frame-destroy SEH_SaveRegP 21, 22, 80
|
||||
$x23, $x24 = frame-destroy LDPXi $sp, 8 :: (load 8 from %stack.4), (load 8 from %stack.5)
|
||||
frame-destroy SEH_SaveRegP 23, 24, 64
|
||||
$x25, $x26 = frame-destroy LDPXi $sp, 6 :: (load 8 from %stack.6), (load 8 from %stack.7)
|
||||
frame-destroy SEH_SaveRegP 25, 26, 48
|
||||
$x27, $x28 = frame-destroy LDPXi $sp, 4 :: (load 8 from %stack.8), (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveRegP 27, 28, 32
|
||||
$d8, $d9 = frame-destroy LDPDi $sp, 2 :: (load 8 from %stack.10), (load 8 from %stack.11)
|
||||
frame-destroy SEH_SaveFRegP 8, 9, 16
|
||||
early-clobber $sp, $d10, $d11 = frame-destroy LDPDpost $sp, 14 :: (load 8 from %stack.12), (load 8 from %stack.13)
|
||||
frame-destroy SEH_SaveFRegP_X 10, 11, -112
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $x0
|
||||
|
||||
...
|
228
test/CodeGen/AArch64/wineh4.mir
Normal file
228
test/CodeGen/AArch64/wineh4.mir
Normal file
@ -0,0 +1,228 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -disable-branch-fold -disable-post-ra -filetype=obj \
|
||||
# RUN: | llvm-readobj -unwind | FileCheck %s
|
||||
# Check that multiple epilgoues are correctly placed in .xdata.
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 164
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 2
|
||||
# CHECK-NEXT: ByteCodeLength: 48
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xc80c ; stp x19, x20, [sp, #96]
|
||||
# CHECK-NEXT: 0xc88a ; stp x21, x22, [sp, #80]
|
||||
# CHECK-NEXT: 0xc908 ; stp x23, x24, [sp, #64]
|
||||
# CHECK-NEXT: 0xc986 ; stp x25, x26, [sp, #48]
|
||||
# CHECK-NEXT: 0xca04 ; stp x27, x28, [sp, #32]
|
||||
# CHECK-NEXT: 0xd802 ; stp d8, d9, [sp, #16]
|
||||
# CHECK-NEXT: 0xda8d ; stp d10, d11, [sp, #-112]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 16
|
||||
# CHECK-NEXT: EpilogueStartIndex: 15
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xc80c ; ldp x19, x20, [sp, #96]
|
||||
# CHECK-NEXT: 0xc88a ; ldp x21, x22, [sp, #80]
|
||||
# CHECK-NEXT: 0xc908 ; ldp x23, x24, [sp, #64]
|
||||
# CHECK-NEXT: 0xc986 ; ldp x25, x26, [sp, #48]
|
||||
# CHECK-NEXT: 0xca04 ; ldp x27, x28, [sp, #32]
|
||||
# CHECK-NEXT: 0xd802 ; ldp d8, d9, [sp, #16]
|
||||
# CHECK-NEXT: 0xda8d ; ldp d10, d11, [sp], #112
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 33
|
||||
# CHECK-NEXT: EpilogueStartIndex: 30
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xc80c ; ldp x19, x20, [sp, #96]
|
||||
# CHECK-NEXT: 0xc88a ; ldp x21, x22, [sp, #80]
|
||||
# CHECK-NEXT: 0xc908 ; ldp x23, x24, [sp, #64]
|
||||
# CHECK-NEXT: 0xc986 ; ldp x25, x26, [sp, #48]
|
||||
# CHECK-NEXT: 0xca04 ; ldp x27, x28, [sp, #32]
|
||||
# CHECK-NEXT: 0xd802 ; ldp d8, d9, [sp, #16]
|
||||
# CHECK-NEXT: 0xda8d ; ldp d10, d11, [sp], #112
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
...
|
||||
---
|
||||
name: test
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 112
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: false
|
||||
hasCalls: false
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: true
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 0
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x19', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x20', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x21', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x22', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 4, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x23', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 5, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x24', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -56, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x25', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 7, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x26', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 8, name: '', type: spill-slot, offset: -72, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x27', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 9, name: '', type: spill-slot, offset: -80, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x28', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 10, name: '', type: spill-slot, offset: -88, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d8', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 11, name: '', type: spill-slot, offset: -96, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d9', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 12, name: '', type: spill-slot, offset: -104, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d10', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 13, name: '', type: spill-slot, offset: -112, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$d11', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
successors: %bb.2(0x40000000), %bb.1(0x40000000)
|
||||
liveins: $x0, $x1, $d0, $d1, $d10, $d11, $d8, $d9, $x27, $x28, $x25, $x26, $x23, $x24, $x21, $x22, $x19, $x20
|
||||
|
||||
early-clobber $sp = frame-setup STPDpre killed $d10, killed $d11, $sp, -14 :: (store 8 into %stack.12), (store 8 into %stack.13)
|
||||
frame-setup SEH_SaveFRegP_X 10, 11, -112
|
||||
frame-setup STPDi killed $d8, killed $d9, $sp, 2 :: (store 8 into %stack.10), (store 8 into %stack.11)
|
||||
frame-setup SEH_SaveFRegP 8, 9, 16
|
||||
frame-setup STPXi killed $x27, killed $x28, $sp, 4 :: (store 8 into %stack.8), (store 8 into %stack.9)
|
||||
frame-setup SEH_SaveRegP 27, 28, 32
|
||||
frame-setup STPXi killed $x25, killed $x26, $sp, 6 :: (store 8 into %stack.6), (store 8 into %stack.7)
|
||||
frame-setup SEH_SaveRegP 25, 26, 48
|
||||
frame-setup STPXi killed $x23, killed $x24, $sp, 8 :: (store 8 into %stack.4), (store 8 into %stack.5)
|
||||
frame-setup SEH_SaveRegP 23, 24, 64
|
||||
frame-setup STPXi killed $x21, killed $x22, $sp, 10 :: (store 8 into %stack.2), (store 8 into %stack.3)
|
||||
frame-setup SEH_SaveRegP 21, 22, 80
|
||||
frame-setup STPXi killed $x19, killed $x20, $sp, 12 :: (store 8 into %stack.0), (store 8 into %stack.1)
|
||||
frame-setup SEH_SaveRegP 19, 20, 96
|
||||
frame-setup SEH_PrologEnd
|
||||
frame-setup CFI_INSTRUCTION def_cfa_offset 112
|
||||
frame-setup CFI_INSTRUCTION offset $w19, -8
|
||||
frame-setup CFI_INSTRUCTION offset $w20, -16
|
||||
frame-setup CFI_INSTRUCTION offset $w21, -24
|
||||
frame-setup CFI_INSTRUCTION offset $w22, -32
|
||||
frame-setup CFI_INSTRUCTION offset $w23, -40
|
||||
frame-setup CFI_INSTRUCTION offset $w24, -48
|
||||
frame-setup CFI_INSTRUCTION offset $w25, -56
|
||||
frame-setup CFI_INSTRUCTION offset $w26, -64
|
||||
frame-setup CFI_INSTRUCTION offset $w27, -72
|
||||
frame-setup CFI_INSTRUCTION offset $w28, -80
|
||||
frame-setup CFI_INSTRUCTION offset $b8, -88
|
||||
frame-setup CFI_INSTRUCTION offset $b9, -96
|
||||
frame-setup CFI_INSTRUCTION offset $b10, -104
|
||||
frame-setup CFI_INSTRUCTION offset $b11, -112
|
||||
$x19 = ADDXrr $x0, killed $x1
|
||||
$d8 = FADDDrr killed $d0, $d1
|
||||
$d9 = FADDDrr $d8, $d1
|
||||
$d10 = FADDDrr $d9, $d8
|
||||
$d11 = FADDDrr killed $d9, $d10
|
||||
$x20 = SUBSXrr $x19, killed $x0, implicit-def $nzcv
|
||||
Bcc 1, %bb.2, implicit killed $nzcv
|
||||
B %bb.1
|
||||
|
||||
bb.1:
|
||||
liveins: $x19, $x20
|
||||
|
||||
$x21 = ADDXrr $x20, killed $x19
|
||||
$x22 = ADDXrr $x21, killed $x20
|
||||
$x23 = ADDXrr $x22, killed $x21
|
||||
$x24 = ADDXrr $x23, killed $x22
|
||||
$x25 = ADDXrr $x24, killed $x23
|
||||
$x26 = ADDXrr $x25, killed $x24
|
||||
$x27 = ADDXrr $x26, killed $x25
|
||||
$x28 = ADDXrr $x27, killed $x26
|
||||
$x0 = COPY $x28
|
||||
frame-destroy SEH_EpilogStart
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 12 :: (load 8 from %stack.0), (load 8 from %stack.1)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 96
|
||||
$x21, $x22 = frame-destroy LDPXi $sp, 10 :: (load 8 from %stack.2), (load 8 from %stack.3)
|
||||
frame-destroy SEH_SaveRegP 21, 22, 80
|
||||
$x23, $x24 = frame-destroy LDPXi $sp, 8 :: (load 8 from %stack.4), (load 8 from %stack.5)
|
||||
frame-destroy SEH_SaveRegP 23, 24, 64
|
||||
$x25, $x26 = frame-destroy LDPXi $sp, 6 :: (load 8 from %stack.6), (load 8 from %stack.7)
|
||||
frame-destroy SEH_SaveRegP 25, 26, 48
|
||||
$x27, $x28 = frame-destroy LDPXi $sp, 4 :: (load 8 from %stack.8), (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveRegP 27, 28, 32
|
||||
$d8, $d9 = frame-destroy LDPDi $sp, 2 :: (load 8 from %stack.10), (load 8 from %stack.11)
|
||||
frame-destroy SEH_SaveFRegP 8, 9, 16
|
||||
early-clobber $sp, $d10, $d11 = frame-destroy LDPDpost $sp, 14 :: (load 8 from %stack.12), (load 8 from %stack.13)
|
||||
frame-destroy SEH_SaveFRegP_X 10, 11, -112
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $x0
|
||||
|
||||
bb.2:
|
||||
liveins: $x28, $d11
|
||||
|
||||
$x0 = COPY $d11
|
||||
$x0 = ADDXrr $x0, killed $x28
|
||||
frame-destroy SEH_EpilogStart
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 12 :: (load 8 from %stack.0), (load 8 from %stack.1)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 96
|
||||
$x21, $x22 = frame-destroy LDPXi $sp, 10 :: (load 8 from %stack.2), (load 8 from %stack.3)
|
||||
frame-destroy SEH_SaveRegP 21, 22, 80
|
||||
$x23, $x24 = frame-destroy LDPXi $sp, 8 :: (load 8 from %stack.4), (load 8 from %stack.5)
|
||||
frame-destroy SEH_SaveRegP 23, 24, 64
|
||||
$x25, $x26 = frame-destroy LDPXi $sp, 6 :: (load 8 from %stack.6), (load 8 from %stack.7)
|
||||
frame-destroy SEH_SaveRegP 25, 26, 48
|
||||
$x27, $x28 = frame-destroy LDPXi $sp, 4 :: (load 8 from %stack.8), (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveRegP 27, 28, 32
|
||||
$d8, $d9 = frame-destroy LDPDi $sp, 2 :: (load 8 from %stack.10), (load 8 from %stack.11)
|
||||
frame-destroy SEH_SaveFRegP 8, 9, 16
|
||||
early-clobber $sp, $d10, $d11 = frame-destroy LDPDpost $sp, 14 :: (load 8 from %stack.12), (load 8 from %stack.13)
|
||||
frame-destroy SEH_SaveFRegP_X 10, 11, -112
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $x0
|
||||
|
||||
...
|
224
test/CodeGen/AArch64/wineh5.mir
Normal file
224
test/CodeGen/AArch64/wineh5.mir
Normal file
@ -0,0 +1,224 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -disable-post-ra -filetype=obj | llvm-readobj -unwind | FileCheck %s
|
||||
|
||||
# Check that that the large stack allocation is correctly represented in .xdata.
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 156
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 20
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xe002dac9 ; sub sp, #2993296
|
||||
# CHECK-NEXT: 0xe3 ; nop
|
||||
# CHECK-NEXT: 0xe3 ; nop
|
||||
# CHECK-NEXT: 0x42 ; stp x29, x30, [sp, #16]
|
||||
# CHECK-NEXT: 0xd53f ; str x28, [sp, #256]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 34
|
||||
# CHECK-NEXT: EpilogueStartIndex: 10
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xe002da00 ; add sp, #2990080
|
||||
# CHECK-NEXT: 0xc0c9 ; add sp, #3216
|
||||
# CHECK-NEXT: 0x42 ; ldp x29, x30, [sp, #16]
|
||||
# CHECK-NEXT: 0xd53f ; ldr x28, [sp], #256
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
|
||||
|
||||
--- |
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
; Function Attrs: noinline optnone
|
||||
define dso_local i32 @"?func@@YAHH@Z"(i32 %i) #0 {
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
%i.addr = alloca i32, align 4
|
||||
%A = alloca [748193 x i32], align 4
|
||||
%a = alloca i32, align 4
|
||||
%B = alloca [123 x i32], align 4
|
||||
store i32 %i, i32* %i.addr, align 4
|
||||
%0 = load i32, i32* %i.addr, align 4
|
||||
%add = add nsw i32 %0, 2
|
||||
store i32 %add, i32* %a, align 4
|
||||
%call = call i32 @"?func2@@YAHXZ"()
|
||||
%1 = load i32, i32* %i.addr, align 4
|
||||
%cmp = icmp sgt i32 %1, 2
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%call1 = call i32 @"?func2@@YAHXZ"()
|
||||
store i32 %call1, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%arraydecay = getelementptr inbounds [123 x i32], [123 x i32]* %B, i32 0, i32 0
|
||||
%call2 = call i32 @"?func3@@YAHPEAH@Z"(i32* %arraydecay)
|
||||
store i32 %call2, i32* %retval, align 4
|
||||
br label %return
|
||||
|
||||
return: ; preds = %if.else, %if.then
|
||||
%2 = load i32, i32* %retval, align 4
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
declare dso_local i32 @"?func2@@YAHXZ"() #1
|
||||
|
||||
declare dso_local i32 @"?func3@@YAHPEAH@Z"(i32*) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #2
|
||||
|
||||
attributes #0 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #2 = { nounwind }
|
||||
|
||||
!llvm.module.flags = !{!0}
|
||||
|
||||
!0 = !{i32 1, !"wchar_size", i32 2}
|
||||
|
||||
...
|
||||
---
|
||||
name: '?func@@YAHH@Z'
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
selected: true
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 2993328
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 16
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 2993276
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: retval, type: default, offset: -36, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -4, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 1, name: i.addr, type: default, offset: -40, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -8, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 2, name: A, type: default, offset: -2992812, size: 2992772, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -2992780, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 3, name: a, type: default, offset: -2992816, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -2992784, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 4, name: B, type: default, offset: -2993308, size: 492, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -2993276, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 5, name: '', type: spill-slot, offset: -2993320, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -2993324, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 7, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$fp', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 8, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 9, name: '', type: spill-slot, offset: -32, size: 8, alignment: 16,
|
||||
stack-id: 0, callee-saved-register: '$x28', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.1.entry:
|
||||
successors: %bb.2(0x40000000), %bb.3(0x40000000)
|
||||
liveins: $w0, $x28, $fp, $lr
|
||||
|
||||
early-clobber $sp = frame-setup STRXpre killed $x28, $sp, -32 :: (store 8 into %stack.9)
|
||||
frame-setup SEH_SaveReg_X 28, -256
|
||||
frame-setup STPXi killed $fp, killed $lr, $sp, 2 :: (store 8 into %stack.7), (store 8 into %stack.8)
|
||||
frame-setup SEH_SaveFPLR 16
|
||||
$x15 = frame-setup MOVi64imm 187081
|
||||
frame-setup SEH_Nop
|
||||
frame-setup BL &__chkstk, implicit-def $lr, implicit $sp, implicit $x15
|
||||
frame-setup SEH_Nop
|
||||
$sp = frame-setup SUBXrx64 killed $sp, killed $x15, 28
|
||||
frame-setup SEH_StackAlloc 2993296
|
||||
frame-setup SEH_PrologEnd
|
||||
$x8 = ADDXri $sp, 730, 12
|
||||
$x8 = ADDXri $x8, 3208, 0
|
||||
renamable $w9 = MOVi32imm 2
|
||||
STRWui killed renamable $w0, renamable $x8, 0 :: (store 4 into %ir.i.addr)
|
||||
renamable $w0 = LDRWui renamable $x8, 0 :: (load 4 from %ir.i.addr)
|
||||
renamable $w0 = ADDWri killed renamable $w0, 2, 0
|
||||
STRWui killed renamable $w0, $sp, 128 :: (store 4 into %ir.a)
|
||||
STRXui killed $x8, $sp, 1 :: (store 8 into %stack.5)
|
||||
STRWui killed $w9, $sp, 1 :: (store 4 into %stack.6)
|
||||
BL @"?func2@@YAHXZ", csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0
|
||||
$x8 = LDRXui $sp, 1 :: (load 8 from %stack.5)
|
||||
renamable $w9 = LDRWui killed renamable $x8, 0 :: (load 4 from %ir.i.addr)
|
||||
$w10 = LDRWui $sp, 1 :: (load 4 from %stack.6)
|
||||
$wzr = SUBSWrr killed renamable $w9, killed renamable $w10, implicit-def $nzcv
|
||||
renamable $w9 = CSINCWr $wzr, $wzr, 13, implicit $nzcv
|
||||
TBNZW killed renamable $w9, 0, %bb.2
|
||||
B %bb.3
|
||||
|
||||
bb.2.if.then:
|
||||
successors: %bb.4(0x80000000)
|
||||
|
||||
BL @"?func2@@YAHXZ", csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0
|
||||
$x8 = LDRXui $sp, 1 :: (load 8 from %stack.5)
|
||||
STRWui killed renamable $w0, killed renamable $x8, 1 :: (store 4 into %ir.retval)
|
||||
B %bb.4
|
||||
|
||||
bb.3.if.else:
|
||||
successors: %bb.4(0x80000000)
|
||||
|
||||
$x8 = ADDXri $sp, 20, 0
|
||||
$x0 = COPY killed renamable $x8
|
||||
BL @"?func3@@YAHPEAH@Z", csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit killed $x0, implicit-def $w0
|
||||
$x8 = LDRXui $sp, 1 :: (load 8 from %stack.5)
|
||||
STRWui killed renamable $w0, killed renamable $x8, 1 :: (store 4 into %ir.retval)
|
||||
|
||||
bb.4.return:
|
||||
$x8 = LDRXui $sp, 1 :: (load 8 from %stack.5)
|
||||
renamable $w0 = LDRWui killed renamable $x8, 1 :: (load 4 from %ir.retval)
|
||||
frame-destroy SEH_EpilogStart
|
||||
$sp = frame-destroy ADDXri $sp, 730, 12
|
||||
frame-destroy SEH_StackAlloc 2990080
|
||||
$sp = frame-destroy ADDXri $sp, 3216, 0
|
||||
frame-destroy SEH_StackAlloc 3216
|
||||
$fp, $lr = frame-destroy LDPXi $sp, 2 :: (load 8 from %stack.7), (load 8 from %stack.8)
|
||||
frame-destroy SEH_SaveFPLR 16
|
||||
early-clobber $sp, $x28 = frame-destroy LDRXpost $sp, 32 :: (load 8 from %stack.9)
|
||||
frame-destroy SEH_SaveReg_X 28, -256
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit killed $w0
|
||||
|
||||
...
|
138
test/CodeGen/AArch64/wineh6.mir
Normal file
138
test/CodeGen/AArch64/wineh6.mir
Normal file
@ -0,0 +1,138 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -disable-post-ra -filetype=obj | llvm-readobj -unwind | FileCheck %s
|
||||
# Check save_fplr_x, set_fp, alloc_s
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 92
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 8
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0x02 ; sub sp, #32
|
||||
# CHECK-NEXT: 0xe1 ; mov fp, sp
|
||||
# CHECK-NEXT: 0x81 ; stp x29, x30, [sp, #-16]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 20
|
||||
# CHECK-NEXT: EpilogueStartIndex: 4
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xe1 ; mov fp, sp
|
||||
# CHECK-NEXT: 0x81 ; ldp x29, x30, [sp], #16
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
...
|
||||
---
|
||||
name: '?func@@YAHHHHH@Z'
|
||||
alignment: 3
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
- { reg: '$w1', virtual-reg: '' }
|
||||
- { reg: '$w2', virtual-reg: '' }
|
||||
- { reg: '$w3', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 48
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 24
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: default, offset: -20, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -4, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 1, name: '', type: default, offset: -24, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -8, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 2, name: '', type: default, offset: -28, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -12, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 3, name: '', type: default, offset: -32, size: 4, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -16, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 4, name: '', type: default, offset: -40, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -24, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 5, name: '', type: variable-sized, offset: -40,
|
||||
alignment: 1, stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -24, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 7, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$fp', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 8, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $w0, $w1, $w2, $w3, $lr
|
||||
|
||||
early-clobber $sp = frame-setup STPXpre killed $fp, killed $lr, $sp, -2 :: (store 8 into %stack.7), (store 8 into %stack.8)
|
||||
frame-setup SEH_SaveFPLR_X -16
|
||||
$fp = frame-setup ADDXri $sp, 0, 0
|
||||
frame-setup SEH_SetFP
|
||||
$sp = frame-setup SUBXri $sp, 32, 0
|
||||
frame-setup SEH_StackAlloc 32
|
||||
frame-setup SEH_PrologEnd
|
||||
STURWi killed renamable $w3, $fp, -4
|
||||
STURWi killed renamable $w2, $fp, -8
|
||||
STURWi killed renamable $w1, $fp, -12
|
||||
STURWi killed renamable $w0, $fp, -16
|
||||
renamable $x8 = LDURSWi $fp, -16
|
||||
renamable $x8 = ADDXri killed renamable $x8, 15, 0
|
||||
renamable $x8 = UBFMXri killed renamable $x8, 4, 63
|
||||
$x15 = COPY renamable $x8
|
||||
STURXi killed $x8, $fp, -32 :: (store 8 into %stack.6)
|
||||
BL &__chkstk, csr_aarch64_stackprobe_windows, implicit-def dead $lr, implicit $sp, implicit killed $x15
|
||||
renamable $x8 = COPY $sp
|
||||
$x15 = LDURXi $fp, -32 :: (load 8 from %stack.6)
|
||||
renamable $x8 = SUBSXrs killed renamable $x8, killed renamable $x15, 4, implicit-def dead $nzcv
|
||||
$sp = COPY renamable $x8
|
||||
STURXi killed renamable $x8, $fp, -24
|
||||
renamable $x0 = LDURXi $fp, -24
|
||||
renamable $w1 = COPY $wzr
|
||||
$w0 = COPY killed renamable $w1
|
||||
frame-destroy SEH_EpilogStart
|
||||
$sp = frame-destroy ADDXri $fp, 0, 0
|
||||
frame-destroy SEH_SetFP
|
||||
early-clobber $sp, $fp, $lr = frame-destroy LDPXpost $sp, 2
|
||||
frame-destroy SEH_SaveFPLR_X -16
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit killed $w0
|
||||
|
||||
...
|
134
test/CodeGen/AArch64/wineh7.mir
Normal file
134
test/CodeGen/AArch64/wineh7.mir
Normal file
@ -0,0 +1,134 @@
|
||||
# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog \
|
||||
# RUN: -filetype=obj -disable-post-ra | llvm-readobj -unwind | FileCheck %s
|
||||
# Check AddFP
|
||||
|
||||
# CHECK: ExceptionData {
|
||||
# CHECK-NEXT: FunctionLength: 72
|
||||
# CHECK-NEXT: Version: 0
|
||||
# CHECK-NEXT: ExceptionData: No
|
||||
# CHECK-NEXT: EpiloguePacked: No
|
||||
# CHECK-NEXT: EpilogueScopes: 1
|
||||
# CHECK-NEXT: ByteCodeLength: 16
|
||||
# CHECK-NEXT: Prologue [
|
||||
# CHECK-NEXT: 0xe204 ; add fp, sp, #32
|
||||
# CHECK-NEXT: 0x44 ; stp x29, x30, [sp, #32]
|
||||
# CHECK-NEXT: 0xc802 ; stp x19, x20, [sp, #16]
|
||||
# CHECK-NEXT: 0xcc85 ; stp x21, x22, [sp, #-48]!
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: EpilogueScopes [
|
||||
# CHECK-NEXT: EpilogueScope {
|
||||
# CHECK-NEXT: StartOffset: 13
|
||||
# CHECK-NEXT: EpilogueStartIndex: 8
|
||||
# CHECK-NEXT: Opcodes [
|
||||
# CHECK-NEXT: 0xe204 ; add fp, sp, #32
|
||||
# CHECK-NEXT: 0x44 ; ldp x29, x30, [sp, #32]
|
||||
# CHECK-NEXT: 0xc802 ; ldp x19, x20, [sp, #16]
|
||||
# CHECK-NEXT: 0xcc85 ; ldp x21, x22, [sp], #48
|
||||
# CHECK-NEXT: 0xe4 ; end
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: }
|
||||
|
||||
...
|
||||
---
|
||||
name: '?func@@YAHHHHH@Z'
|
||||
alignment: 3
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
- { reg: '$w1', virtual-reg: '' }
|
||||
- { reg: '$w2', virtual-reg: '' }
|
||||
- { reg: '$w3', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 48
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 0
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: '', type: variable-sized, offset: -48,
|
||||
alignment: 1, stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: 0, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
- { id: 1, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$fp', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 2, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 3, name: '', type: spill-slot, offset: -24, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x19', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 4, name: '', type: spill-slot, offset: -32, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x20', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 5, name: '', type: spill-slot, offset: -40, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x21', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
- { id: 6, name: '', type: spill-slot, offset: -48, size: 8, alignment: 8,
|
||||
stack-id: 0, callee-saved-register: '$x22', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $w0, $w1, $w2, $w3, $x21, $x22, $x19, $x20, $lr
|
||||
|
||||
early-clobber $sp = frame-setup STPXpre killed $x21, killed $x22, $sp, -6 :: (store 8 into %stack.5), (store 8 into %stack.6)
|
||||
frame-setup SEH_SaveRegP_X 21, 22, -48
|
||||
frame-setup STPXi killed $x19, killed $x20, $sp, 2 :: (store 8 into %stack.3), (store 8 into %stack.4)
|
||||
frame-setup SEH_SaveRegP 19, 20, 16
|
||||
frame-setup STPXi killed $fp, killed $lr, $sp, 4 :: (store 8 into %stack.1), (store 8 into %stack.2)
|
||||
frame-setup SEH_SaveFPLR 32
|
||||
$fp = frame-setup ADDXri $sp, 32, 0
|
||||
frame-setup SEH_AddFP 32
|
||||
frame-setup SEH_PrologEnd
|
||||
renamable $w19 = COPY $w3
|
||||
renamable $w0 = KILL $w0, implicit-def $x0
|
||||
renamable $w20 = COPY $w2
|
||||
renamable $w21 = COPY $w1
|
||||
renamable $x8 = SBFMXri killed renamable $x0, 0, 31
|
||||
renamable $x9 = ADDXri killed renamable $x8, 15, 0
|
||||
renamable $x15 = UBFMXri killed renamable $x9, 4, 63
|
||||
renamable $x8 = COPY $sp
|
||||
renamable $x22 = SUBXrs killed renamable $x8, killed renamable $x15, 4
|
||||
$sp = COPY renamable $x22
|
||||
$x0 = COPY renamable $x22
|
||||
renamable $w8 = LDRWroW killed renamable $x22, killed renamable $w21, 1, 1
|
||||
renamable $w9 = ADDWrr killed renamable $w19, killed renamable $w20
|
||||
renamable $w0 = ADDWrr killed renamable $w9, killed renamable $w8
|
||||
frame-destroy SEH_EpilogStart
|
||||
$sp = frame-destroy SUBXri $fp, 32, 0
|
||||
frame-destroy SEH_AddFP 32
|
||||
$fp, $lr = frame-destroy LDPXi $sp, 4 :: (load 8 from %stack.1), (load 8 from %stack.2)
|
||||
frame-destroy SEH_SaveFPLR 32
|
||||
$x19, $x20 = frame-destroy LDPXi $sp, 2 :: (load 8 from %stack.3), (load 8 from %stack.4)
|
||||
frame-destroy SEH_SaveRegP 19, 20, 16
|
||||
early-clobber $sp, $x21, $x22 = frame-destroy LDPXpost $sp, 6 :: (load 8 from %stack.5), (load 8 from %stack.6)
|
||||
frame-destroy SEH_SaveRegP_X 21, 22, -48
|
||||
frame-destroy SEH_EpilogEnd
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
146
test/CodeGen/AArch64/wineh_shrinkwrap.mir
Normal file
146
test/CodeGen/AArch64/wineh_shrinkwrap.mir
Normal file
@ -0,0 +1,146 @@
|
||||
# RUN: llc -O2 -o - %s -mtriple=aarch64-windows -start-before=shrink-wrap \
|
||||
# RUN: -stop-after=prologepilog | FileCheck %s --check-prefix=WIN64
|
||||
# RUN: llc -O2 -o - %s -mtriple=aarch64-linux -start-before=shrink-wrap \
|
||||
# RUN: -stop-after=prologepilog | FileCheck %s --check-prefix=LINUX
|
||||
|
||||
# This tests checks that shrink wrapping bails out on Windows AMR64 due to the
|
||||
# use of Windows CFI. We don't currently support fragments for WIndows EH on
|
||||
# ARM64.
|
||||
# The same test gets shrink wrapped on Linux ARM64.
|
||||
|
||||
# WIN64-LABEL: bb.0.entry:
|
||||
# WIN64: early-clobber $sp = frame-setup STRXpre killed $x28, $sp, -32
|
||||
# WIN64-LABEL: bb.1:
|
||||
# WIN64-LABEL: bb.2.if.then:
|
||||
|
||||
# LINUX-LABEL: bb.0.entry:
|
||||
# LINUX-LABEL: bb.1:
|
||||
# LINUX-LABEL: bb.2.if.then:
|
||||
# LINUX: early-clobber $sp = frame-setup STRXpre killed $x28, $sp, -32
|
||||
--- |
|
||||
; ModuleID = 'shrink.cpp'
|
||||
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-windows-msvc19.11.0"
|
||||
|
||||
define dso_local i32 @"?func@@YAHHH@Z"(i32 %a, i32 %b) local_unnamed_addr #0 {
|
||||
entry:
|
||||
%A = alloca [1000 x i32], align 4
|
||||
%cmp = icmp sgt i32 %a, 1
|
||||
br i1 %cmp, label %if.then, label %return
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%0 = bitcast [1000 x i32]* %A to i8*
|
||||
call void @llvm.lifetime.start.p0i8(i64 4000, i8* nonnull %0) #3
|
||||
%arraydecay2 = bitcast [1000 x i32]* %A to i32*
|
||||
call void @"?init@@YAXPEAH@Z"(i32* nonnull %arraydecay2)
|
||||
%arrayidx = getelementptr inbounds [1000 x i32], [1000 x i32]* %A, i64 0, i64 100
|
||||
%1 = load i32, i32* %arrayidx, align 4, !tbaa !2
|
||||
%add = add i32 %b, 1
|
||||
%add1 = add i32 %add, %1
|
||||
call void @llvm.lifetime.end.p0i8(i64 4000, i8* nonnull %0) #3
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry, %if.then
|
||||
%retval.0 = phi i32 [ %add1, %if.then ], [ 0, %entry ]
|
||||
ret i32 %retval.0
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
|
||||
|
||||
declare dso_local void @"?init@@YAXPEAH@Z"(i32*) local_unnamed_addr #2
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #3
|
||||
|
||||
attributes #0 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #1 = { argmemonly nounwind }
|
||||
attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
|
||||
attributes #3 = { nounwind }
|
||||
|
||||
!llvm.module.flags = !{!0}
|
||||
!llvm.ident = !{!1}
|
||||
|
||||
!0 = !{i32 1, !"wchar_size", i32 2}
|
||||
!1 = !{!"clang version 8.0.0"}
|
||||
!2 = !{!3, !3, i64 0}
|
||||
!3 = !{!"int", !4, i64 0}
|
||||
!4 = !{!"omnipotent char", !5, i64 0}
|
||||
!5 = !{!"Simple C++ TBAA"}
|
||||
|
||||
...
|
||||
---
|
||||
name: '?func@@YAHHH@Z'
|
||||
alignment: 2
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
liveins:
|
||||
- { reg: '$w0', virtual-reg: '' }
|
||||
- { reg: '$w1', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 0
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 4
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
cvBytesOfCalleeSavedRegisters: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 4000
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack:
|
||||
stack:
|
||||
- { id: 0, name: A, type: default, offset: 0, size: 4000, alignment: 4,
|
||||
stack-id: 0, callee-saved-register: '', callee-saved-restored: true,
|
||||
local-offset: -4000, debug-info-variable: '', debug-info-expression: '',
|
||||
debug-info-location: '' }
|
||||
constants:
|
||||
body: |
|
||||
bb.0.entry:
|
||||
successors: %bb.2(0x40000000), %bb.1(0x40000000)
|
||||
liveins: $w0, $w1
|
||||
|
||||
dead $wzr = SUBSWri killed renamable $w0, 2, 0, implicit-def $nzcv
|
||||
Bcc 10, %bb.2, implicit killed $nzcv
|
||||
|
||||
bb.1:
|
||||
successors: %bb.3(0x80000000)
|
||||
|
||||
renamable $w0 = COPY $wzr
|
||||
B %bb.3
|
||||
|
||||
bb.2.if.then:
|
||||
successors: %bb.3(0x80000000)
|
||||
liveins: $w1
|
||||
|
||||
renamable $w19 = COPY $w1
|
||||
ADJCALLSTACKDOWN 0, 0, implicit-def dead $sp, implicit $sp
|
||||
$x0 = ADDXri %stack.0.A, 0, 0
|
||||
BL @"?init@@YAXPEAH@Z", csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit-def $sp
|
||||
ADJCALLSTACKUP 0, 0, implicit-def dead $sp, implicit $sp
|
||||
renamable $w8 = LDRWui %stack.0.A, 100 :: (dereferenceable load 4 from %ir.arrayidx, !tbaa !2)
|
||||
renamable $w8 = ADDWrr killed renamable $w19, killed renamable $w8
|
||||
renamable $w0 = ADDWri killed renamable $w8, 1, 0
|
||||
|
||||
bb.3.return:
|
||||
liveins: $w0
|
||||
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
Loading…
Reference in New Issue
Block a user