https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/101871
This attribute applies to `GCCAsmStmt` statements or functions. If a function is declared with this, it is effectively the default for all `GCCAsmStmt`s contained in the function. Takes one string argument: `"intel"`, `"att"` or `"reset"`. If `"reset"`, the dialect used will be the one specified on the command line. Resolves #101328 >From 2e544ca9628cdaa4ef8875494f2b5948c7623d21 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sun, 4 Aug 2024 09:09:19 +0100 Subject: [PATCH] [Clang][CodeGen][Sema] Add [[clang::asm_dialect]] attribute --- clang/include/clang/Basic/Attr.td | 7 ++ clang/lib/CodeGen/CGStmt.cpp | 51 ++++++++++++-- clang/lib/CodeGen/CodeGenFunction.h | 4 ++ clang/lib/Parse/ParseStmt.cpp | 12 ++-- clang/lib/Sema/SemaDeclAttr.cpp | 19 ++++++ clang/lib/Sema/SemaStmtAttr.cpp | 22 +++++++ 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..c7dd72f57b52a 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,45 @@ 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..d5bc3d47edb16 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..ff14256afbb49 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5599,6 +5599,22 @@ 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 +6433,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..d47257f7a9526 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -623,6 +623,26 @@ 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 +671,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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits