[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:21:53 PDT 2024
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/101871
>From 321934e1fc59908cbcd7fac4992e2b85357899d4 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 +++++++++++++++++++
7 files changed, 167 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
More information about the cfe-commits
mailing list