[llvm-branch-commits] [clang] [CIR] Implement codegen for inline assembly without input and output operands (PR #153546)
Iris Shi via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 14 02:02:27 PDT 2025
https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/153546
>From 1022c8f98362fb52bb35ad0a3d426864e00dd2a4 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Thu, 14 Aug 2025 15:12:18 +0800
Subject: [PATCH] [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 805c43e6d5054..17dc59a6cd01f 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -179,7 +179,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 2333ec3209c3b..7af08c902d2e0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -926,6 +926,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 5538aba57014c..bf42f14eeb728 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 332babdf43772..7a0c56c1618bf 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -130,6 +130,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:
@@ -143,8 +146,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" : : : );
+}
More information about the llvm-branch-commits
mailing list