https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/153546
>From b1b7b10975ecd212405d7f8a7a4021821b95fc7b Mon Sep 17 00:00:00 2001 From: Iris Shi <0...@owo.li> Date: Thu, 14 Aug 2025 15:12:18 +0800 Subject: [PATCH 1/2] [CIR] Implement codegen for inline assembly without input and output operands --- clang/include/clang/CIR/MissingFeatures.h | 5 + clang/lib/CIR/CodeGen/CIRGenAsm.cpp | 136 ++++++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 2 + clang/lib/CIR/CodeGen/CIRGenModule.h | 1 + clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 5 +- clang/lib/CIR/CodeGen/CMakeLists.txt | 1 + clang/test/CIR/CodeGen/inline-asm.c | 18 +++ 7 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 clang/lib/CIR/CodeGen/CIRGenAsm.cpp create mode 100644 clang/test/CIR/CodeGen/inline-asm.c diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index baab62f572b98..ebf57246ba0b9 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -176,7 +176,12 @@ struct MissingFeatures { static bool aggValueSlotVolatile() { return false; } static bool alignCXXRecordDecl() { return false; } static bool armComputeVolatileBitfields() { return false; } + static bool asmGoto() { return false; } + static bool asmInputOperands() { return false; } static bool asmLabelAttr() { return false; } + static bool asmMemoryEffects() { return false; } + static bool asmOutputOperands() { return false; } + static bool asmUnwindClobber() { return false; } static bool assignMemcpyizer() { return false; } static bool astVarDeclInterface() { return false; } static bool attributeBuiltin() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp new file mode 100644 index 0000000000000..fdf59f071335b --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp @@ -0,0 +1,136 @@ +//===--- CIRGenAsm.cpp - Inline Assembly Support for CIR CodeGen ---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains code to emit inline assembly. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/DiagnosticSema.h" +#include "llvm/ADT/StringExtras.h" + +#include "CIRGenFunction.h" +#include "TargetInfo.h" +#include "clang/CIR/MissingFeatures.h" + +using namespace clang; +using namespace clang::CIRGen; +using namespace cir; + +static AsmFlavor inferFlavor(const CIRGenModule &cgm, const AsmStmt &s) { + AsmFlavor gnuAsmFlavor = + cgm.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT + ? AsmFlavor::x86_att + : AsmFlavor::x86_intel; + + return isa<MSAsmStmt>(&s) ? AsmFlavor::x86_intel : gnuAsmFlavor; +} + +static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, + std::string &constraints, bool &hasUnwindClobber, + bool &readOnly, bool readNone) { + + hasUnwindClobber = false; + const CIRGenModule &cgm = cgf.getCIRGenModule(); + + // Clobbers + for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) { + std::string clobberStr = s.getClobber(i); + StringRef clobber{clobberStr}; + if (clobber == "memory") + readOnly = readNone = false; + else if (clobber == "unwind") { + hasUnwindClobber = true; + continue; + } else if (clobber != "cc") { + clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber); + if (cgm.getCodeGenOpts().StackClashProtector && + cgf.getTarget().isSPRegName(clobber)) { + cgm.getDiags().Report(s.getAsmLoc(), + diag::warn_stack_clash_protection_inline_asm); + } + } + + if (isa<MSAsmStmt>(&s)) { + if (clobber == "eax" || clobber == "edx") { + if (constraints.find("=&A") != std::string::npos) + continue; + std::string::size_type position1 = + constraints.find("={" + clobber.str() + "}"); + if (position1 != std::string::npos) { + constraints.insert(position1 + 1, "&"); + continue; + } + std::string::size_type position2 = constraints.find("=A"); + if (position2 != std::string::npos) { + constraints.insert(position2 + 1, "&"); + continue; + } + } + } + if (!constraints.empty()) + constraints += ','; + + constraints += "~{"; + constraints += clobber; + constraints += '}'; + } + + // Add machine specific clobbers + std::string_view machineClobbers = cgf.getTarget().getClobbers(); + if (!machineClobbers.empty()) { + if (!constraints.empty()) + constraints += ','; + constraints += machineClobbers; + } +} + +mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) { + // Assemble the final asm string. + std::string asmString = s.generateAsmString(getContext()); + + std::string constraints; + + // An inline asm can be marked readonly if it meets the following conditions: + // - it doesn't have any sideeffects + // - it doesn't clobber memory + // - it doesn't return a value by-reference + // It can be marked readnone if it doesn't have any input memory constraints + // in addition to meeting the conditions listed above. + bool readOnly = true, readNone = true; + + if (s.getNumInputs() != 0 || s.getNumOutputs() != 0) { + assert(!cir::MissingFeatures::asmInputOperands()); + assert(!cir::MissingFeatures::asmOutputOperands()); + cgm.errorNYI(s.getAsmLoc(), "asm with operands"); + } + + bool hasUnwindClobber = false; + collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone); + + llvm::SmallVector<mlir::ValueRange, 8> operands; + mlir::Type resultType; + + bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0; + + cir::InlineAsmOp ia = builder.create<cir::InlineAsmOp>( + getLoc(s.getAsmLoc()), resultType, operands, asmString, constraints, + hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr()); + + if (false /*IsGCCAsmGoto*/) { + assert(!cir::MissingFeatures::asmGoto()); + } else if (hasUnwindClobber) { + assert(!cir::MissingFeatures::asmUnwindClobber()); + } else { + assert(!cir::MissingFeatures::asmMemoryEffects()); + } + + llvm::SmallVector<mlir::Attribute> operandAttrs; + ia.setOperandAttrsAttr(builder.getArrayAttr(operandAttrs)); + + return mlir::success(); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index c3e77c99cca35..2ae217aa1cdb2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -942,6 +942,8 @@ class CIRGenFunction : public CIRGenTypeCache { Address emitArrayToPointerDecay(const Expr *array); + mlir::LogicalResult emitAsmStmt(const clang::AsmStmt &s); + RValue emitAtomicExpr(AtomicExpr *e); void emitAtomicInit(Expr *init, LValue dest); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 283b76a0dd16e..06cc3e09e416b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -102,6 +102,7 @@ class CIRGenModule : public CIRGenTypeCache { clang::ASTContext &getASTContext() const { return astContext; } const clang::TargetInfo &getTarget() const { return target; } const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; } + clang::DiagnosticsEngine &getDiags() const { return diags; } CIRGenTypes &getTypes() { return genTypes; } const clang::LangOptions &getLangOpts() const { return langOpts; } diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index d1e4a14824011..a0c69f34c74f9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -132,6 +132,9 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s, return emitOpenACCCacheConstruct(cast<OpenACCCacheConstruct>(*s)); case Stmt::OpenACCAtomicConstructClass: return emitOpenACCAtomicConstruct(cast<OpenACCAtomicConstruct>(*s)); + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + return emitAsmStmt(cast<AsmStmt>(*s)); case Stmt::OMPScopeDirectiveClass: case Stmt::OMPErrorDirectiveClass: case Stmt::LabelStmtClass: @@ -145,8 +148,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s, case Stmt::CoreturnStmtClass: case Stmt::CXXTryStmtClass: case Stmt::IndirectGotoStmtClass: - case Stmt::GCCAsmStmtClass: - case Stmt::MSAsmStmtClass: case Stmt::OMPParallelDirectiveClass: case Stmt::OMPTaskwaitDirectiveClass: case Stmt::OMPTaskyieldDirectiveClass: diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 12cea944eb2f3..7366446a33c6e 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -8,6 +8,7 @@ get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) add_clang_library(clangCIR CIRGenerator.cpp + CIRGenAsm.cpp CIRGenAtomic.cpp CIRGenBuilder.cpp CIRGenCall.cpp diff --git a/clang/test/CIR/CodeGen/inline-asm.c b/clang/test/CIR/CodeGen/inline-asm.c new file mode 100644 index 0000000000000..73b2c9aa0a0eb --- /dev/null +++ b/clang/test/CIR/CodeGen/inline-asm.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM + +void f1() { + // CIR: cir.asm(x86_att, + // CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects + // LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() + __asm__ volatile("" : : : ); +} + +void f2() { + // CIR: cir.asm(x86_att, + // CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects + // LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() + __asm__ volatile("nop" : : : ); +} >From 5328c79e2a64d47cccba7f4aa04c52a1c026be66 Mon Sep 17 00:00:00 2001 From: Iris Shi <0...@owo.li> Date: Sun, 17 Aug 2025 17:07:59 +0800 Subject: [PATCH 2/2] Address comments --- clang/lib/CIR/CodeGen/CIRGenAsm.cpp | 26 +++++++++++++------------- clang/test/CIR/CodeGen/inline-asm.c | 6 ++++++ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp index fdf59f071335b..17dffb3515d2a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAsm.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAsm.cpp @@ -10,11 +10,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/DiagnosticSema.h" -#include "llvm/ADT/StringExtras.h" - #include "CIRGenFunction.h" -#include "TargetInfo.h" #include "clang/CIR/MissingFeatures.h" using namespace clang; @@ -39,20 +35,18 @@ static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, // Clobbers for (unsigned i = 0, e = s.getNumClobbers(); i != e; i++) { - std::string clobberStr = s.getClobber(i); - StringRef clobber{clobberStr}; - if (clobber == "memory") + std::string clobber = s.getClobber(i); + if (clobber == "memory") { readOnly = readNone = false; - else if (clobber == "unwind") { + } else if (clobber == "unwind") { hasUnwindClobber = true; continue; } else if (clobber != "cc") { clobber = cgf.getTarget().getNormalizedGCCRegisterName(clobber); if (cgm.getCodeGenOpts().StackClashProtector && - cgf.getTarget().isSPRegName(clobber)) { + cgf.getTarget().isSPRegName(clobber)) cgm.getDiags().Report(s.getAsmLoc(), diag::warn_stack_clash_protection_inline_asm); - } } if (isa<MSAsmStmt>(&s)) { @@ -60,7 +54,7 @@ static void collectClobbers(const CIRGenFunction &cgf, const AsmStmt &s, if (constraints.find("=&A") != std::string::npos) continue; std::string::size_type position1 = - constraints.find("={" + clobber.str() + "}"); + constraints.find("={" + clobber + "}"); if (position1 != std::string::npos) { constraints.insert(position1 + 1, "&"); continue; @@ -93,7 +87,12 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) { // Assemble the final asm string. std::string asmString = s.generateAsmString(getContext()); + bool isGCCAsmGoto = false; + std::string constraints; + std::vector<mlir::Value> outArgs; + std::vector<mlir::Value> inArgs; + std::vector<mlir::Value> inOutArgs; // An inline asm can be marked readonly if it meets the following conditions: // - it doesn't have any sideeffects @@ -112,7 +111,8 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) { bool hasUnwindClobber = false; collectClobbers(*this, s, constraints, hasUnwindClobber, readOnly, readNone); - llvm::SmallVector<mlir::ValueRange, 8> operands; + std::array<mlir::ValueRange, 3> operands = {outArgs, inArgs, inOutArgs}; + mlir::Type resultType; bool hasSideEffect = s.isVolatile() || s.getNumOutputs() == 0; @@ -121,7 +121,7 @@ mlir::LogicalResult CIRGenFunction::emitAsmStmt(const AsmStmt &s) { getLoc(s.getAsmLoc()), resultType, operands, asmString, constraints, hasSideEffect, inferFlavor(cgm, s), mlir::ArrayAttr()); - if (false /*IsGCCAsmGoto*/) { + if (isGCCAsmGoto) { assert(!cir::MissingFeatures::asmGoto()); } else if (hasUnwindClobber) { assert(!cir::MissingFeatures::asmUnwindClobber()); diff --git a/clang/test/CIR/CodeGen/inline-asm.c b/clang/test/CIR/CodeGen/inline-asm.c index 73b2c9aa0a0eb..fc959f9326876 100644 --- a/clang/test/CIR/CodeGen/inline-asm.c +++ b/clang/test/CIR/CodeGen/inline-asm.c @@ -5,6 +5,9 @@ void f1() { // CIR: cir.asm(x86_att, + // CIR: out = [], + // CIR: in = [], + // CIR: in_out = [], // CIR: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects // LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() __asm__ volatile("" : : : ); @@ -12,6 +15,9 @@ void f1() { void f2() { // CIR: cir.asm(x86_att, + // CIR: out = [], + // CIR: in = [], + // CIR: in_out = [], // CIR: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects // LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"() __asm__ volatile("nop" : : : ); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits