Skip to content

Conversation

@tambry
Copy link
Contributor

@tambry tambry commented Nov 9, 2025

This eases interoperability by making it explicit in emitted assembly code which syntax is used. Refactored to remove X86-specific directives and logic from the generic MC(Asm)Streamer.

Motivated by building LLVM with -mllvm -x86-asm-syntax=intel (i.e. a global preference for Intel syntax). A Bolt test (runtime/X86/fdata-escape-chars.ll) was using llc to compile to assembly and then assembling with clang. The specific option causes Clang to assume Intel syntax but only for assembly and not inline assembly.

@tambry tambry requested a review from MaskRay November 9, 2025 17:35
@tambry tambry self-assigned this Nov 9, 2025
@llvmbot llvmbot added llvm:mc Machine (object) code backend:m68k labels Nov 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 9, 2025

@llvm/pr-subscribers-backend-m68k
@llvm/pr-subscribers-llvm-mc

@llvm/pr-subscribers-backend-x86

Author: Raul Tambre (tambry)

Changes

This eases interoperability by making it explicit in emitted assembly code which syntax is used. Refactored to remove X86-specific directives and logic from the generic MC(Asm)Streamer.

Motivated by building LLVM with -mllvm -x86-asm-syntax=intel (i.e. a global preference for Intel syntax). A Bolt test (runtime/X86/fdata-escape-chars.ll) was using llc to compile to assembly and then assembling with clang. The specific option causes Clang to assume Intel syntax but only for assembly and not inline assembly.


Full diff: https://github.com/llvm/llvm-project/pull/167234.diff

8 Files Affected:

  • (modified) llvm/docs/ReleaseNotes.md (+2)
  • (modified) llvm/include/llvm/MC/MCStreamer.h (+1-1)
  • (modified) llvm/lib/MC/MCAsmStreamer.cpp (+6-8)
  • (modified) llvm/lib/MC/MCStreamer.cpp (+1-1)
  • (modified) llvm/lib/Target/M68k/M68kAsmPrinter.cpp (+3-1)
  • (modified) llvm/lib/Target/X86/X86AsmPrinter.cpp (+7-1)
  • (added) llvm/test/CodeGen/X86/asm-syntax-directive.ll (+7)
  • (modified) llvm/test/CodeGen/X86/coal-sections.ll (+1-1)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index fd78c97c86d24..ee8072c68855d 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -152,6 +152,8 @@ Changes to the X86 Backend
 
 * `-mcpu=wildcatlake` is now supported.
 * `-mcpu=novalake` is now supported.
+* `.att_syntax` is now emitted at the beginning of the file when emitting AT&T
+  syntax assembly.
 
 Changes to the OCaml bindings
 -----------------------------
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 79c715e3820a6..eaee7957e090d 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1055,7 +1055,7 @@ class LLVM_ABI MCStreamer {
   /// Get the .xdata section used for the given section.
   MCSection *getAssociatedXDataSection(const MCSection *TextSec);
 
-  virtual void emitSyntaxDirective();
+  virtual void emitSyntaxDirective(StringRef Syntax, StringRef Options);
 
   /// Record a relocation described by the .reloc directive.
   virtual void emitRelocDirective(const MCExpr &Offset, StringRef Name,
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 885fa55b65d50..dc5673234ed2e 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -123,7 +123,7 @@ class MCAsmStreamer final : public MCStreamer {
     EmitCommentsAndEOL();
   }
 
-  void emitSyntaxDirective() override;
+  void emitSyntaxDirective(StringRef Syntax, StringRef Options) override;
 
   void EmitCommentsAndEOL();
 
@@ -796,14 +796,12 @@ void MCAsmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
   EmitEOL();
 }
 
-void MCAsmStreamer::emitSyntaxDirective() {
-  if (MAI->getAssemblerDialect() == 1) {
-    OS << "\t.intel_syntax noprefix";
-    EmitEOL();
+void MCAsmStreamer::emitSyntaxDirective(StringRef Syntax, StringRef Options) {
+  OS << "\t." << Syntax << "_syntax";
+  if (!Options.empty()) {
+    OS << " " << Options;
   }
-  // FIXME: Currently emit unprefix'ed registers.
-  // The intel_syntax directive has one optional argument
-  // with may have a value of prefix or noprefix.
+  EmitEOL();
 }
 
 void MCAsmStreamer::beginCOFFSymbolDef(const MCSymbol *Symbol) {
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index bc7398120096e..108ddf9910f82 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -876,7 +876,7 @@ MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) {
                           TextSec);
 }
 
-void MCStreamer::emitSyntaxDirective() {}
+void MCStreamer::emitSyntaxDirective(StringRef Syntax, StringRef Options) {}
 
 static unsigned encodeSEHRegNum(MCContext &Ctx, MCRegister Reg) {
   return Ctx.getRegisterInfo()->getSEHRegNum(Reg);
diff --git a/llvm/lib/Target/M68k/M68kAsmPrinter.cpp b/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
index 0437400b81d84..866db23f3ea56 100644
--- a/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
+++ b/llvm/lib/Target/M68k/M68kAsmPrinter.cpp
@@ -190,7 +190,9 @@ void M68kAsmPrinter::emitFunctionBodyStart() {}
 void M68kAsmPrinter::emitFunctionBodyEnd() {}
 
 void M68kAsmPrinter::emitStartOfAsmFile(Module &M) {
-  OutStreamer->emitSyntaxDirective();
+  const bool IntelSyntax{MAI->getAssemblerDialect() == InlineAsm::AD_Intel};
+  OutStreamer->emitSyntaxDirective(IntelSyntax ? "intel" : "att",
+                                   IntelSyntax ? "noprefix" : "");
 }
 
 void M68kAsmPrinter::emitEndOfAsmFile(Module &M) {}
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 84b921222a116..8b0420de01e71 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -932,7 +932,13 @@ void X86AsmPrinter::emitStartOfAsmFile(Module &M) {
     if (M.getModuleFlag("import-call-optimization"))
       EnableImportCallOptimization = true;
   }
-  OutStreamer->emitSyntaxDirective();
+
+  // FIXME: Currently emit unprefix'ed registers.
+  // The intel_syntax directive has one optional argument
+  // with may have a value of prefix or noprefix.
+  const bool IntelSyntax{MAI->getAssemblerDialect() == InlineAsm::AD_Intel};
+  OutStreamer->emitSyntaxDirective(IntelSyntax ? "intel" : "att",
+                                   IntelSyntax ? "noprefix" : "");
 
   // If this is not inline asm and we're in 16-bit
   // mode prefix assembly with .code16.
diff --git a/llvm/test/CodeGen/X86/asm-syntax-directive.ll b/llvm/test/CodeGen/X86/asm-syntax-directive.ll
new file mode 100644
index 0000000000000..4cdf4408c2084
--- /dev/null
+++ b/llvm/test/CodeGen/X86/asm-syntax-directive.ll
@@ -0,0 +1,7 @@
+;; Make sure that we always emit an assembly syntax directive for X86.
+; RUN: llc < %s -mtriple=x86_64 | FileCheck %s --check-prefix=ATT
+; RUN: llc < %s -mtriple=x86_64 -x86-asm-syntax=att | FileCheck %s --check-prefix=ATT
+; RUN: llc < %s -mtriple=x86_64 -x86-asm-syntax=intel | FileCheck %s --check-prefix=INTEL
+
+; INTEL: .intel_syntax noprefix
+; ATT: .att_syntax
diff --git a/llvm/test/CodeGen/X86/coal-sections.ll b/llvm/test/CodeGen/X86/coal-sections.ll
index 3fed158befdd8..faab0397a4053 100644
--- a/llvm/test/CodeGen/X86/coal-sections.ll
+++ b/llvm/test/CodeGen/X86/coal-sections.ll
@@ -3,7 +3,7 @@
 ; Check that *coal* sections are not emitted.
 
 ; CHECK: .section  __TEXT,__text,regular,pure_instructions{{$}}
-; CHECK-NEXT: .globl  _foo
+; CHECK: .globl  _foo
 
 ; CHECK: .section  __TEXT,__const{{$}}
 ; CHECK-NEXT: .globl  _a

This eases interoperability by making it explicit in emitted assembly code which syntax is used.
Refactored to remove X86-specific directives and logic from the generic MC(Asm)Streamer.

Motivated by building LLVM with `-mllvm -x86-asm-syntax=intel` (i.e. a global preference for Intel
syntax). A Bolt test (`runtime/X86/fdata-escape-chars.ll`) was using `llc` to compile to assembly
and then assembling with `clang`. The specific option causes Clang to assume Intel syntax but only
for assembly and not inline assembly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants