https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/176887
Backport 792670a4003cba8636713916bed89a0b991fb32d Requested by: @nikic >From 04e5731d99466da994cd3adf83f9ebd79ef21655 Mon Sep 17 00:00:00 2001 From: Nikita Popov <[email protected]> Date: Mon, 19 Jan 2026 09:09:04 +0100 Subject: [PATCH] [X86][WinEH] Insert nop after unwinding inline assembly (#176393) As discussed on https://github.com/llvm/llvm-project/pull/144745, insert a nop after unwinding inline assembly, as it may end on a call. While the change itself is trivial, I ended up having to do two infrastructure changes: * The unwind flag needs to be propagated to ExtraInfo of the MachineInstr. * The MachineInstr needs to be passed through to emitInlineAsmEnd(), and the method needs to be non-const. Fixes https://github.com/llvm/llvm-project/issues/157073. (cherry picked from commit 792670a4003cba8636713916bed89a0b991fb32d) --- llvm/include/llvm/CodeGen/AsmPrinter.h | 15 ++++++++------- llvm/include/llvm/IR/InlineAsm.h | 3 +++ .../CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 14 ++++++++------ llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp | 2 ++ llvm/lib/CodeGen/MachineInstr.cpp | 2 ++ llvm/lib/CodeGen/MachineVerifier.cpp | 4 ++-- llvm/lib/CodeGen/SelectionDAG/FastISel.cpp | 2 ++ .../CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 2 ++ llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 3 ++- llvm/lib/Target/ARM/ARMAsmPrinter.h | 3 ++- llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 3 ++- llvm/lib/Target/Mips/MipsAsmPrinter.h | 3 ++- llvm/lib/Target/X86/X86AsmPrinter.h | 4 ++++ llvm/lib/Target/X86/X86MCInstLower.cpp | 12 ++++++++++++ .../GlobalISel/irtranslator-unwind-inline-asm.ll | 2 +- .../CodeGen/X86/seh-unwind-inline-asm-codegen.ll | 2 ++ 16 files changed, 56 insertions(+), 20 deletions(-) diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 7f99e81e7d1a0..707dd5ddcf515 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -908,7 +908,8 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// \p EndInfo - the final subtarget info after parsing the inline asm, /// or NULL if the value is unknown. virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const; + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI); /// This emits visibility information about symbol, if this is supported by /// the target. @@ -942,15 +943,15 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { void emitFunctionPrefix(ArrayRef<const Constant *> Prefix); /// Emit a blob of inline asm to the output streamer. - void - emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, - const MCTargetOptions &MCOptions, - const MDNode *LocMDNode = nullptr, - InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const; + void emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, + const MCTargetOptions &MCOptions, + const MDNode *LocMDNode = nullptr, + InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT, + const MachineInstr *MI = nullptr); /// This method formats and emits the specified machine instruction that is an /// inline asm. - void emitInlineAsm(const MachineInstr *MI) const; + void emitInlineAsm(const MachineInstr *MI); /// Add inline assembly info to the diagnostics machinery, so we can /// emit file and position info. Returns SrcMgr memory buffer position. diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h index 96887d129a69f..fed0ccc5818f8 100644 --- a/llvm/include/llvm/IR/InlineAsm.h +++ b/llvm/include/llvm/IR/InlineAsm.h @@ -220,6 +220,7 @@ class InlineAsm final : public Value { Extra_MayLoad = 8, Extra_MayStore = 16, Extra_IsConvergent = 32, + Extra_MayUnwind = 64, }; // Inline asm operands map to multiple SDNode / MachineInstr operands. @@ -455,6 +456,8 @@ class InlineAsm final : public Value { Result.push_back("isconvergent"); if (ExtraInfo & InlineAsm::Extra_IsAlignStack) Result.push_back("alignstack"); + if (ExtraInfo & InlineAsm::Extra_MayUnwind) + Result.push_back("unwind"); AsmDialect Dialect = InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect)); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 69c2950711c7c..ae9fff80133d0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -73,7 +73,8 @@ unsigned AsmPrinter::addInlineAsmDiagBuffer(StringRef AsmStr, void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, const MCTargetOptions &MCOptions, const MDNode *LocMDNode, - InlineAsm::AsmDialect Dialect) const { + InlineAsm::AsmDialect Dialect, + const MachineInstr *MI) { assert(!Str.empty() && "Can't emit empty inline asm block"); // Remember if the buffer is nul terminated or not so we can avoid a copy. @@ -93,7 +94,7 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, !OutStreamer->isIntegratedAssemblerRequired()) { emitInlineAsmStart(); OutStreamer->emitRawText(Str); - emitInlineAsmEnd(STI, nullptr); + emitInlineAsmEnd(STI, nullptr, MI); return; } @@ -135,7 +136,7 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, // Don't implicitly switch to the text section before the asm. (void)Parser->Run(/*NoInitialTextSection*/ true, /*NoFinalize*/ true); - emitInlineAsmEnd(STI, &TAP->getSTI()); + emitInlineAsmEnd(STI, &TAP->getSTI(), MI); } static void EmitInlineAsmStr(const char *AsmStr, const MachineInstr *MI, @@ -336,7 +337,7 @@ static void EmitInlineAsmStr(const char *AsmStr, const MachineInstr *MI, /// This method formats and emits the specified machine instruction that is an /// inline asm. -void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { +void AsmPrinter::emitInlineAsm(const MachineInstr *MI) { assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. @@ -417,7 +418,7 @@ void AsmPrinter::emitInlineAsm(const MachineInstr *MI) const { } emitInlineAsm(StringData, getSubtargetInfo(), TM.Options.MCOptions, LocMD, - MI->getInlineAsmDialect()); + MI->getInlineAsmDialect(), MI); // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't // enabled, so we use emitRawComment. @@ -518,4 +519,5 @@ bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, void AsmPrinter::emitInlineAsmStart() const {} void AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const {} + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) {} diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp index 2927b075fc360..41b6489064efd 100644 --- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp @@ -51,6 +51,8 @@ class ExtraFlags { Flags |= InlineAsm::Extra_HasSideEffects; if (IA->isAlignStack()) Flags |= InlineAsm::Extra_IsAlignStack; + if (IA->canThrow()) + Flags |= InlineAsm::Extra_MayUnwind; if (CB.isConvergent()) Flags |= InlineAsm::Extra_IsConvergent; Flags |= IA->getDialect() * InlineAsm::Extra_AsmDialect; diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp index c801d3deafa0f..003f78ecfddd0 100644 --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -1924,6 +1924,8 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST, OS << " [isconvergent]"; if (ExtraInfo & InlineAsm::Extra_IsAlignStack) OS << " [alignstack]"; + if (ExtraInfo & InlineAsm::Extra_MayUnwind) + OS << " [unwind]"; if (getInlineAsmDialect() == InlineAsm::AD_ATT) OS << " [attdialect]"; if (getInlineAsmDialect() == InlineAsm::AD_Intel) diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp index 5ce7606b051a5..9e64a19f1d017 100644 --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -955,8 +955,8 @@ void MachineVerifier::verifyInlineAsm(const MachineInstr *MI) { report("Asm flags must be an immediate", MI); // Allowed flags are Extra_HasSideEffects = 1, Extra_IsAlignStack = 2, // Extra_AsmDialect = 4, Extra_MayLoad = 8, and Extra_MayStore = 16, - // and Extra_IsConvergent = 32. - if (!isUInt<6>(MI->getOperand(1).getImm())) + // and Extra_IsConvergent = 32, Extra_MayUnwind = 64. + if (!isUInt<7>(MI->getOperand(1).getImm())) report("Unknown asm flags", &MI->getOperand(1), 1); static_assert(InlineAsm::MIOp_FirstOperand == 2, "Asm format changed"); diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp index 03727b77b3e1a..dd5587625e2aa 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1162,6 +1162,8 @@ bool FastISel::selectCall(const User *I) { ExtraInfo |= InlineAsm::Extra_HasSideEffects; if (IA->isAlignStack()) ExtraInfo |= InlineAsm::Extra_IsAlignStack; + if (IA->canThrow()) + ExtraInfo |= InlineAsm::Extra_MayUnwind; if (Call->isConvergent()) ExtraInfo |= InlineAsm::Extra_IsConvergent; ExtraInfo |= IA->getDialect() * InlineAsm::Extra_AsmDialect; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index bc8a97cbcc024..e68339bd9b428 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -10057,6 +10057,8 @@ class ExtraFlags { Flags |= InlineAsm::Extra_HasSideEffects; if (IA->isAlignStack()) Flags |= InlineAsm::Extra_IsAlignStack; + if (IA->canThrow()) + Flags |= InlineAsm::Extra_MayUnwind; if (Call.isConvergent()) Flags |= InlineAsm::Extra_IsConvergent; Flags |= IA->getDialect() * InlineAsm::Extra_AsmDialect; diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index 458a3f0ced070..e7d30aec14860 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -519,7 +519,8 @@ static bool isThumb(const MCSubtargetInfo& STI) { } void ARMAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const { + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) { // If either end mode is unknown (EndInfo == NULL) or different than // the start mode, then restore the start mode. const bool WasThumb = isThumb(StartInfo); diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.h b/llvm/lib/Target/ARM/ARMAsmPrinter.h index 12e20d758e415..1d35b3c445958 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.h +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.h @@ -83,7 +83,8 @@ class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter { const char *ExtraCode, raw_ostream &O) override; void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const override; + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) override; void emitJumpTableAddrs(const MachineInstr *MI); void emitJumpTableInsts(const MachineInstr *MI); diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp index 9d8b9f86daf7a..a0e5872da5e6e 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -810,7 +810,8 @@ void MipsAsmPrinter::emitInlineAsmStart() const { } void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const { + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) { OutStreamer->addBlankLine(); getTargetStreamer().emitDirectiveSetPop(); } diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.h b/llvm/lib/Target/Mips/MipsAsmPrinter.h index 8b2fb32dc552d..6d45ad551db72 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.h +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.h @@ -83,7 +83,8 @@ class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { void emitInlineAsmStart() const override; void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, - const MCSubtargetInfo *EndInfo) const override; + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) override; void emitJumpTableEntry(const MachineJumpTableInfo &MJTI, const MachineBasicBlock *MBB, diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h index e02b5562d3b5e..705bb9a4aacfb 100644 --- a/llvm/lib/Target/X86/X86AsmPrinter.h +++ b/llvm/lib/Target/X86/X86AsmPrinter.h @@ -172,6 +172,10 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { void emitInstruction(const MachineInstr *MI) override; + void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) override; + void emitBasicBlockEnd(const MachineBasicBlock &MBB) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp index 2287a921a19c0..1dd702069843b 100644 --- a/llvm/lib/Target/X86/X86MCInstLower.cpp +++ b/llvm/lib/Target/X86/X86MCInstLower.cpp @@ -2627,6 +2627,18 @@ void X86AsmPrinter::emitInstruction(const MachineInstr *MI) { EmitAndCountInstruction(TmpInst); } +void X86AsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, + const MCSubtargetInfo *EndInfo, + const MachineInstr *MI) { + if (MI) { + // If unwinding inline asm ends on a call, wineh may require insertion of + // a nop. + unsigned ExtraInfo = MI->getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_MayUnwind) + maybeEmitNopAfterCallForWindowsEH(MI); + } +} + void X86AsmPrinter::emitCallInstruction(const llvm::MCInst &MCI) { // Stackmap shadows cannot include branch targets, so we can count the bytes // in a call towards the shadow, but must ensure that the no thread returns diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-unwind-inline-asm.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-unwind-inline-asm.ll index fbffb50bcbc8a..1d22682a804ea 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-unwind-inline-asm.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-unwind-inline-asm.ll @@ -21,7 +21,7 @@ define dso_local void @test() personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: [[GV:%[0-9]+]]:_(p0) = G_GLOBAL_VALUE @.str.2 ; CHECK-NEXT: G_INVOKE_REGION_START ; CHECK-NEXT: EH_LABEL <mcsymbol > - ; CHECK-NEXT: INLINEASM &"bl trap", 1 /* sideeffect attdialect */ + ; CHECK-NEXT: INLINEASM &"bl trap", 65 /* sideeffect unwind attdialect */ ; CHECK-NEXT: EH_LABEL <mcsymbol > ; CHECK-NEXT: G_BR %bb.2 ; CHECK-NEXT: {{ $}} diff --git a/llvm/test/CodeGen/X86/seh-unwind-inline-asm-codegen.ll b/llvm/test/CodeGen/X86/seh-unwind-inline-asm-codegen.ll index 5a6aeb6020344..e2959718b6068 100644 --- a/llvm/test/CodeGen/X86/seh-unwind-inline-asm-codegen.ll +++ b/llvm/test/CodeGen/X86/seh-unwind-inline-asm-codegen.ll @@ -15,6 +15,7 @@ entry: ; CHECK-LABEL: .Ltmp0: ; CHECK: callq trap +; CHECK: nop ; CHECK-LABEL: .Ltmp1: invoke void asm sideeffect unwind "call trap", "~{dirflag},~{fpsr},~{flags}"() @@ -27,6 +28,7 @@ except: ; CHECK-LABEL: "?dtor$2@?0?test@4HA": ; CHECK: callq printf +; CHECK: nop %0 = cleanuppad within none [] call void (ptr, ...) @printf(ptr @str) [ "funclet"(token %0) ] _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
