[llvm] [ms] [llvm-ml] Implement support for PROC NEAR/FAR (PR #131707)

Eric Astor via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 23 19:46:16 PDT 2025


https://github.com/ericastor updated https://github.com/llvm/llvm-project/pull/131707

>From b15ee713ea034abf19e79a17933f3f90b301a447 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Mon, 17 Mar 2025 21:48:58 +0000
Subject: [PATCH 1/4] [ms] [llvm-ml] Implement support for PROC NEAR/FAR

Matches ML.EXE by translating "ret" instructions inside a `PROC FAR` to "retf", and automatically prepending a `push cs` to all near calls to a `PROC FAR`.
---
 llvm/include/llvm/MC/MCContext.h              |  7 ++
 llvm/include/llvm/MC/MCSymbolCOFF.h           |  4 ++
 llvm/lib/MC/MCParser/COFFMasmParser.cpp       | 72 ++++++++++++++-----
 .../lib/Target/X86/AsmParser/X86AsmParser.cpp | 53 +++++++++++++-
 llvm/test/tools/llvm-ml/proc_distance.asm     | 56 +++++++++++++++
 5 files changed, 173 insertions(+), 19 deletions(-)
 create mode 100644 llvm/test/tools/llvm-ml/proc_distance.asm

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index e97c890ce9135..70b90834f1edc 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -97,9 +97,13 @@ class MCContext {
     IsDXContainer
   };
 
+  enum DefaultRetType { IsNear, IsFar };
+
 private:
   Environment Env;
 
+  DefaultRetType DefaultRet = IsNear;
+
   /// The name of the Segment where Swift5 Reflection Section data will be
   /// outputted
   StringRef Swift5ReflectionSegmentName;
@@ -394,6 +398,9 @@ class MCContext {
 
   Environment getObjectFileType() const { return Env; }
 
+  DefaultRetType getDefaultRetType() const { return DefaultRet; }
+  void setDefaultRetType(DefaultRetType DR) { DefaultRet = DR; }
+
   const StringRef &getSwift5ReflectionSegmentName() const {
     return Swift5ReflectionSegmentName;
   }
diff --git a/llvm/include/llvm/MC/MCSymbolCOFF.h b/llvm/include/llvm/MC/MCSymbolCOFF.h
index 2964c521e8e44..c0ddef5cfee50 100644
--- a/llvm/include/llvm/MC/MCSymbolCOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolCOFF.h
@@ -25,6 +25,7 @@ class MCSymbolCOFF : public MCSymbol {
     SF_ClassShift = 0,
 
     SF_SafeSEH = 0x0100,
+    SF_FarProc = 0x0200,
     SF_WeakExternalCharacteristicsMask = 0x0E00,
     SF_WeakExternalCharacteristicsShift = 9,
   };
@@ -66,6 +67,9 @@ class MCSymbolCOFF : public MCSymbol {
     modifyFlags(SF_SafeSEH, SF_SafeSEH);
   }
 
+  bool isFarProc() const { return getFlags() & SF_FarProc; }
+  void setIsFarProc() const { modifyFlags(SF_FarProc, SF_FarProc); }
+
   static bool classof(const MCSymbol *S) { return S->isCOFF(); }
 };
 
diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
index 8464a2392680b..4ed73e6d93be0 100644
--- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "third_party/llvm/llvm-project/llvm/include/llvm/MC/MCContext.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/COFF.h"
@@ -41,6 +42,7 @@ class COFFMasmParser : public MCAsmParserExtension {
                           StringRef COMDATSymName, COFF::COMDATType Type,
                           Align Alignment);
 
+  bool parseDirectiveModel(StringRef, SMLoc);
   bool parseDirectiveProc(StringRef, SMLoc);
   bool parseDirectiveEndProc(StringRef, SMLoc);
   bool parseDirectiveSegment(StringRef, SMLoc);
@@ -167,7 +169,7 @@ class COFFMasmParser : public MCAsmParserExtension {
     // .exit
     // .fardata
     // .fardata?
-    addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
+    addDirectiveHandler<&COFFMasmParser::parseDirectiveModel>(".model");
     // .stack
     // .startup
 
@@ -201,8 +203,13 @@ class COFFMasmParser : public MCAsmParserExtension {
   }
 
   /// Stack of active procedure definitions.
-  SmallVector<StringRef, 1> CurrentProcedures;
-  SmallVector<bool, 1> CurrentProceduresFramed;
+  enum ProcDistance { PROC_DISTANCE_NEAR = 0, PROC_DISTANCE_FAR = 1 };
+  struct ProcInfo {
+    StringRef Name;
+    ProcDistance Distance = PROC_DISTANCE_NEAR;
+    bool IsFramed = false;
+  };
+  SmallVector<ProcInfo, 1> CurrentProcedures;
 
 public:
   COFFMasmParser() = default;
@@ -435,48 +442,75 @@ bool COFFMasmParser::parseDirectiveOption(StringRef Directive, SMLoc Loc) {
   return false;
 }
 
+/// parseDirectiveModel
+///  ::= ".model" "flat"
+bool COFFMasmParser::parseDirectiveModel(StringRef Directive, SMLoc Loc) {
+  if (!getLexer().is(AsmToken::Identifier))
+    return TokError("expected identifier in directive");
+
+  StringRef ModelType = getTok().getIdentifier();
+  if (!ModelType.equals_insensitive("flat")) {
+    return TokError(
+        "expected 'flat' for memory model; no other models supported");
+  }
+
+  // Ignore; no action necessary.
+  Lex();
+  return false;
+}
+
 /// parseDirectiveProc
 /// TODO(epastor): Implement parameters and other attributes.
-///  ::= label "proc" [[distance]]
+///  ::= label "proc" [[distance]] [[frame]]
 ///          statements
 ///      label "endproc"
 bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
   if (!getStreamer().getCurrentFragment())
     return Error(getTok().getLoc(), "expected section directive");
 
-  StringRef Label;
-  if (getParser().parseIdentifier(Label))
+  ProcInfo Proc;
+  if (getParser().parseIdentifier(Proc.Name))
     return Error(Loc, "expected identifier for procedure");
   if (getLexer().is(AsmToken::Identifier)) {
     StringRef nextVal = getTok().getString();
     SMLoc nextLoc = getTok().getLoc();
     if (nextVal.equals_insensitive("far")) {
-      // TODO(epastor): Handle far procedure definitions.
       Lex();
-      return Error(nextLoc, "far procedure definitions not yet supported");
+      Proc.Distance = PROC_DISTANCE_FAR;
+      nextVal = getTok().getString();
+      nextLoc = getTok().getLoc();
     } else if (nextVal.equals_insensitive("near")) {
       Lex();
+      Proc.Distance = PROC_DISTANCE_NEAR;
       nextVal = getTok().getString();
       nextLoc = getTok().getLoc();
     }
   }
-  MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
+  MCSymbolCOFF *Sym =
+      cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Proc.Name));
 
   // Define symbol as simple external function
   Sym->setExternal(true);
   Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
+  if (Proc.Distance == PROC_DISTANCE_FAR)
+    Sym->setIsFarProc();
+
+  getContext().setDefaultRetType(Proc.Distance == PROC_DISTANCE_NEAR
+                                     ? MCContext::IsNear
+                                     : MCContext::IsFar);
 
-  bool Framed = false;
   if (getLexer().is(AsmToken::Identifier) &&
       getTok().getString().equals_insensitive("frame")) {
     Lex();
-    Framed = true;
+    Proc.IsFramed = true;
+    getStreamer().emitWinCFIStartProc(Sym, Loc);
+  }
+  if (Proc.IsFramed) {
     getStreamer().emitWinCFIStartProc(Sym, Loc);
   }
   getStreamer().emitLabel(Sym, Loc);
 
-  CurrentProcedures.push_back(Label);
-  CurrentProceduresFramed.push_back(Framed);
+  CurrentProcedures.push_back(std::move(Proc));
   return false;
 }
 bool COFFMasmParser::parseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
@@ -487,15 +521,19 @@ bool COFFMasmParser::parseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
 
   if (CurrentProcedures.empty())
     return Error(Loc, "endp outside of procedure block");
-  else if (!CurrentProcedures.back().equals_insensitive(Label))
+  else if (!CurrentProcedures.back().Name.equals_insensitive(Label))
     return Error(LabelLoc, "endp does not match current procedure '" +
-                               CurrentProcedures.back() + "'");
+                               CurrentProcedures.back().Name + "'");
 
-  if (CurrentProceduresFramed.back()) {
+  if (CurrentProcedures.back().IsFramed) {
     getStreamer().emitWinCFIEndProc(Loc);
   }
   CurrentProcedures.pop_back();
-  CurrentProceduresFramed.pop_back();
+  getContext().setDefaultRetType(
+      (CurrentProcedures.empty() ||
+       CurrentProcedures.back().Distance == PROC_DISTANCE_NEAR)
+          ? MCContext::IsNear
+          : MCContext::IsFar);
   return false;
 }
 
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index a6285a55f4155..c4a92f37cb325 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -32,6 +32,7 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolCOFF.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
@@ -1202,6 +1203,10 @@ class X86AsmParser : public MCTargetAsmParser {
   void MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op, OperandVector &Operands,
                          MCStreamer &Out, bool MatchingInlineAsm);
 
+  void MatchMASMFarCallToNear(SMLoc IDLoc, X86Operand &Op,
+                              OperandVector &Operands, MCStreamer &Out,
+                              bool MatchingInlineAsm);
+
   bool ErrorMissingFeature(SMLoc IDLoc, const FeatureBitset &MissingFeatures,
                            bool MatchingInlineAsm);
 
@@ -2740,11 +2745,11 @@ bool X86AsmParser::parseIntelOperand(OperandVector &Operands, StringRef Name) {
   if ((BaseReg || IndexReg || RegNo || DefaultBaseReg))
     Operands.push_back(X86Operand::CreateMem(
         getPointerWidth(), RegNo, Disp, BaseReg, IndexReg, Scale, Start, End,
-        Size, DefaultBaseReg, /*SymName=*/StringRef(), /*OpDecl=*/nullptr,
+        Size, DefaultBaseReg, /*SymName=*/SM.getSymName(), /*OpDecl=*/nullptr,
         /*FrontendSize=*/0, /*UseUpRegs=*/false, MaybeDirectBranchDest));
   else
     Operands.push_back(X86Operand::CreateMem(
-        getPointerWidth(), Disp, Start, End, Size, /*SymName=*/StringRef(),
+        getPointerWidth(), Disp, Start, End, Size, /*SymName=*/SM.getSymName(),
         /*OpDecl=*/nullptr, /*FrontendSize=*/0, /*UseUpRegs=*/false,
         MaybeDirectBranchDest));
   return false;
@@ -3442,6 +3447,14 @@ bool X86AsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
     }
   }
 
+  if (Parser.isParsingMasm() && !is64BitMode()) {
+    // MASM implicitly converts "ret" to "retf" in far procedures; this is
+    // reflected in the default return type in the MCContext.
+    if (PatchedName == "ret" &&
+        getContext().getDefaultRetType() == MCContext::IsFar)
+      PatchedName = "retf";
+  }
+
   // Determine whether this is an instruction prefix.
   // FIXME:
   // Enhance prefixes integrity robustness. for example, following forms
@@ -4130,6 +4143,11 @@ bool X86AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   // First, handle aliases that expand to multiple instructions.
   MatchFPUWaitAlias(IDLoc, static_cast<X86Operand &>(*Operands[0]), Operands,
                     Out, MatchingInlineAsm);
+  if (getParser().isParsingMasm() && !is64BitMode()) {
+    MatchMASMFarCallToNear(IDLoc, static_cast<X86Operand &>(*Operands[0]),
+                           Operands, Out, MatchingInlineAsm);
+  }
+
   unsigned Prefixes = getPrefixes(Operands);
 
   MCInst Inst;
@@ -4191,6 +4209,37 @@ void X86AsmParser::MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op,
   }
 }
 
+void X86AsmParser::MatchMASMFarCallToNear(SMLoc IDLoc, X86Operand &Op,
+                                          OperandVector &Operands,
+                                          MCStreamer &Out,
+                                          bool MatchingInlineAsm) {
+  // FIXME: This should be replaced with a real .td file alias mechanism.
+  // Also, MatchInstructionImpl should actually *do* the EmitInstruction
+  // call.
+  if (Op.getToken() != "call")
+    return;
+  // This is a call instruction...
+
+  X86Operand &Operand = static_cast<X86Operand &>(*Operands[1]);
+  MCSymbol *Sym = getContext().lookupSymbol(Operand.getSymName());
+  if (Sym == nullptr || !Sym->isInSection() || !Sym->isCOFF() ||
+      !dyn_cast<MCSymbolCOFF>(Sym)->isFarProc())
+    return;
+  // Sym is a reference to a far proc in a code section....
+
+  if (Out.getCurrentSectionOnly() == &Sym->getSection()) {
+    // This is a call to a symbol declared as a far proc, and will be emitted as
+    // a near call... so we need to explicitly push the code section register
+    // before the call.
+    MCInst Inst;
+    Inst.setOpcode(X86::PUSH32r);
+    Inst.addOperand(MCOperand::createReg(MCRegister(X86::CS)));
+    Inst.setLoc(IDLoc);
+    if (!MatchingInlineAsm)
+      emitInstruction(Inst, Operands, Out);
+  }
+}
+
 bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc,
                                        const FeatureBitset &MissingFeatures,
                                        bool MatchingInlineAsm) {
diff --git a/llvm/test/tools/llvm-ml/proc_distance.asm b/llvm/test/tools/llvm-ml/proc_distance.asm
new file mode 100644
index 0000000000000..71db903640b42
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/proc_distance.asm
@@ -0,0 +1,56 @@
+; RUN: llvm-ml -m32 -filetype=s %s /Fo - | FileCheck %s
+
+.code
+
+DefaultProc PROC
+  ret
+DefaultProc ENDP
+; CHECK: DefaultProc:
+; CHECK: {{^ *}}ret{{ *$}}
+
+t1:
+call DefaultProc
+; CHECK: t1:
+; CHECK-NEXT: call DefaultProc
+
+NearProc PROC NEAR
+  ret
+NearProc ENDP
+; CHECK: NearProc:
+; CHECK: {{^ *}}ret{{ *$}}
+
+t2:
+call NearProc
+; CHECK: t2:
+; CHECK-NEXT: call NearProc
+
+FarProcInCode PROC FAR
+  ret
+FarProcInCode ENDP
+; CHECK: FarProcInCode:
+; CHECK: {{^ *}}retf{{ *$}}
+
+t3:
+call FarProcInCode
+; CHECK: t3:
+; CHECK-NEXT: push cs
+; CHECK-NEXT: call FarProcInCode
+
+FarCode SEGMENT SHARED NOPAGE NOCACHE INFO READ WRITE EXECUTE DISCARD
+
+FarProcInFarCode PROC FAR
+  ret
+FarProcInFarCode ENDP
+; CHECK: FarProcInFarCode:
+; CHECK: {{^ *}}retf{{ *$}}
+
+FarCode ENDS
+
+.code
+
+t4:
+call FarProcInFarCode
+; CHECK: t4:
+; CHECK-NEXT: call FarProcInFarCode
+
+END

>From b68722b8a378998e391bc75b98fea3388f48edba Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Tue, 18 Mar 2025 03:32:33 +0000
Subject: [PATCH 2/4] Fix a duplicated (and broken) import

---
 llvm/lib/MC/MCParser/COFFMasmParser.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
index 4ed73e6d93be0..6d27ec04f0f21 100644
--- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -6,7 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "third_party/llvm/llvm-project/llvm/include/llvm/MC/MCContext.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/BinaryFormat/COFF.h"

>From 9c08e197b79686939b8c1d77fbbb86e0eb7edaa3 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Tue, 18 Mar 2025 12:26:46 +0000
Subject: [PATCH 3/4] Fix contended handling between NEAR/FAR and FRAME

---
 llvm/lib/MC/MCParser/COFFMasmParser.cpp | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
index 6d27ec04f0f21..ecaa84c59624f 100644
--- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -470,7 +470,7 @@ bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
   ProcInfo Proc;
   if (getParser().parseIdentifier(Proc.Name))
     return Error(Loc, "expected identifier for procedure");
-  if (getLexer().is(AsmToken::Identifier)) {
+  while (getLexer().is(AsmToken::Identifier)) {
     StringRef nextVal = getTok().getString();
     SMLoc nextLoc = getTok().getLoc();
     if (nextVal.equals_insensitive("far")) {
@@ -483,6 +483,13 @@ bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
       Proc.Distance = PROC_DISTANCE_NEAR;
       nextVal = getTok().getString();
       nextLoc = getTok().getLoc();
+    } else if (nextVal.equals_insensitive("frame")) {
+      Lex();
+      Proc.IsFramed = true;
+      nextVal = getTok().getString();
+      nextLoc = getTok().getLoc();
+    } else {
+      break;
     }
   }
   MCSymbolCOFF *Sym =
@@ -498,12 +505,6 @@ bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
                                      ? MCContext::IsNear
                                      : MCContext::IsFar);
 
-  if (getLexer().is(AsmToken::Identifier) &&
-      getTok().getString().equals_insensitive("frame")) {
-    Lex();
-    Proc.IsFramed = true;
-    getStreamer().emitWinCFIStartProc(Sym, Loc);
-  }
   if (Proc.IsFramed) {
     getStreamer().emitWinCFIStartProc(Sym, Loc);
   }

>From b4d7c741ba8e29058383a820625a0e6797942903 Mon Sep 17 00:00:00 2001
From: Eric Astor <epastor at google.com>
Date: Mon, 24 Mar 2025 02:40:42 +0000
Subject: [PATCH 4/4] Introduce public MCMasmParser interface, and use it for
 MASM-specific context

Moves the DefaultRetIsFar information from MCContext to MCMasmParser.
---
 llvm/include/llvm/MC/MCContext.h              |  7 -----
 llvm/include/llvm/MC/MCParser/MCMasmParser.h  | 29 +++++++++++++++++++
 llvm/lib/MC/MCParser/COFFMasmParser.cpp       | 16 +++++-----
 llvm/lib/MC/MCParser/MasmParser.cpp           | 17 +++++++++--
 .../lib/Target/X86/AsmParser/X86AsmParser.cpp |  3 +-
 5 files changed, 53 insertions(+), 19 deletions(-)
 create mode 100644 llvm/include/llvm/MC/MCParser/MCMasmParser.h

diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 70b90834f1edc..e97c890ce9135 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -97,13 +97,9 @@ class MCContext {
     IsDXContainer
   };
 
-  enum DefaultRetType { IsNear, IsFar };
-
 private:
   Environment Env;
 
-  DefaultRetType DefaultRet = IsNear;
-
   /// The name of the Segment where Swift5 Reflection Section data will be
   /// outputted
   StringRef Swift5ReflectionSegmentName;
@@ -398,9 +394,6 @@ class MCContext {
 
   Environment getObjectFileType() const { return Env; }
 
-  DefaultRetType getDefaultRetType() const { return DefaultRet; }
-  void setDefaultRetType(DefaultRetType DR) { DefaultRet = DR; }
-
   const StringRef &getSwift5ReflectionSegmentName() const {
     return Swift5ReflectionSegmentName;
   }
diff --git a/llvm/include/llvm/MC/MCParser/MCMasmParser.h b/llvm/include/llvm/MC/MCParser/MCMasmParser.h
new file mode 100644
index 0000000000000..a34c6eba8bc59
--- /dev/null
+++ b/llvm/include/llvm/MC/MCParser/MCMasmParser.h
@@ -0,0 +1,29 @@
+//===- llvm/MC/MasmParser.h - MASM Parser Interface -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MC_MCPARSER_MCMASMPARSER_H
+#define LLVM_MC_MCPARSER_MCMASMPARSER_H
+
+#include "llvm/MC/MCParser/MCAsmParser.h"
+
+namespace llvm {
+
+/// MASM-type assembler parser interface.
+class MCMasmParser : public MCAsmParser {
+public:
+  virtual bool getDefaultRetIsFar() const = 0;
+  virtual void setDefaultRetIsFar(bool IsFar) = 0;
+
+  bool isParsingMasm() const override { return true; }
+
+  static bool classof(const MCAsmParser *AP) { return AP->isParsingMasm(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_MC_MCPARSER_MCMASMPARSER_H
diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
index ecaa84c59624f..94f69402ad082 100644
--- a/llvm/lib/MC/MCParser/COFFMasmParser.cpp
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -12,7 +12,9 @@
 #include "llvm/MC/MCAsmMacro.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCMasmParser.h"
 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
 #include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCStreamer.h"
@@ -501,9 +503,8 @@ bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
   if (Proc.Distance == PROC_DISTANCE_FAR)
     Sym->setIsFarProc();
 
-  getContext().setDefaultRetType(Proc.Distance == PROC_DISTANCE_NEAR
-                                     ? MCContext::IsNear
-                                     : MCContext::IsFar);
+  cast<MCMasmParser>(getParser())
+      .setDefaultRetIsFar(Proc.Distance == PROC_DISTANCE_FAR);
 
   if (Proc.IsFramed) {
     getStreamer().emitWinCFIStartProc(Sym, Loc);
@@ -529,11 +530,10 @@ bool COFFMasmParser::parseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
     getStreamer().emitWinCFIEndProc(Loc);
   }
   CurrentProcedures.pop_back();
-  getContext().setDefaultRetType(
-      (CurrentProcedures.empty() ||
-       CurrentProcedures.back().Distance == PROC_DISTANCE_NEAR)
-          ? MCContext::IsNear
-          : MCContext::IsFar);
+  cast<MCMasmParser>(getParser())
+      .setDefaultRetIsFar(!CurrentProcedures.empty() &&
+                          CurrentProcedures.back().Distance ==
+                              PROC_DISTANCE_FAR);
   return false;
 }
 
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index c1a451a7119d5..cb28b70b33b3f 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -36,6 +36,7 @@
 #include "llvm/MC/MCParser/MCAsmLexer.h"
 #include "llvm/MC/MCParser/MCAsmParser.h"
 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCMasmParser.h"
 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -65,6 +66,7 @@
 #include <memory>
 #include <optional>
 #include <sstream>
+#include <stdbool.h>
 #include <string>
 #include <tuple>
 #include <utility>
@@ -373,7 +375,7 @@ FieldInitializer &FieldInitializer::operator=(FieldInitializer &&Initializer) {
 /// The concrete assembly parser instance.
 // Note that this is a full MCAsmParser, not an MCAsmParserExtension!
 // It's a peer of AsmParser, not of COFFAsmParser, WasmAsmParser, etc.
-class MasmParser : public MCAsmParser {
+class MasmParser : public MCMasmParser {
 private:
   AsmLexer Lexer;
   MCContext &Ctx;
@@ -456,6 +458,9 @@ class MasmParser : public MCAsmParser {
   /// Are we parsing ms-style inline assembly?
   bool ParsingMSInlineAsm = false;
 
+  /// Is the current default `ret` instruction far?
+  bool DefaultRetIsFar = false;
+
   // Current <...> expression depth.
   unsigned AngleBracketDepth = 0U;
 
@@ -481,6 +486,14 @@ class MasmParser : public MCAsmParser {
     DirectiveKindMap[Directive] = DirectiveKindMap[Alias];
   }
 
+  /// @name MCMasmParser Interface
+  /// {
+
+  bool getDefaultRetIsFar() const override { return DefaultRetIsFar; }
+  void setDefaultRetIsFar(bool IsFar) override { DefaultRetIsFar = IsFar; }
+
+  /// }
+
   /// @name MCAsmParser Interface
   /// {
 
@@ -517,8 +530,6 @@ class MasmParser : public MCAsmParser {
   }
   bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; }
 
-  bool isParsingMasm() const override { return true; }
-
   bool defineMacro(StringRef Name, StringRef Value) override;
 
   bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override;
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index c4a92f37cb325..5fb39f80cc68d 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -25,6 +25,7 @@
 #include "llvm/MC/MCInstrInfo.h"
 #include "llvm/MC/MCParser/MCAsmLexer.h"
 #include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCMasmParser.h"
 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -3451,7 +3452,7 @@ bool X86AsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
     // MASM implicitly converts "ret" to "retf" in far procedures; this is
     // reflected in the default return type in the MCContext.
     if (PatchedName == "ret" &&
-        getContext().getDefaultRetType() == MCContext::IsFar)
+        cast<MCMasmParser>(getParser()).getDefaultRetIsFar())
       PatchedName = "retf";
   }
 



More information about the llvm-commits mailing list