-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[AArch64] Implement assembler support for new SVE SEH unwind opcodes. #137895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-llvm-support Author: Eli Friedman (efriedma-quic) ChangesIn order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows. Full diff: https://github.com/llvm/llvm-project/pull/137895.diff 9 Files Affected:
diff --git a/llvm/include/llvm/Support/Win64EH.h b/llvm/include/llvm/Support/Win64EH.h
index 8a9be15373917..ec3413b31ee4a 100644
--- a/llvm/include/llvm/Support/Win64EH.h
+++ b/llvm/include/llvm/Support/Win64EH.h
@@ -75,6 +75,9 @@ enum UnwindOpcodes {
UOP_SaveAnyRegDPX,
UOP_SaveAnyRegQX,
UOP_SaveAnyRegQPX,
+ UOP_AllocZ,
+ UOP_SaveZReg,
+ UOP_SavePReg,
// The following set of unwind opcodes is for ARM. They are documented at
// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index bd5cf354659b6..7021c3e31789b 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -421,6 +421,9 @@ static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
case Win64EH::UOP_PACSignLR:
Count += 1;
break;
+ case Win64EH::UOP_AllocZ:
+ Count += 2;
+ break;
case Win64EH::UOP_SaveAnyRegI:
case Win64EH::UOP_SaveAnyRegIP:
case Win64EH::UOP_SaveAnyRegD:
@@ -433,6 +436,8 @@ static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
case Win64EH::UOP_SaveAnyRegDPX:
case Win64EH::UOP_SaveAnyRegQX:
case Win64EH::UOP_SaveAnyRegQPX:
+ case Win64EH::UOP_SaveZReg:
+ case Win64EH::UOP_SavePReg:
Count += 3;
break;
}
@@ -640,6 +645,37 @@ static void ARM64EmitUnwindCode(MCStreamer &streamer,
streamer.emitInt8(b);
break;
}
+ case Win64EH::UOP_AllocZ: {
+ b = 0xDF;
+ streamer.emitInt8(b);
+ b = inst.Offset;
+ streamer.emitInt8(b);
+ break;
+ }
+ case Win64EH::UOP_SaveZReg: {
+ assert(inst.Register >= 8 && inst.Register <= 23);
+ assert(inst.Offset < 256);
+ b = 0xE7;
+ streamer.emitInt8(b);
+ reg = inst.Register - 8;
+ b = ((inst.Offset & 0xC0) >> 1) | reg;
+ streamer.emitInt8(b);
+ b = 0xC0 | (inst.Offset & 0x3F);
+ streamer.emitInt8(b);
+ break;
+ }
+ case Win64EH::UOP_SavePReg: {
+ assert(inst.Register >= 4 && inst.Register <= 15);
+ assert(inst.Offset < 256);
+ b = 0xE7;
+ streamer.emitInt8(b);
+ reg = inst.Register - 4;
+ b = ((inst.Offset & 0xC0) >> 1) | 0x10 | reg;
+ streamer.emitInt8(b);
+ b = 0xC0 | (inst.Offset & 0x3F);
+ streamer.emitInt8(b);
+ break;
+ }
}
}
@@ -1004,6 +1040,9 @@ static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
case Win64EH::UOP_SaveAnyRegDPX:
case Win64EH::UOP_SaveAnyRegQX:
case Win64EH::UOP_SaveAnyRegQPX:
+ case Win64EH::UOP_AllocZ:
+ case Win64EH::UOP_SaveZReg:
+ case Win64EH::UOP_SavePReg:
// These are never canonical; they don't show up with the usual Arm64
// calling convention.
return false;
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index e178c5027571a..bcd5fde3b8e27 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -230,6 +230,9 @@ class AArch64AsmParser : public MCTargetAsmParser {
bool parseDirectiveSEHClearUnwoundToCall(SMLoc L);
bool parseDirectiveSEHPACSignLR(SMLoc L);
bool parseDirectiveSEHSaveAnyReg(SMLoc L, bool Paired, bool Writeback);
+ bool parseDirectiveSEHAllocZ(SMLoc L);
+ bool parseDirectiveSEHSaveZReg(SMLoc L);
+ bool parseDirectiveSEHSavePReg(SMLoc L);
bool parseDirectiveAeabiSubSectionHeader(SMLoc L);
bool parseDirectiveAeabiAArch64Attr(SMLoc L);
@@ -7111,6 +7114,12 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveSEHSaveAnyReg(Loc, false, true);
else if (IDVal == ".seh_save_any_reg_px")
parseDirectiveSEHSaveAnyReg(Loc, true, true);
+ else if (IDVal == ".seh_allocz")
+ parseDirectiveSEHAllocZ(Loc);
+ else if (IDVal == ".seh_save_zreg")
+ parseDirectiveSEHSaveZReg(Loc);
+ else if (IDVal == ".seh_save_preg")
+ parseDirectiveSEHSavePReg(Loc);
else
return true;
} else if (IsELF) {
@@ -7856,6 +7865,54 @@ bool AArch64AsmParser::parseDirectiveSEHSaveAnyReg(SMLoc L, bool Paired,
return false;
}
+/// parseDirectiveAllocZ
+/// ::= .seh_allocz
+bool AArch64AsmParser::parseDirectiveSEHAllocZ(SMLoc L) {
+ int64_t Offset;
+ if (parseImmExpr(Offset))
+ return true;
+ getTargetStreamer().emitARM64WinCFIAllocZ(Offset);
+ return false;
+}
+
+/// parseDirectiveSEHSaveZReg
+/// ::= .seh_save_zreg
+bool AArch64AsmParser::parseDirectiveSEHSaveZReg(SMLoc L) {
+ MCRegister RegNum;
+ StringRef Kind;
+ int64_t Offset;
+ ParseStatus Res =
+ tryParseVectorRegister(RegNum, Kind, RegKind::SVEDataVector);
+ if (!Res.isSuccess())
+ return true;
+ if (check(RegNum < AArch64::Z8 || RegNum > AArch64::Z23, L,
+ "expected register in range z8 to z23"))
+ return true;
+ if (parseComma() || parseImmExpr(Offset))
+ return true;
+ getTargetStreamer().emitARM64WinCFISaveZReg(RegNum - AArch64::Z0, Offset);
+ return false;
+}
+
+/// parseDirectiveSEHSavePReg
+/// ::= .seh_save_preg
+bool AArch64AsmParser::parseDirectiveSEHSavePReg(SMLoc L) {
+ MCRegister RegNum;
+ StringRef Kind;
+ int64_t Offset;
+ ParseStatus Res =
+ tryParseVectorRegister(RegNum, Kind, RegKind::SVEPredicateVector);
+ if (!Res.isSuccess())
+ return true;
+ if (check(RegNum < AArch64::P4 || RegNum > AArch64::P15, L,
+ "expected register in range p4 to p15"))
+ return true;
+ if (parseComma() || parseImmExpr(Offset))
+ return true;
+ getTargetStreamer().emitARM64WinCFISavePReg(RegNum - AArch64::P0, Offset);
+ return false;
+}
+
bool AArch64AsmParser::parseDirectiveAeabiSubSectionHeader(SMLoc L) {
// Expecting 3 AsmToken::Identifier after '.aeabi_subsection', a name and 2
// parameters, e.g.: .aeabi_subsection (1)aeabi_feature_and_bits, (2)optional,
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index b12a12436db81..cc607e863d190 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -150,6 +150,15 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset) override {
OS << "\t.seh_save_any_reg_px\tq" << Reg << ", " << Offset << "\n";
}
+ void emitARM64WinCFIAllocZ(int Offset) override {
+ OS << "\t.seh_allocz\t" << Offset << "\n";
+ }
+ void emitARM64WinCFISaveZReg(unsigned Reg, int Offset) override {
+ OS << "\t.seh_save_zreg\tz" << Reg << ", " << Offset << "\n";
+ }
+ void emitARM64WinCFISavePReg(unsigned Reg, int Offset) override {
+ OS << "\t.seh_save_preg\tp" << Reg << ", " << Offset << "\n";
+ }
void emitAttribute(StringRef VendorName, unsigned Tag, unsigned Value,
std::string String) override {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
index 43e099f919999..1427427b951a8 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -93,6 +93,9 @@ class AArch64TargetStreamer : public MCTargetStreamer {
virtual void emitARM64WinCFISaveAnyRegDPX(unsigned Reg, int Offset) {}
virtual void emitARM64WinCFISaveAnyRegQX(unsigned Reg, int Offset) {}
virtual void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset) {}
+ virtual void emitARM64WinCFIAllocZ(int Offset) {}
+ virtual void emitARM64WinCFISaveZReg(unsigned Reg, int Offset) {}
+ virtual void emitARM64WinCFISavePReg(unsigned Reg, int Offset) {}
/// Build attributes implementation
virtual void
@@ -182,6 +185,9 @@ class AArch64TargetWinCOFFStreamer : public llvm::AArch64TargetStreamer {
void emitARM64WinCFISaveAnyRegDPX(unsigned Reg, int Offset) override;
void emitARM64WinCFISaveAnyRegQX(unsigned Reg, int Offset) override;
void emitARM64WinCFISaveAnyRegQPX(unsigned Reg, int Offset) override;
+ void emitARM64WinCFIAllocZ(int Offset) override;
+ void emitARM64WinCFISaveZReg(unsigned Reg, int Offset) override;
+ void emitARM64WinCFISavePReg(unsigned Reg, int Offset) override;
private:
void emitARM64WinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp
index fb8a3e1215d90..c03bc386ae349 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp
@@ -284,6 +284,20 @@ void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQPX(unsigned Reg,
emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQPX, Reg, Offset);
}
+void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAllocZ(int Offset) {
+ emitARM64WinUnwindCode(Win64EH::UOP_AllocZ, 0, Offset);
+}
+
+void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveZReg(unsigned Reg,
+ int Offset) {
+ emitARM64WinUnwindCode(Win64EH::UOP_SaveZReg, Reg, Offset);
+}
+
+void AArch64TargetWinCOFFStreamer::emitARM64WinCFISavePReg(unsigned Reg,
+ int Offset) {
+ emitARM64WinUnwindCode(Win64EH::UOP_SavePReg, Reg, Offset);
+}
+
MCStreamer *
llvm::createAArch64WinCOFFStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> &&MAB,
diff --git a/llvm/test/MC/AArch64/seh.s b/llvm/test/MC/AArch64/seh.s
index 5ad4fba2bf6b4..93ba9ccfff80b 100644
--- a/llvm/test/MC/AArch64/seh.s
+++ b/llvm/test/MC/AArch64/seh.s
@@ -20,7 +20,7 @@
// CHECK-NEXT: }
// CHECK: Section {
// CHECK: Name: .xdata
-// CHECK: RawDataSize: 92
+// CHECK: RawDataSize: 100
// CHECK: RelocationCount: 1
// CHECK: Characteristics [
// CHECK-NEXT: ALIGN_4BYTES
@@ -41,7 +41,7 @@
// CHECK-NEXT: Relocations [
// CHECK-NEXT: Section (4) .xdata {
-// CHECK-NEXT: 0x50 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler
+// CHECK-NEXT: 0x58 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler
// CHECK-NEXT: }
// CHECK-NEXT: Section (5) .pdata {
// CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB .text
@@ -54,8 +54,11 @@
// CHECK-NEXT: Function: func
// CHECK-NEXT: ExceptionRecord: .xdata
// CHECK-NEXT: ExceptionData {
-// CHECK-NEXT: FunctionLength: 156
+// CHECK-NEXT: FunctionLength: 172
// CHECK: Prologue [
+// CHECK-NEXT: 0xe712c3 ; str p10, [sp, #3, mul vl]
+// CHECK-NEXT: 0xe703c5 ; str z11, [sp, #5, mul vl]
+// CHECK-NEXT: 0xdf05 ; addvl sp, #-5
// CHECK-NEXT: 0xe76983 ; stp q9, q10, [sp, #-64]!
// CHECK-NEXT: 0xe73d83 ; str q29, [sp, #-64]!
// CHECK-NEXT: 0xe76243 ; stp d2, d3, [sp, #-64]!
@@ -96,8 +99,8 @@
// CHECK-NEXT: ]
// CHECK-NEXT: EpilogueScopes [
// CHECK-NEXT: EpilogueScope {
-// CHECK-NEXT: StartOffset: 37
-// CHECK-NEXT: EpilogueStartIndex: 69
+// CHECK-NEXT: StartOffset: 41
+// CHECK-NEXT: EpilogueStartIndex: 77
// CHECK-NEXT: Opcodes [
// CHECK-NEXT: 0x01 ; add sp, #16
// CHECK-NEXT: 0xe4 ; end
@@ -193,6 +196,13 @@ func:
.seh_save_any_reg_x q29, 64
nop
.seh_save_any_reg_px q9, 64
+ nop
+ .seh_allocz 5
+ nop
+ .seh_save_zreg z11, 5
+ nop
+ .seh_save_preg p6, 3
+ nop
.seh_endprologue
nop
.seh_startepilogue
diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
index 08baa037eab27..62d9c6e559796 100644
--- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -160,6 +160,7 @@ const Decoder::RingEntry Decoder::Ring64[] = {
{0xfe, 0xda, 2, &Decoder::opcode_save_fregp_x},
{0xfe, 0xdc, 2, &Decoder::opcode_save_freg},
{0xff, 0xde, 2, &Decoder::opcode_save_freg_x},
+ {0xff, 0xdf, 2, &Decoder::opcode_alloc_z},
{0xff, 0xe0, 4, &Decoder::opcode_alloc_l},
{0xff, 0xe1, 1, &Decoder::opcode_setfp},
{0xff, 0xe2, 2, &Decoder::opcode_addfp},
@@ -167,7 +168,7 @@ const Decoder::RingEntry Decoder::Ring64[] = {
{0xff, 0xe4, 1, &Decoder::opcode_end},
{0xff, 0xe5, 1, &Decoder::opcode_end_c},
{0xff, 0xe6, 1, &Decoder::opcode_save_next},
- {0xff, 0xe7, 3, &Decoder::opcode_save_any_reg},
+ {0xff, 0xe7, 3, &Decoder::opcode_e7},
{0xff, 0xe8, 1, &Decoder::opcode_trap_frame},
{0xff, 0xe9, 1, &Decoder::opcode_machine_frame},
{0xff, 0xea, 1, &Decoder::opcode_context},
@@ -805,6 +806,16 @@ bool Decoder::opcode_save_freg_x(const uint8_t *OC, unsigned &Offset,
return false;
}
+bool Decoder::opcode_alloc_z(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ unsigned Off = OC[Offset + 1];
+ SW.startLine() << format("0x%02x%02x ; addvl sp, #%d\n",
+ OC[Offset], OC[Offset + 1],
+ Prologue ? -(int)Off : (int)Off);
+ Offset += 2;
+ return false;
+}
+
bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Off =
@@ -871,6 +882,24 @@ bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset,
return false;
}
+bool Decoder::opcode_e7(const uint8_t *OC, unsigned &Offset, unsigned Length,
+ bool Prologue) {
+ // The e7 opcode has unusual decoding rules; write out the logic.
+ if ((OC[Offset + 1] & 0x80) == 0x80) {
+ SW.getOStream() << "reserved encoding\n";
+ Offset += 3;
+ return false;
+ }
+
+ if ((OC[Offset + 2] & 0xC0) == 0xC0) {
+ if ((OC[Offset + 1] & 0x10) == 0)
+ return opcode_save_zreg(OC, Offset, Length, Prologue);
+ return opcode_save_preg(OC, Offset, Length, Prologue);
+ }
+
+ return opcode_save_any_reg(OC, Offset, Length, Prologue);
+}
+
bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
// Whether the instruction has writeback
@@ -948,6 +977,30 @@ bool Decoder::opcode_save_any_reg(const uint8_t *OC, unsigned &Offset,
return false;
}
+bool Decoder::opcode_save_zreg(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Reg = (OC[Offset + 1] & 0x0F) + 8;
+ uint32_t Off = ((OC[Offset + 1] & 0x60) << 1) | (OC[Offset + 2] & 0x3F);
+ SW.startLine() << format(
+ "0x%02x%02x%02x ; %s z%u, [sp, #%u, mul vl]\n", OC[Offset],
+ OC[Offset + 1], OC[Offset + 2],
+ static_cast<const char *>(Prologue ? "str" : "ldr"), Reg, Off);
+ Offset += 3;
+ return false;
+}
+
+bool Decoder::opcode_save_preg(const uint8_t *OC, unsigned &Offset,
+ unsigned Length, bool Prologue) {
+ uint32_t Reg = (OC[Offset + 1] & 0x0F) + 8;
+ uint32_t Off = ((OC[Offset + 1] & 0x60) << 1) | (OC[Offset + 2] & 0x3F);
+ SW.startLine() << format(
+ "0x%02x%02x%02x ; %s p%u, [sp, #%u, mul vl]\n", OC[Offset],
+ OC[Offset + 1], OC[Offset + 2],
+ static_cast<const char *>(Prologue ? "str" : "ldr"), Reg, Off);
+ Offset += 3;
+ return false;
+}
+
bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]);
diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
index fa5b31dd87b4b..b412c4a8ae231 100644
--- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -107,6 +107,8 @@ class Decoder {
unsigned Length, bool Prologue);
bool opcode_save_freg_x(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
+ bool opcode_alloc_z(const uint8_t *Opcodes, unsigned &Offset, unsigned Length,
+ bool Prologue);
bool opcode_alloc_l(const uint8_t *Opcodes, unsigned &Offset, unsigned Length,
bool Prologue);
bool opcode_setfp(const uint8_t *Opcodes, unsigned &Offset, unsigned Length,
@@ -121,6 +123,12 @@ class Decoder {
bool Prologue);
bool opcode_save_next(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
+ bool opcode_e7(const uint8_t *Opcodes, unsigned &Offset, unsigned Length,
+ bool Prologue);
+ bool opcode_save_zreg(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
+ bool opcode_save_preg(const uint8_t *Opcodes, unsigned &Offset,
+ unsigned Length, bool Prologue);
bool opcode_save_any_reg(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
bool opcode_trap_frame(const uint8_t *Opcodes, unsigned &Offset,
|
In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows.
9171163
to
b244f02
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, other than the test failure.
@pmsjt any concerns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
…llvm#137895) In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows.
…llvm#137895) In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows.
…llvm#137895) In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows.
…llvm#137895) In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .) First in a series of patches to support SVE on Windows.
In order to support the AArch64 ABI, Microsoft has extended the unwinder to support additional opcodes. (Updated documentation at https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling .)
First in a series of patches to support SVE on Windows.