From e01ecbf2742f8e3fe84b2093f6e3a4ca188663a3 Mon Sep 17 00:00:00 2001 From: wizardengineer Date: Wed, 19 Nov 2025 20:46:55 -0500 Subject: [PATCH] [CIR] Add support for FileScopeAsm --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 12 +++++ clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 5 +- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 32 ++++++++++++ clang/lib/CIR/CodeGen/CIRGenModule.h | 16 ++++++ .../Lowering/DirectToLLVM/LowerToLLVMIR.cpp | 12 +++++ clang/test/CIR/CodeGen/file-scope-asm.c | 51 +++++++++++++++++++ 6 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGen/file-scope-asm.c diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index c3281e30506c..14bf50aeeb43 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -221,6 +221,18 @@ def CIR_TypeSizeInfoAttr : CIR_Attr<"TypeSizeInfo", "type_size_info"> { }]; } +//===----------------------------------------------------------------------===// +// FileScopeAsm +//===----------------------------------------------------------------------===// + +def CIR_ModuleAsmAttr : CIR_Attr<"ModuleAsm", "module_asm"> { + let summary = "Module-level inline assembly"; + let description = [{ + Stores file-scope inline assembly strings. + }]; + let parameters = (ins "mlir::ArrayAttr":$asm_strings); + let assemblyFormat = [{ `<` $asm_strings `>`}]; +} //===----------------------------------------------------------------------===// // BoolAttr diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index a394d355a910..895911cad5c6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -832,7 +832,10 @@ void CIRGenFunction::emitDecl(const Decl &D) { case Decl::LinkageSpec: case Decl::Export: case Decl::ObjCPropertyImpl: - case Decl::FileScopeAsm: + case Decl::FileScopeAsm: { + CGM.buildFileScopeAsm(cast(&D)); + return; + } case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 552371a0b054..2a0acb381b5d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -31,6 +31,7 @@ #include "mlir/IR/OperationSupport.h" #include "mlir/IR/SymbolTable.h" #include "mlir/IR/Verifier.h" +#include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/Basic/Cuda.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" @@ -2072,6 +2073,9 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { emitTopLevelDecl(childDecl); break; } + case Decl::FileScopeAsm: + buildFileScopeAsm(cast(decl)); + break; case Decl::PragmaComment: { const auto *PCD = cast(decl); switch (PCD->getCommentKind()) { @@ -3776,6 +3780,9 @@ void CIRGenModule::Release() { if (getTriple().isPPC() && !MissingFeatures::mustTailCallUndefinedGlobals()) { llvm_unreachable("NYI"); } + + // Finalize module attributes (including inline assembly) + finalizeModuleAttributes(); } namespace { @@ -4430,3 +4437,28 @@ cir::LabelOp CIRGenModule::lookupBlockAddressInfo(cir::BlockAddrInfoAttr blockInfo) { return blockAddressInfoToLabel.lookup(blockInfo); } + +void CIRGenModule::buildFileScopeAsm(const FileScopeAsmDecl *D) { + // Get assembly string from declaration + appendModuleInlineAsm(D->getAsmString()); +} + +void CIRGenModule::finalizeModuleAttributes() { + if (moduleAsm.empty()) + return; + + // Build array of string attributes + llvm::SmallVector asmStrings; + for (const auto &asmStr : moduleAsm) { + asmStrings.push_back(builder.getStringAttr(asmStr)); + } + + // Create array attribute + mlir::ArrayAttr asmArray = builder.getArrayAttr(asmStrings); + + // Create ModuleAsmAttr + auto moduleAsmAttr = cir::ModuleAsmAttr::get(builder.getContext(), asmArray); + + // Set as module attribute + theModule->setAttr("cir.module_asm", moduleAsmAttr); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 5c505cddf723..005489b09e57 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -23,6 +23,7 @@ #include "CIRGenTypes.h" #include "CIRGenVTables.h" #include "CIRGenValue.h" +#include "clang/AST/Decl.h" #include "clang/CIR/MissingFeatures.h" #include "clang/AST/ASTContext.h" @@ -154,6 +155,8 @@ class CIRGenModule : public CIRGenTypeCache { llvm::DenseMap materializedGlobalTemporaryMap; + llvm::SmallVector moduleAsm; + public: mlir::ModuleOp getModule() const { return theModule; } CIRGenBuilderTy &getBuilder() { return builder; } @@ -958,6 +961,11 @@ class CIRGenModule : public CIRGenTypeCache { /// one of them. cir::AnnotationAttr emitAnnotateAttr(const clang::AnnotateAttr *aa); + /// Process file-scope inline assembly (e.g., `asm(".text");` at global + /// scope). Collects assembly strings into moduleAsm vector for later + /// finalization. + void buildFileScopeAsm(const FileScopeAsmDecl *D); + private: // An ordered map of canonical GlobalDecls to their mangled names. llvm::MapVector MangledDeclNames; @@ -989,6 +997,14 @@ class CIRGenModule : public CIRGenTypeCache { /// Add global annotations for a global value. /// Those annotations are emitted during lowering to the LLVM code. void addGlobalAnnotations(const ValueDecl *d, mlir::Operation *gv); + + /// Append module-level inline assembly + void appendModuleInlineAsm(llvm::StringRef Asm) { + moduleAsm.push_back(Asm.str()); + } + + /// Finalize module attribute (call at the end of codegen) + void finalizeModuleAttributes(); }; } // namespace clang::CIRGen diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp index 33650a77e36c..1c3db4cb7766 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/Attributes.h" #include "mlir/IR/DialectRegistry.h" #include "mlir/Target/LLVMIR/LLVMTranslationInterface.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" @@ -86,6 +87,17 @@ class CIRDialectLLVMIRTranslationInterface mlir::dyn_cast(attribute.getValue())) llvmModule->setUwtable(convertUWTableKind(uwTableAttr.getValue())); + // Handle module-level inline assembly + if (auto moduleAsmAttr = + mlir::dyn_cast(attribute.getValue())) { + mlir::ArrayAttr asmStrings = moduleAsmAttr.getAsmStrings(); + for (mlir::Attribute attr : asmStrings) { + if (auto strAttr = mlir::dyn_cast(attr)) { + llvmModule->appendModuleInlineAsm(strAttr.getValue()); + } + } + } + // Drop ammended CIR attribute from LLVM op. module->removeAttr(attribute.getName()); } diff --git a/clang/test/CIR/CodeGen/file-scope-asm.c b/clang/test/CIR/CodeGen/file-scope-asm.c new file mode 100644 index 000000000000..ee2788e237db --- /dev/null +++ b/clang/test/CIR/CodeGen/file-scope-asm.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \ +// RUN: -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 \ +// RUN: -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM + +// Test basic file-scope assembly +asm(".section .text"); +asm(".global my_func"); +asm("my_func: ret"); + +// Test file-scope assembly with functions +int foo() { + return 42; +} + +asm(".data"); +asm(".align 8"); + +int bar() { + return 24; +} + +// Test file-scope assembly at end of file +asm(".section .rodata"); +asm(".string \"hello\""); + +int main() { + return foo() + bar(); +} + +// CIR: cir.module_asm = #cir.module_asm<[".section .text", ".global my_func", "my_func: ret", ".data", ".align 8", ".section .rodata", ".string {{\\22}}hello{{\\22}}" + +// CIR: cir.func {{.*}}@foo +// CIR: cir.func {{.*}}@bar +// CIR: cir.func {{.*}}@main + +// LLVM: module asm ".section .text" +// LLVM: module asm ".global my_func" +// LLVM: module asm "my_func: ret" +// LLVM: module asm ".data" +// LLVM: module asm ".align 8" +// LLVM: module asm ".section .rodata" +// LLVM: module asm ".string {{\\22}}hello{{\\22}}" + +// LLVM: define{{.*}} i32 @foo() +// LLVM: define{{.*}} i32 @bar() +// LLVM: define{{.*}} i32 @main() +