diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -1822,8 +1822,11 @@ EmitEOL(); } -// TODO: Implement void MCAsmStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) { + MCStreamer::EmitWinCFIFuncletOrFuncEnd(Loc); + + OS << "\t.seh_endfunclet"; + EmitEOL(); } void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) { diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -77,6 +77,8 @@ ".seh_proc"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( ".seh_endproc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc>( + ".seh_endfunclet"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( ".seh_startchained"); addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( @@ -131,6 +133,7 @@ // Win64 EH directives. bool ParseSEHDirectiveStartProc(StringRef, SMLoc); bool ParseSEHDirectiveEndProc(StringRef, SMLoc); + bool ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc); bool ParseSEHDirectiveStartChained(StringRef, SMLoc); bool ParseSEHDirectiveEndChained(StringRef, SMLoc); bool ParseSEHDirectiveHandler(StringRef, SMLoc); @@ -629,6 +632,12 @@ return false; } +bool COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) { + Lex(); + getStreamer().EmitWinCFIFuncletOrFuncEnd(Loc); + return false; +} + bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { Lex(); getStreamer().EmitWinCFIStartChained(Loc); diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/AArch64AddressingModes.h" +#include "MCTargetDesc/AArch64InstPrinter.h" #include "MCTargetDesc/AArch64MCExpr.h" #include "MCTargetDesc/AArch64MCTargetDesc.h" #include "MCTargetDesc/AArch64TargetStreamer.h" @@ -160,6 +161,10 @@ bool parseOptionalMulOperand(OperandVector &Operands); bool parseOperand(OperandVector &Operands, bool isCondCode, bool invertCondCode); + bool parseImmExpr(int64_t &Out); + bool parseComma(); + bool parseRegisterInRange(unsigned &Out, unsigned Base, unsigned First, + unsigned Last); bool showMatchError(SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo, OperandVector &Operands); @@ -179,6 +184,24 @@ bool parseDirectiveCFINegateRAState(); bool parseDirectiveCFIBKeyFrame(); + bool parseDirectiveSEHAllocStack(SMLoc L); + bool parseDirectiveSEHPrologEnd(SMLoc L); + bool parseDirectiveSEHSaveFPLR(SMLoc L); + bool parseDirectiveSEHSaveFPLRX(SMLoc L); + bool parseDirectiveSEHSaveReg(SMLoc L); + bool parseDirectiveSEHSaveRegX(SMLoc L); + bool parseDirectiveSEHSaveRegP(SMLoc L); + bool parseDirectiveSEHSaveRegPX(SMLoc L); + bool parseDirectiveSEHSaveFReg(SMLoc L); + bool parseDirectiveSEHSaveFRegX(SMLoc L); + bool parseDirectiveSEHSaveFRegP(SMLoc L); + bool parseDirectiveSEHSaveFRegPX(SMLoc L); + bool parseDirectiveSEHSetFP(SMLoc L); + bool parseDirectiveSEHAddFP(SMLoc L); + bool parseDirectiveSEHNop(SMLoc L); + bool parseDirectiveSEHEpilogStart(SMLoc L); + bool parseDirectiveSEHEpilogEnd(SMLoc L); + bool validateInstruction(MCInst &Inst, SMLoc &IDLoc, SmallVectorImpl &Loc); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, @@ -3741,6 +3764,66 @@ } } +bool AArch64AsmParser::parseImmExpr(int64_t &Out) { + const MCExpr *Expr = nullptr; + SMLoc L = getLoc(); + if (check(getParser().parseExpression(Expr), L, "expected expression")) + return true; + const MCConstantExpr *Value = dyn_cast_or_null(Expr); + if (check(!Value, L, "expected constant expression")) + return true; + Out = Value->getValue(); + return false; +} + +bool AArch64AsmParser::parseComma() { + if (check(getParser().getTok().isNot(AsmToken::Comma), getLoc(), + "expected comma")) + return true; + // Eat the comma + getParser().Lex(); + return false; +} + +bool AArch64AsmParser::parseRegisterInRange(unsigned &Out, unsigned Base, + unsigned First, unsigned Last) { + unsigned Reg; + SMLoc Start, End; + if (check(ParseRegister(Reg, Start, End), getLoc(), "expected register")) + return true; + + // Special handling for FP and LR; they aren't linearly after x28 in + // the registers enum. + unsigned RangeEnd = Last; + if (Base == AArch64::X0) { + if (Last == AArch64::FP) { + RangeEnd = AArch64::X28; + if (Reg == AArch64::FP) { + Out = 29; + return false; + } + } + if (Last == AArch64::LR) { + RangeEnd = AArch64::X28; + if (Reg == AArch64::FP) { + Out = 29; + return false; + } else if (Reg == AArch64::LR) { + Out = 30; + return false; + } + } + } + + if (check(Reg < First || Reg > RangeEnd, Start, + Twine("expected register in range ") + + AArch64InstPrinter::getRegisterName(First) + " to " + + AArch64InstPrinter::getRegisterName(Last))) + return true; + Out = Reg - Base; + return false; +} + bool AArch64AsmParser::regsEqual(const MCParsedAsmOperand &Op1, const MCParsedAsmOperand &Op2) const { auto &AOp1 = static_cast(Op1); @@ -5059,6 +5142,7 @@ const MCObjectFileInfo::Environment Format = getContext().getObjectFileInfo()->getObjectFileType(); bool IsMachO = Format == MCObjectFileInfo::IsMachO; + bool IsCOFF = Format == MCObjectFileInfo::IsCOFF; auto IDVal = DirectiveID.getIdentifier().lower(); SMLoc Loc = DirectiveID.getLoc(); @@ -5085,6 +5169,43 @@ parseDirectiveLOH(IDVal, Loc); else return true; + } else if (IsCOFF) { + if (IDVal == ".seh_stackalloc") + parseDirectiveSEHAllocStack(Loc); + else if (IDVal == ".seh_endprologue") + parseDirectiveSEHPrologEnd(Loc); + else if (IDVal == ".seh_save_fplr") + parseDirectiveSEHSaveFPLR(Loc); + else if (IDVal == ".seh_save_fplr_x") + parseDirectiveSEHSaveFPLRX(Loc); + else if (IDVal == ".seh_save_reg") + parseDirectiveSEHSaveReg(Loc); + else if (IDVal == ".seh_save_reg_x") + parseDirectiveSEHSaveRegX(Loc); + else if (IDVal == ".seh_save_regp") + parseDirectiveSEHSaveRegP(Loc); + else if (IDVal == ".seh_save_regp_x") + parseDirectiveSEHSaveRegPX(Loc); + else if (IDVal == ".seh_save_freg") + parseDirectiveSEHSaveFReg(Loc); + else if (IDVal == ".seh_save_freg_x") + parseDirectiveSEHSaveFRegX(Loc); + else if (IDVal == ".seh_save_fregp") + parseDirectiveSEHSaveFRegP(Loc); + else if (IDVal == ".seh_save_fregp_x") + parseDirectiveSEHSaveFRegPX(Loc); + else if (IDVal == ".seh_set_fp") + parseDirectiveSEHSetFP(Loc); + else if (IDVal == ".seh_add_fp") + parseDirectiveSEHAddFP(Loc); + else if (IDVal == ".seh_nop") + parseDirectiveSEHNop(Loc); + else if (IDVal == ".seh_startepilogue") + parseDirectiveSEHEpilogStart(Loc); + else if (IDVal == ".seh_endepilogue") + parseDirectiveSEHEpilogEnd(Loc); + else + return true; } else return true; return false; @@ -5507,6 +5628,177 @@ return false; } +/// parseDirectiveSEHAllocStack +/// ::= .seh_stackalloc +bool AArch64AsmParser::parseDirectiveSEHAllocStack(SMLoc L) { + int64_t Size; + if (parseImmExpr(Size)) + return true; + getTargetStreamer().EmitARM64WinCFIAllocStack(Size); + return false; +} + +/// parseDirectiveSEHPrologEnd +/// ::= .seh_endprologue +bool AArch64AsmParser::parseDirectiveSEHPrologEnd(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIPrologEnd(); + return false; +} + +/// parseDirectiveSEHSaveFPLR +/// ::= .seh_save_fplr +bool AArch64AsmParser::parseDirectiveSEHSaveFPLR(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFPLR(Offset); + return false; +} + +/// parseDirectiveSEHSaveFPLRX +/// ::= .seh_save_fplr_x +bool AArch64AsmParser::parseDirectiveSEHSaveFPLRX(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFPLRX(Offset); + return false; +} + +/// parseDirectiveSEHSaveReg +/// ::= .seh_save_reg +bool AArch64AsmParser::parseDirectiveSEHSaveReg(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveReg(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegX +/// ::= .seh_save_reg_x +bool AArch64AsmParser::parseDirectiveSEHSaveRegX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegP +/// ::= .seh_save_regp +bool AArch64AsmParser::parseDirectiveSEHSaveRegP(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegP(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveRegPX +/// ::= .seh_save_regp_x +bool AArch64AsmParser::parseDirectiveSEHSaveRegPX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::X28) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveRegPX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFReg +/// ::= .seh_save_freg +bool AArch64AsmParser::parseDirectiveSEHSaveFReg(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFReg(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegX +/// ::= .seh_save_freg_x +bool AArch64AsmParser::parseDirectiveSEHSaveFRegX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegP +/// ::= .seh_save_fregp +bool AArch64AsmParser::parseDirectiveSEHSaveFRegP(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegP(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSaveFRegPX +/// ::= .seh_save_fregp_x +bool AArch64AsmParser::parseDirectiveSEHSaveFRegPX(SMLoc L) { + unsigned Reg; + int64_t Offset; + if (parseRegisterInRange(Reg, AArch64::D0, AArch64::D8, AArch64::D15) || + parseComma() || parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveFRegPX(Reg, Offset); + return false; +} + +/// parseDirectiveSEHSetFP +/// ::= .seh_set_fp +bool AArch64AsmParser::parseDirectiveSEHSetFP(SMLoc L) { + getTargetStreamer().EmitARM64WinCFISetFP(); + return false; +} + +/// parseDirectiveSEHAddFP +/// ::= .seh_add_fp +bool AArch64AsmParser::parseDirectiveSEHAddFP(SMLoc L) { + int64_t Size; + if (parseImmExpr(Size)) + return true; + getTargetStreamer().EmitARM64WinCFIAddFP(Size); + return false; +} + +/// parseDirectiveSEHNop +/// ::= .seh_nop +bool AArch64AsmParser::parseDirectiveSEHNop(SMLoc L) { + getTargetStreamer().EmitARM64WinCFINop(); + return false; +} + +/// parseDirectiveSEHEpilogStart +/// ::= .seh_startepilogue +bool AArch64AsmParser::parseDirectiveSEHEpilogStart(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIEpilogStart(); + return false; +} + +/// parseDirectiveSEHEpilogEnd +/// ::= .seh_endepilogue +bool AArch64AsmParser::parseDirectiveSEHEpilogEnd(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIEpilogEnd(); + return false; +} + bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64MCExpr::VariantKind &ELFRefKind, diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp @@ -47,6 +47,48 @@ void emitInst(uint32_t Inst) override; + void EmitARM64WinCFIAllocStack(unsigned Size) override { + OS << "\t.seh_stackalloc " << Size << "\n"; + } + void EmitARM64WinCFISaveFPLR(int Offset) override { + OS << "\t.seh_save_fplr " << Offset << "\n"; + } + void EmitARM64WinCFISaveFPLRX(int Offset) override { + OS << "\t.seh_save_fplr_x " << Offset << "\n"; + } + void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) override { + OS << "\t.seh_save_reg x" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) override { + OS << "\t.seh_save_reg_x x" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) override { + OS << "\t.seh_save_regp x" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override { + OS << "\t.seh_save_regp_x x" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override { + OS << "\t.seh_save_freg d" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override { + OS << "\t.seh_save_freg_x d" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override { + OS << "\t.seh_save_fregp d" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) override { + OS << "\t.seh_save_fregp_x d" << Reg << ", " << Offset << "\n"; + } + void EmitARM64WinCFISetFP() override { OS << "\t.seh_set_fp\n"; } + void EmitARM64WinCFIAddFP(unsigned Size) override { + OS << "\t.seh_add_fp " << Size << "\n"; + } + void EmitARM64WinCFINop() override { OS << "\t.seh_nop\n"; } + void EmitARM64WinCFIPrologEnd() override { OS << "\t.seh_endprologue\n"; } + void EmitARM64WinCFIEpilogStart() override { OS << "\t.seh_startepilogue\n"; } + void EmitARM64WinCFIEpilogEnd() override { OS << "\t.seh_endepilogue\n"; } + public: AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); }; diff --git a/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll b/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll --- a/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll +++ b/llvm/test/CodeGen/AArch64/arm64-windows-calls.ll @@ -29,6 +29,7 @@ ; CHECK: stp xzr, xzr, [sp, #-16]! ; CHECK-NEXT: mov x0, xzr ; CHECK-NEXT: mov x1, xzr +; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: add sp, sp, #16 %retval = alloca %struct.S2, align 4 diff --git a/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll b/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll --- a/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll +++ b/llvm/test/CodeGen/AArch64/lrint-conv-fp16-win.ll @@ -3,6 +3,8 @@ ; CHECK-LABEL: testmhhs: ; CHECK: frintx h0, h0 ; CHECK-NEXT: fcvtzs w0, h0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i16 @testmhhs(half %x) { entry: @@ -14,6 +16,8 @@ ; CHECK-LABEL: testmhws: ; CHECK: frintx h0, h0 ; CHECK-NEXT: fcvtzs w0, h0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i32 @testmhws(half %x) { entry: @@ -25,6 +29,8 @@ ; CHECK: frintx h0, h0 ; CHECK-NEXT: fcvtzs w8, h0 ; CHECK-NEXT: sxtw x0, w8 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmhxs(half %x) { entry: diff --git a/llvm/test/CodeGen/AArch64/lrint-conv-win.ll b/llvm/test/CodeGen/AArch64/lrint-conv-win.ll --- a/llvm/test/CodeGen/AArch64/lrint-conv-win.ll +++ b/llvm/test/CodeGen/AArch64/lrint-conv-win.ll @@ -4,6 +4,8 @@ ; CHECK: frintx [[SREG:s[0-9]+]], s0 ; CHECK-NEXT: fcvtzs [[WREG:w[0-9]+]], [[SREG]] ; CHECK-NEXT: sxtw x0, [[WREG]] +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmsxs(float %x) { entry: @@ -15,6 +17,8 @@ ; CHECK-LABEL: testmsws: ; CHECK: frintx [[SREG:s[0-9]+]], s0 ; CHECK-NEXT: fcvtzs [[WREG:w[0-9]+]], [[SREG]] +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i32 @testmsws(float %x) { entry: @@ -26,6 +30,8 @@ ; CHECK: frintx [[DREG:d[0-9]+]], d0 ; CHECK-NEXT: fcvtzs [[WREG:w[0-9]+]], [[DREG]] ; CHECK-NEXT: sxtw x0, [[WREG]] +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmsxd(double %x) { entry: @@ -37,6 +43,8 @@ ; CHECK-LABEL: testmswd: ; CHECK: frintx [[DREG:d[0-9]+]], d0 ; CHECK-NEXT: fcvtzs [[WREG:w[0-9]+]], [[DREG]] +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i32 @testmswd(double %x) { entry: diff --git a/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll b/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll --- a/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll +++ b/llvm/test/CodeGen/AArch64/lround-conv-fp16-win.ll @@ -22,6 +22,8 @@ ; CHECK-LABEL: testmhxs: ; CHECK: fcvtas w8, h0 ; CHECK-NEXT: sxtw x0, w8 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmhxs(half %x) { entry: diff --git a/llvm/test/CodeGen/AArch64/lround-conv-win.ll b/llvm/test/CodeGen/AArch64/lround-conv-win.ll --- a/llvm/test/CodeGen/AArch64/lround-conv-win.ll +++ b/llvm/test/CodeGen/AArch64/lround-conv-win.ll @@ -3,6 +3,8 @@ ; CHECK-LABEL: testmsxs: ; CHECK: fcvtas w8, s0 ; CHECK-NEXT: sxtw x0, w8 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmsxs(float %x) { entry: @@ -13,6 +15,8 @@ ; CHECK-LABEL: testmsws: ; CHECK: fcvtas w0, s0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i32 @testmsws(float %x) { entry: @@ -23,6 +27,8 @@ ; CHECK-LABEL: testmsxd: ; CHECK: fcvtas w8, d0 ; CHECK-NEXT: sxtw x0, w8 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i64 @testmsxd(double %x) { entry: @@ -33,6 +39,8 @@ ; CHECK-LABEL: testmswd: ; CHECK: fcvtas w0, d0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret define i32 @testmswd(double %x) { entry: diff --git a/llvm/test/CodeGen/AArch64/powi-windows.ll b/llvm/test/CodeGen/AArch64/powi-windows.ll --- a/llvm/test/CodeGen/AArch64/powi-windows.ll +++ b/llvm/test/CodeGen/AArch64/powi-windows.ll @@ -11,6 +11,8 @@ ; CHECK-LABEL: d: ; CHECK: scvtf d1, w0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: b pow define float @f(float %f, i32 %i) { @@ -21,6 +23,8 @@ ; CHECK-LABEL: f: ; CHECK: scvtf s1, w0 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: b powf define float @g(double %d, i32 %i) { diff --git a/llvm/test/CodeGen/AArch64/seh_funclet_x1.ll b/llvm/test/CodeGen/AArch64/seh_funclet_x1.ll --- a/llvm/test/CodeGen/AArch64/seh_funclet_x1.ll +++ b/llvm/test/CodeGen/AArch64/seh_funclet_x1.ll @@ -6,6 +6,8 @@ ; CHECK: ?dtor$3@?0?main@4HA": ; CHECK: .seh_proc "?dtor$3@?0?main@4HA" ; CHECK: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: mov x29, x1 target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/CodeGen/AArch64/win64-jumptable.ll b/llvm/test/CodeGen/AArch64/win64-jumptable.ll --- a/llvm/test/CodeGen/AArch64/win64-jumptable.ll +++ b/llvm/test/CodeGen/AArch64/win64-jumptable.ll @@ -37,6 +37,7 @@ ; CHECK: f: ; CHECK: .seh_proc f ; CHECK: b g +; CHECK-NEXT: .seh_endfunclet ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: .LJTI0_0: ; CHECK: .word .LBB0_2-.LJTI0_0 diff --git a/llvm/test/CodeGen/AArch64/win_cst_pool.ll b/llvm/test/CodeGen/AArch64/win_cst_pool.ll --- a/llvm/test/CodeGen/AArch64/win_cst_pool.ll +++ b/llvm/test/CodeGen/AArch64/win_cst_pool.ll @@ -12,6 +12,8 @@ ; CHECK: double: ; CHECK: adrp x8, __real@2000000000800001 ; CHECK-NEXT: ldr d0, [x8, __real@2000000000800001] +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret ; MINGW: .section .rdata,"dr" @@ -21,4 +23,6 @@ ; MINGW: double: ; MINGW: adrp x8, [[LABEL]] ; MINGW-NEXT: ldr d0, [x8, [[LABEL]]] +; MINGW-NEXT: .seh_startepilogue +; MINGW-NEXT: .seh_endepilogue ; MINGW-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/windows-extern-weak.ll b/llvm/test/CodeGen/AArch64/windows-extern-weak.ll --- a/llvm/test/CodeGen/AArch64/windows-extern-weak.ll +++ b/llvm/test/CodeGen/AArch64/windows-extern-weak.ll @@ -5,13 +5,18 @@ define void @func() { ; CHECK-LABEL: func: ; CHECK: str x30, [sp, #-16]! +; CHECK-NEXT: .seh_save_reg_x x30, 16 +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: adrp x8, .refptr.weakfunc ; CHECK-NEXT: ldr x8, [x8, .refptr.weakfunc] ; CHECK-NEXT: cbz x8, .LBB0_2 ; CHECK-NEXT: ; %bb.1: ; CHECK-NEXT: blr x8 ; CHECK-NEXT: .LBB0_2: +; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: ldr x30, [sp], #16 +; CHECK-NEXT: .seh_save_reg_x x30, 16 +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret br i1 icmp ne (void ()* @weakfunc, void ()* null), label %1, label %2 diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll @@ -5,7 +5,10 @@ ; after the frame setup.) ; CHECK: stp x29, x30, [sp, #-32]! +; CHECK-NEXT: .seh_save_fplr_x 32 ; CHECK-NEXT: mov x29, sp +; CHECK-NEXT: .seh_set_fp +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: mov x1, #-2 ; CHECK-NEXT: stur x1, [x29, #16] ; CHECK-NEXT: cbz w0, .LBB0_2 diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch-nobase.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch-nobase.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch-nobase.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch-nobase.ll @@ -7,12 +7,17 @@ ; Check that we compute the address relative to fp. ; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA": ; CHECK: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: sub x0, x29, #16 ; =16 ; CHECK-NEXT: mov x1, xzr ; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z" ; CHECK-NEXT: adrp x0, .LBB0_1 ; CHECK-NEXT: add x0, x0, .LBB0_1 +; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll @@ -10,16 +10,25 @@ ; epilogue should be symmetrical. ; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA": ; CHECK: stp x29, x30, [sp, #-32]! +; CHECK-NEXT: .seh_save_fplr_x 32 ; CHECK-NEXT: str x28, [sp, #16] +; CHECK-NEXT: .seh_save_reg x28, 16 ; CHECK-NEXT: str x19, [sp, #24] +; CHECK-NEXT: .seh_save_reg x19, 24 +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: add x0, x19, #0 ; CHECK-NEXT: mov w1, wzr ; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z" ; CHECK-NEXT: adrp x0, .LBB0_1 ; CHECK-NEXT: add x0, x0, .LBB0_1 +; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: ldr x19, [sp, #24] +; CHECK-NEXT: .seh_save_reg x19, 24 ; CHECK-NEXT: ldr x28, [sp, #16] +; CHECK-NEXT: .seh_save_reg x28, 16 ; CHECK-NEXT: ldp x29, x30, [sp], #32 +; CHECK-NEXT: .seh_save_fplr_x 32 +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/wineh-try-catch-vla.ll b/llvm/test/CodeGen/AArch64/wineh-try-catch-vla.ll --- a/llvm/test/CodeGen/AArch64/wineh-try-catch-vla.ll +++ b/llvm/test/CodeGen/AArch64/wineh-try-catch-vla.ll @@ -9,12 +9,17 @@ ; (Funclets aren't allowed to contain dynamic allocas.) ; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ@4HA": ; CHECK: stp x29, x30, [sp, #-16]! +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: ldur x0, [x29, #-8] ; CHECK-NEXT: mov x1, x0 ; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z" ; CHECK-NEXT: adrp x0, .LBB0_1 ; CHECK-NEXT: add x0, x0, .LBB0_1 +; CHECK-NEXT: .seh_startepilogue ; CHECK-NEXT: ldp x29, x30, [sp], #16 +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endepilogue ; CHECK-NEXT: ret target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" diff --git a/llvm/test/CodeGen/AArch64/wineh1.mir b/llvm/test/CodeGen/AArch64/wineh1.mir --- a/llvm/test/CodeGen/AArch64/wineh1.mir +++ b/llvm/test/CodeGen/AArch64/wineh1.mir @@ -6,6 +6,10 @@ # documented at: # https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling +# Also test the generated assembler SEH directives. +# RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog -filetype=asm \ +# RUN: | FileCheck %s --check-prefix=ASM + # We expect to see the following in the .xdata section: # CHECK: ExceptionData { @@ -47,6 +51,33 @@ # CHECK-LDSTOPT: name: test # CHECK-LDSTOPT: frame-setup STRXui killed $x21, $sp, 6 # CHECK-LDSTOPT: frame-setup STRXui killed $x22, $sp, 7 + +# ASM-LABEL: test: +# ASM: .seh_proc test +# ASM: .seh_save_regp_x x27, 80 +# ASM: .seh_save_regp x25, 16 +# ASM: .seh_save_regp x23, 32 +# ASM: .seh_save_reg x21, 48 +# ASM: .seh_save_reg x22, 56 +# ASM: .seh_save_regp x19, 64 +# ASM: .seh_endprologue + +# ASM: .seh_startepilogue +# ASM: .seh_save_regp x19, 64 +# ASM: .seh_save_reg x21, 48 +# ASM: .seh_nop +# ASM: .seh_save_reg x22, 56 +# ASM: .seh_save_regp x23, 32 +# ASM: .seh_save_regp x25, 16 +# ASM: .seh_save_regp_x x27, 80 +# ASM: .seh_endepilogue + +# ASM: .seh_endfunclet +# ASM: .section .xdata,"dr" +# ASM: .seh_handlerdata +# ASM: .text +# ASM: .seh_endproc + ... --- name: test diff --git a/llvm/test/MC/AArch64/seh.s b/llvm/test/MC/AArch64/seh.s --- a/llvm/test/MC/AArch64/seh.s +++ b/llvm/test/MC/AArch64/seh.s @@ -1,9 +1,12 @@ -// This test checks that the SEH directives don't cause the assembler to fail. -// Checking that llvm-readobj doesn't bail out on the unwind data, but not -// really checking the contents yet. +// This test checks that the SEH directives emit the correct unwind data. // RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s | llvm-readobj -S -r -u - | FileCheck %s +// Check that the output assembler directives also can be parsed, and +// that they produce equivalent output: + +// RUN: llvm-mc -triple aarch64-pc-win32 -filetype=asm %s | llvm-mc -triple aarch64-pc-win32 -filetype=obj - | llvm-readobj -S -r -u - | FileCheck %s + // CHECK: Sections [ // CHECK: Section { // CHECK: Name: .text @@ -17,7 +20,7 @@ // CHECK-NEXT: } // CHECK: Section { // CHECK: Name: .xdata -// CHECK: RawDataSize: 20 +// CHECK: RawDataSize: 48 // CHECK: RelocationCount: 1 // CHECK: Characteristics [ // CHECK-NEXT: ALIGN_4BYTES @@ -38,7 +41,7 @@ // CHECK-NEXT: Relocations [ // CHECK-NEXT: Section (4) .xdata { -// CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler +// CHECK-NEXT: 0x24 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler // CHECK-NEXT: } // CHECK-NEXT: Section (5) .pdata { // CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB func @@ -51,7 +54,43 @@ // CHECK-NEXT: Function: func // CHECK-NEXT: ExceptionRecord: .xdata // CHECK-NEXT: ExceptionData { -// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: FunctionLength: 72 +// CHECK: Prologue [ +// CHECK-NEXT: 0xe3 ; nop +// CHECK-NEXT: 0xe202 ; add fp, sp, #16 +// CHECK-NEXT: 0xdd41 ; str d13, [sp, #8] +// CHECK-NEXT: 0xde83 ; str d12, [sp, #-32]! +// CHECK-NEXT: 0xd882 ; stp d10, d11, [sp, #16] +// CHECK-NEXT: 0xda03 ; stp d8, d9, [sp, #-32]! +// CHECK-NEXT: 0x83 ; stp x29, x30, [sp, #-32]! +// CHECK-NEXT: 0x46 ; stp x29, x30, [sp, #48] +// CHECK-NEXT: 0xd141 ; str x24, [sp, #8] +// CHECK-NEXT: 0xd483 ; str x23, [sp, #-32]! +// CHECK-NEXT: 0xc882 ; stp x21, x22, [sp, #16] +// CHECK-NEXT: 0xcc03 ; stp x19, x20, [sp, #-32]! +// CHECK-NEXT: 0x83 ; stp x29, x30, [sp, #-32]! +// CHECK-NEXT: 0xe1 ; mov fp, sp +// CHECK-NEXT: 0x01 ; sub sp, #16 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] +// CHECK-NEXT: EpilogueScopes [ +// CHECK-NEXT: EpilogueScope { +// CHECK-NEXT: StartOffset: 16 +// CHECK-NEXT: EpilogueStartIndex: 25 +// CHECK-NEXT: Opcodes [ +// CHECK-NEXT: 0x01 ; add sp, #16 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: ExceptionHandler [ +// CHECK-NEXT: Routine: __C_specific_handler (0x0) +// CHECK-NEXT: Parameter: 0x0 +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] + .text .globl func @@ -64,13 +103,44 @@ sub sp, sp, #24 .seh_stackalloc 24 mov x29, sp + .seh_set_fp + stp x29, x30, [sp, #-32]! + .seh_save_fplr_x 32 + stp x19, x20, [sp, #-32]! + .seh_save_regp_x x19, 32 + stp x21, x22, [sp, #16] + .seh_save_regp x21, 16 + str x23, [sp, #-32]! + .seh_save_reg_x x23, 32 + str x24, [sp, #8] + .seh_save_reg x24, 8 + stp x29, x30, [sp, #48] + .seh_save_fplr 48 + stp x29, x30, [sp, #-32]! + .seh_save_fplr_x 32 + stp d8, d9, [sp, #-32]! + .seh_save_fregp_x d8, 32 + stp d10, d11, [sp, #16] + .seh_save_fregp d10, 16 + str d12, [sp, #-32]! + .seh_save_freg_x d12, 32 + str d13, [sp, #8] + .seh_save_freg d13, 8 + add x29, sp, #16 + .seh_add_fp 16 + nop + .seh_nop .seh_endprologue + nop + .seh_startepilogue + add sp, sp, #24 + .seh_stackalloc 24 + .seh_endepilogue + ret .seh_handler __C_specific_handler, @except .seh_handlerdata .long 0 .text - add sp, sp, #24 - ret .seh_endproc // Function with no .seh directives; no pdata/xdata entries are