[clang] [Clang][CodeGen] Add `[[clang::asm_dialect]]` attribute (PR #101871)

Mital Ashok via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 4 01:44:56 PDT 2024


https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/101871

>From 7f8c82071c9cc324acd7f2a79539392e74838545 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sun, 4 Aug 2024 09:09:19 +0100
Subject: [PATCH] [Clang][CodeGen] Add `[[clang::asm_dialect]]` attribute

---
 clang/include/clang/Basic/Attr.td             |  7 ++
 clang/lib/CodeGen/CGStmt.cpp                  | 53 +++++++++++++--
 clang/lib/CodeGen/CodeGenFunction.h           |  4 ++
 clang/lib/Parse/ParseStmt.cpp                 | 12 ++--
 clang/lib/Sema/SemaDeclAttr.cpp               | 18 +++++
 clang/lib/Sema/SemaStmtAttr.cpp               | 21 ++++++
 clang/test/CodeGen/inline-asm-mixed-dialect.c | 66 +++++++++++++++++++
 ...a-attribute-supported-attributes-list.test |  1 +
 8 files changed, 168 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/CodeGen/inline-asm-mixed-dialect.c

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 8ac2079099c85..1249f68e8e645 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4730,3 +4730,10 @@ def ClspvLibclcBuiltin: InheritableAttr {
   let Documentation = [ClspvLibclcBuiltinDoc];
   let SimpleHandler = 1;
 }
+
+def AsmDialect: DeclOrStmtAttr {
+  let Spellings = [Clang<"asm_dialect">];
+  let Subjects = SubjectList<[GCCAsmStmt, Function], ErrorDiag, "'asm' inline assembly statements or functions">;
+  let Args = [EnumArgument<"Dialect", "Kind", /*is_string=*/true, ["intel", "att", "reset", ""], ["Intel", "ATT", "Global", "Local"]>];
+  let Documentation = [Undocumented];
+}
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 30b6fce5d016a..b4b5efa575230 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -724,6 +724,8 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   bool noinline = false;
   bool alwaysinline = false;
   bool noconvergent = false;
+  AsmDialectAttr::Kind asmdialect = AsmDialectAttr::Kind::Local;
+
   const CallExpr *musttail = nullptr;
 
   for (const auto *A : S.getAttrs()) {
@@ -755,6 +757,9 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
         Builder.CreateAssumption(AssumptionVal);
       }
     } break;
+    case attr::AsmDialect: {
+      asmdialect = cast<AsmDialectAttr>(A)->getDialect();
+    } break;
     }
   }
   SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge);
@@ -762,6 +767,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   SaveAndRestore save_alwaysinline(InAlwaysInlineAttributedStmt, alwaysinline);
   SaveAndRestore save_noconvergent(InNoConvergentAttributedStmt, noconvergent);
   SaveAndRestore save_musttail(MustTailCall, musttail);
+  SaveAndRestore save_asmdialect(AsmDialect, asmdialect);
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
 
@@ -3029,12 +3035,47 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
 
   bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0;
 
-  llvm::InlineAsm::AsmDialect GnuAsmDialect =
-      CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
-          ? llvm::InlineAsm::AD_ATT
-          : llvm::InlineAsm::AD_Intel;
-  llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ?
-    llvm::InlineAsm::AD_Intel : GnuAsmDialect;
+  llvm::InlineAsm::AsmDialect AsmDialect;
+  auto GlobalAsmDialect = [&] {
+    return CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT
+               ? llvm::InlineAsm::AD_ATT
+               : llvm::InlineAsm::AD_Intel;
+  };
+  if (auto *GS = dyn_cast<GCCAsmStmt>(&S)) {
+    switch (this->AsmDialect) { // Fixme: rename member
+    case AsmDialectAttr::Intel:
+      AsmDialect = llvm::InlineAsm::AsmDialect::AD_Intel;
+      break;
+    case AsmDialectAttr::ATT:
+      AsmDialect = llvm::InlineAsm::AsmDialect::AD_ATT;
+      break;
+    case AsmDialectAttr::Local:
+      if (CurFuncDecl) {
+        if (auto *DialectAttr = CurFuncDecl->getAttr<AsmDialectAttr>()) {
+          switch (DialectAttr->getDialect()) {
+          case AsmDialectAttr::Intel:
+            AsmDialect = llvm::InlineAsm::AsmDialect::AD_Intel;
+            break;
+          case AsmDialectAttr::ATT:
+            AsmDialect = llvm::InlineAsm::AsmDialect::AD_ATT;
+            break;
+          case AsmDialectAttr::Global:
+          case AsmDialectAttr::Local:
+            AsmDialect = GlobalAsmDialect();
+            break;
+          }
+          break;
+        }
+      }
+      [[fallthrough]];
+    case AsmDialectAttr::Global:
+      AsmDialect = GlobalAsmDialect();
+      break;
+    }
+  } else {
+    assert(isa<MSAsmStmt>(&S));
+    AsmDialect = llvm::InlineAsm::AD_Intel;
+  }
 
   llvm::InlineAsm *IA = llvm::InlineAsm::get(
       FTy, AsmString, Constraints, HasSideEffect,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 6a5faa1e8f343..d8af9285f6d22 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -615,6 +615,10 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// True if the current statement has noconvergent attribute.
   bool InNoConvergentAttributedStmt = false;
 
+  /// Override for the assembly dialect to use when substituting
+  /// parameters (from the [[clang::asm_dialect("kind")]] attribute)
+  AsmDialectAttr::Kind AsmDialect = AsmDialectAttr::Kind::Local;
+
   // The CallExpr within the current statement that the musttail attribute
   // applies to.  nullptr if there is no 'musttail' on the current statement.
   const CallExpr *MustTailCall = nullptr;
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index bdb3fc051d0b3..af8b9be9d8a11 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -356,16 +356,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
     break;
 
   case tok::kw_asm: {
-    for (const ParsedAttr &AL : CXX11Attrs)
+    for (const ParsedAttr &AL : CXX11Attrs) {
       // Could be relaxed if asm-related regular keyword attributes are
       // added later.
-      (AL.isRegularKeywordAttribute()
-           ? Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed)
-           : Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored))
-          << AL;
-    // Prevent these from being interpreted as statement attributes later on.
-    CXX11Attrs.clear();
-    ProhibitAttributes(GNUAttrs);
+      if (AL.isRegularKeywordAttribute())
+        Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed) << AL;
+    }
     bool msAsm = false;
     Res = ParseAsmStatement(msAsm);
     if (msAsm) return Res;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 9011fa547638e..733edcd43e9a6 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5599,6 +5599,21 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
   return ::new (Context) DLLExportAttr(Context, CI);
 }
 
+static void handleAsmDialectAttr(Sema &S, Decl *D, const ParsedAttr &A) {
+  StringRef Name;
+  SourceLocation LiteralLoc;
+  if (!S.checkStringLiteralArgumentAttr(A, 0, Name, &LiteralLoc))
+    return;
+
+  AsmDialectAttr::Kind Kind;
+  if (Name.empty() || !AsmDialectAttr::ConvertStrToKind(Name, Kind)) {
+    S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << A << Name;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) AsmDialectAttr(S.Context, A, Kind));
+}
+
 static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
   if (isa<ClassTemplatePartialSpecializationDecl>(D) &&
       (S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) {
@@ -6417,6 +6432,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
   case ParsedAttr::AT_AMDGPUMaxNumWorkGroups:
     S.AMDGPU().handleAMDGPUMaxNumWorkGroupsAttr(D, AL);
     break;
+  case ParsedAttr::AT_AsmDialect:
+    handleAsmDialectAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_AVRSignal:
     S.AVR().handleSignalAttr(D, AL);
     break;
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index b9b3b4063bc38..48e4fcc4ceb60 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -623,6 +623,25 @@ static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
   return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor);
 }
 
+static Attr *handleAsmDialectAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+                                  SourceRange Range) {
+  if (!A.checkExactlyNumArgs(S, 1))
+    return nullptr;
+
+  StringRef Name;
+  SourceLocation LiteralLoc;
+  if (!S.checkStringLiteralArgumentAttr(A, 0, Name, &LiteralLoc))
+    return nullptr;
+
+  AsmDialectAttr::Kind Kind;
+  if (Name.empty() || !AsmDialectAttr::ConvertStrToKind(Name, Kind)) {
+    S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << A << Name;
+    return nullptr;
+  }
+
+  return ::new (S.Context) AsmDialectAttr(S.Context, A, Kind);
+}
+
 static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
                                   SourceRange Range) {
   if (A.isInvalid() || A.getKind() == ParsedAttr::IgnoredAttribute)
@@ -651,6 +670,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
   switch (A.getKind()) {
   case ParsedAttr::AT_AlwaysInline:
     return handleAlwaysInlineAttr(S, St, A, Range);
+  case ParsedAttr::AT_AsmDialect:
+    return handleAsmDialectAttr(S, St, A, Range);
   case ParsedAttr::AT_CXXAssume:
     return handleCXXAssumeAttr(S, St, A, Range);
   case ParsedAttr::AT_FallThrough:
diff --git a/clang/test/CodeGen/inline-asm-mixed-dialect.c b/clang/test/CodeGen/inline-asm-mixed-dialect.c
new file mode 100644
index 0000000000000..9598888973d8e
--- /dev/null
+++ b/clang/test/CodeGen/inline-asm-mixed-dialect.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -ffreestanding -triple i386 -fasm-blocks -O0 -S %s -o - | FileCheck %s
+// RUN: %clang_cc1 -ffreestanding -triple x86_64 -fasm-blocks -O0 -S %s -o - | FileCheck %s
+// REQUIRES: x86-registered-target
+
+void f(void) {
+  int src = 0;
+  int dst;
+  [[clang::asm_dialect("intel")]] __asm__ (
+    ".intel_syntax noprefix\n\t"
+    "# f1\n\t"
+    "mov %1, %0\n\t"
+    "add %0, 1\n\t"
+    : "=r" (dst)
+    : "r" (src)
+  );
+  // CHECK:      # f1
+  // CHECK-NEXT: movl %eax, %eax
+  // CHECK-NEXT: addl $1, %eax
+  [[clang::asm_dialect("att")]] __asm__ (
+    ".att_syntax prefix\n\t"
+    "# f2\n\t"
+    "movl %1, %0\n\t"
+    "addl $1, %0\n\t"
+    : "=r" (dst)
+    : "r" (src)
+  );
+  // CHECK:      # f2
+  // CHECK-NEXT: movl %eax, %eax
+  // CHECK-NEXT: addl $1, %eax
+}
+
+
+#pragma clang attribute push ([[clang::asm_dialect("intel")]], apply_to = function)
+void intel_fn(void) {
+  int src = 0;
+  int dst;
+  __asm__ (
+    ".intel_syntax noprefix\n\t"
+    "# intel_fn\n\t"
+    "mov %1, %0\n\t"
+    "add %0, 1\n\t"
+    : "=r" (dst)
+    : "r" (src)
+  );
+  // CHECK:      # intel_fn
+  // CHECK-NEXT: movl %eax, %eax
+  // CHECK-NEXT: addl $1, %eax
+}
+#pragma clang attribute pop
+#pragma clang attribute push ([[clang::asm_dialect("att")]], apply_to = function)
+void att_fn(void) {
+  int src = 0;
+  int dst;
+  __asm__ (
+    ".att_syntax prefix\n\t"
+    "# att_fn\n\t"
+    "movl %1, %0\n\t"
+    "addl $1, %0\n\t"
+    : "=r" (dst)
+    : "r" (src)
+  );
+  // CHECK:      # att_fn
+  // CHECK-NEXT: movl %eax, %eax
+  // CHECK-NEXT: addl $1, %eax
+}
+#pragma clang attribute pop
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 0f7dcab7c4248..b8a2da0ed8aae 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -19,6 +19,7 @@
 // CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType)
 // CHECK-NEXT: ArcWeakrefUnavailable (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ArmBuiltinAlias (SubjectMatchRule_function)
+// CHECK-NEXT: AsmDialect (SubjectMatchRule_function)
 // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function)
 // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
 // CHECK-NEXT: AvailableOnlyInDefaultEvalMethod (SubjectMatchRule_type_alias)



More information about the cfe-commits mailing list