Skip to content

[CIR] Add additional frontend actions #127249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 19, 2025
Merged

Conversation

andykaylor
Copy link
Contributor

@andykaylor andykaylor commented Feb 14, 2025

Add frontend actions to support emitting assembly, bitcode, and object files when compiling with ClangIR. This change also correctly sets and propagates the target triple in the MLIR and LLVM modules, which was a necessary prerequisite for emitting assembly and object files.

Add frontend actions to support emitting assembly, bitcode, and
object files when compiling with ClangIR.
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Feb 14, 2025
@llvmbot
Copy link
Member

llvmbot commented Feb 14, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clangir

Author: Andy Kaylor (andykaylor)

Changes

Add frontend actions to support emitting assembly, bitcode, and object files when compiling with ClangIR.


Full diff: https://github.com/llvm/llvm-project/pull/127249.diff

8 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+2)
  • (modified) clang/include/clang/CIR/FrontendAction/CIRGenAction.h (+24)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+3)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.h (+4)
  • (modified) clang/lib/CIR/FrontendAction/CIRGenAction.cpp (+28-1)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+11)
  • (modified) clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+18-3)
  • (added) clang/test/CIR/emit-actions.cpp (+21)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 305a06427ed0e..73759cfa9c3c9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -28,6 +28,8 @@ def CIR_Dialect : Dialect {
   let useDefaultTypePrinterParser = 0;
 
   let extraClassDeclaration = [{
+    static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
+
     void registerAttributes();
     void registerTypes();
 
diff --git a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
index 5f9110bc83b89..99495f4718c5f 100644
--- a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
+++ b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
@@ -25,8 +25,11 @@ class CIRGenConsumer;
 class CIRGenAction : public clang::ASTFrontendAction {
 public:
   enum class OutputType {
+    EmitAssembly,
     EmitCIR,
     EmitLLVM,
+    EmitBC,
+    EmitObj,
   };
 
 private:
@@ -63,6 +66,27 @@ class EmitLLVMAction : public CIRGenAction {
   EmitLLVMAction(mlir::MLIRContext *MLIRCtx = nullptr);
 };
 
+class EmitBCAction : public CIRGenAction {
+  virtual void anchor();
+
+public:
+  EmitBCAction(mlir::MLIRContext *MLIRCtx = nullptr);
+};
+
+class EmitAssemblyAction : public CIRGenAction {
+  virtual void anchor();
+
+public:
+  EmitAssemblyAction(mlir::MLIRContext *MLIRCtx = nullptr);
+};
+
+class EmitObjAction : public CIRGenAction {
+  virtual void anchor();
+
+public:
+  EmitObjAction(mlir::MLIRContext *MLIRCtx = nullptr);
+};
+
 } // namespace cir
 
 #endif
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 2615ae382cb8b..cbecdf925aa5d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -52,6 +52,9 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
   DoubleTy = cir::DoubleType::get(&getMLIRContext());
   FP80Ty = cir::FP80Type::get(&getMLIRContext());
   FP128Ty = cir::FP128Type::get(&getMLIRContext());
+
+  theModule->setAttr(cir::CIRDialect::getTripleAttrName(),
+                     builder.getStringAttr(getTriple().str()));
 }
 
 mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 1c7ed63773900..29bb4036218e4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -21,7 +21,9 @@
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/MLIRContext.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/Triple.h"
 
 namespace clang {
 class ASTContext;
@@ -88,6 +90,8 @@ class CIRGenModule : public CIRGenTypeCache {
   void emitGlobalVarDefinition(const clang::VarDecl *vd,
                                bool isTentative = false);
 
+  const llvm::Triple &getTriple() const { return target.getTriple(); }
+
   /// Helpers to emit "not yet implemented" error diagnostics
   DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
 
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index eab6958ac8f6d..0f686a36b982b 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -27,8 +27,14 @@ getBackendActionFromOutputType(CIRGenAction::OutputType Action) {
     assert(false &&
            "Unsupported output type for getBackendActionFromOutputType!");
     break; // Unreachable, but fall through to report that
+  case CIRGenAction::OutputType::EmitAssembly:
+    return BackendAction::Backend_EmitAssembly;
+  case CIRGenAction::OutputType::EmitBC:
+    return BackendAction::Backend_EmitBC;
   case CIRGenAction::OutputType::EmitLLVM:
     return BackendAction::Backend_EmitLL;
+  case CIRGenAction::OutputType::EmitObj:
+    return BackendAction::Backend_EmitObj;
   }
   // We should only get here if a non-enum value is passed in or we went through
   // the assert(false) case above
@@ -84,7 +90,10 @@ class CIRGenConsumer : public clang::ASTConsumer {
         MlirModule->print(*OutputStream, Flags);
       }
       break;
-    case CIRGenAction::OutputType::EmitLLVM: {
+    case CIRGenAction::OutputType::EmitLLVM:
+    case CIRGenAction::OutputType::EmitBC:
+    case CIRGenAction::OutputType::EmitObj:
+    case CIRGenAction::OutputType::EmitAssembly: {
       llvm::LLVMContext LLVMCtx;
       std::unique_ptr<llvm::Module> LLVMModule =
           lowerFromCIRToLLVMIR(MlirModule, LLVMCtx);
@@ -111,10 +120,16 @@ static std::unique_ptr<raw_pwrite_stream>
 getOutputStream(CompilerInstance &CI, StringRef InFile,
                 CIRGenAction::OutputType Action) {
   switch (Action) {
+  case CIRGenAction::OutputType::EmitAssembly:
+    return CI.createDefaultOutputFile(false, InFile, "s");
   case CIRGenAction::OutputType::EmitCIR:
     return CI.createDefaultOutputFile(false, InFile, "cir");
   case CIRGenAction::OutputType::EmitLLVM:
     return CI.createDefaultOutputFile(false, InFile, "ll");
+  case CIRGenAction::OutputType::EmitBC:
+    return CI.createDefaultOutputFile(true, InFile, "bc");
+  case CIRGenAction::OutputType::EmitObj:
+    return CI.createDefaultOutputFile(true, InFile, "o");
   }
   llvm_unreachable("Invalid CIRGenAction::OutputType");
 }
@@ -132,6 +147,10 @@ CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   return Result;
 }
 
+void EmitAssemblyAction::anchor() {}
+EmitAssemblyAction::EmitAssemblyAction(mlir::MLIRContext *MLIRCtx)
+    : CIRGenAction(OutputType::EmitAssembly, MLIRCtx) {}
+
 void EmitCIRAction::anchor() {}
 EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
     : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
@@ -139,3 +158,11 @@ EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
 void EmitLLVMAction::anchor() {}
 EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx)
     : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {}
+
+void EmitBCAction::anchor() {}
+EmitBCAction::EmitBCAction(mlir::MLIRContext *MLIRCtx)
+    : CIRGenAction(OutputType::EmitBC, MLIRCtx) {}
+
+void EmitObjAction::anchor() {}
+EmitObjAction::EmitObjAction(mlir::MLIRContext *MLIRCtx)
+    : CIRGenAction(OutputType::EmitObj, MLIRCtx) {}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index d60a6b38b0c12..5915a9517b028 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -114,6 +114,8 @@ struct ConvertCIRToLLVMPass
   }
   void runOnOperation() final;
 
+  void processCIRAttrs(mlir::ModuleOp module);
+
   StringRef getDescription() const override {
     return "Convert the prepared CIR dialect module to LLVM dialect";
   }
@@ -271,6 +273,13 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
   });
 }
 
+void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
+  // Lower the module attributes to LLVM equivalents.
+  if (auto tripleAttr = module->getAttr(cir::CIRDialect::getTripleAttrName()))
+    module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
+                    tripleAttr);
+}
+
 void ConvertCIRToLLVMPass::runOnOperation() {
   llvm::TimeTraceScope scope("Convert CIR to LLVM Pass");
 
@@ -283,6 +292,8 @@ void ConvertCIRToLLVMPass::runOnOperation() {
 
   patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
 
+  processCIRAttrs(module);
+
   mlir::ConversionTarget target(getContext());
   target.addLegalOp<mlir::ModuleOp>();
   target.addLegalDialect<mlir::LLVM::LLVMDialect>();
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index c8d004163b96d..bb3bb0aac78bf 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -62,8 +62,18 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
     return std::make_unique<DumpCompilerOptionsAction>();
   case DumpRawTokens:          return std::make_unique<DumpRawTokensAction>();
   case DumpTokens:             return std::make_unique<DumpTokensAction>();
-  case EmitAssembly:           return std::make_unique<EmitAssemblyAction>();
-  case EmitBC:                 return std::make_unique<EmitBCAction>();
+  case EmitAssembly:
+#if CLANG_ENABLE_CIR
+    if (UseCIR)
+      return std::make_unique<cir::EmitAssemblyAction>();
+#endif
+    return std::make_unique<EmitAssemblyAction>();
+  case EmitBC:
+#if CLANG_ENABLE_CIR
+    if (UseCIR)
+      return std::make_unique<cir::EmitBCAction>();
+#endif
+    return std::make_unique<EmitBCAction>();
   case EmitCIR:
 #if CLANG_ENABLE_CIR
     return std::make_unique<cir::EmitCIRAction>();
@@ -80,7 +90,12 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
   }
   case EmitLLVMOnly:           return std::make_unique<EmitLLVMOnlyAction>();
   case EmitCodeGenOnly:        return std::make_unique<EmitCodeGenOnlyAction>();
-  case EmitObj:                return std::make_unique<EmitObjAction>();
+  case EmitObj:
+#if CLANG_ENABLE_CIR
+    if (UseCIR)
+      return std::make_unique<cir::EmitObjAction>();
+#endif
+    return std::make_unique<EmitObjAction>();
   case ExtractAPI:
     return std::make_unique<ExtractAPIAction>();
   case FixIt:                  return std::make_unique<FixItAction>();
diff --git a/clang/test/CIR/emit-actions.cpp b/clang/test/CIR/emit-actions.cpp
new file mode 100644
index 0000000000000..94ddf23b34753
--- /dev/null
+++ b/clang/test/CIR/emit-actions.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -S %s -o - | FileCheck %s -check-prefix=ASM
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm-bc %s -o %t.bc
+// RUN: llvm-dis %t.bc -o - | FileCheck %s -check-prefix=BC
+
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-obj %s -o %t.o
+// RUN: llvm-objdump -t %t.o | FileCheck %s -check-prefix=OBJ
+
+// TODO: Make this test target-independent
+// REQUIRES: x86-registered-target
+
+int x = 1;
+
+// BC: @x = dso_local global i32 1
+
+// ASM: x:
+// ASM: .long   1
+// ASM: .size   x, 4
+
+// OBJ: .data
+// OBJ-SAME: x

@andykaylor andykaylor changed the title [CIR] Add addition frontend actions [CIR] Add additional frontend actions Feb 18, 2025
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please improve the commit message to mention the addition of the triple info/spreading of that as well, else LGTM.

@@ -52,6 +52,9 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
DoubleTy = cir::DoubleType::get(&getMLIRContext());
FP80Ty = cir::FP80Type::get(&getMLIRContext());
FP128Ty = cir::FP128Type::get(&getMLIRContext());

theModule->setAttr(cir::CIRDialect::getTripleAttrName(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mention that this is ALSO setting the module 'triple' correctly in the commit message?

@andykaylor andykaylor merged commit 75ea7ae into llvm:main Feb 19, 2025
11 checks passed
@andykaylor andykaylor deleted the cir-gen-obj branch March 4, 2025 22:52
bcardosolopes pushed a commit to bcardosolopes/llvm-project that referenced this pull request Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants