Skip to content

Conversation

@lanza
Copy link
Member

@lanza lanza commented Oct 9, 2024

Build out the necessary infrastructure for the main entry point into
ClangIR generation -- CIRGenModule. A set of boilerplate classes exist
to facilitate this -- CIRGenerator, CIRGenAction, EmitCIRAction and
CIRGenConsumer. These all mirror the corresponding types from LLVM
generation by Clang's CodeGen.

The main entry point to CIR generation is
CIRGenModule::buildTopLevelDecl. It is currently just an empty
function. We've added a test to ensure that the pipeline reaches this
point and doesn't fail, but does nothing else. This will be removed in
one of the subsequent patches that'll add basic cir.func emission.

This patch also re-adds -emit-cir to the driver. lib/Driver/Driver.cpp
requires that a driver flag exists to facilirate the selection of the
right actions for the driver to create. Without a driver flag you get
the standard behaviors of -S, -c, etc. If we want to emit CIR IR
and, eventually, bytecode we'll need a driver flag to force this. This
is why -emit-llvm is a driver flag. Notably, -emit-llvm-bc as a cc1
flag doesn't ever do the right thing. Without a driver flag it is
incorrectly ignored and an executable is emitted. With -S a file named
something.s is emitted which actually contains bitcode.

Created using spr 1.3.5
@lanza lanza requested a review from bcardosolopes as a code owner October 9, 2024 18:14
@lanza lanza requested a review from MaskRay October 9, 2024 18:14
@lanza lanza closed this Oct 9, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' ClangIR Anything related to the ClangIR project labels Oct 9, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-driver

Author: Nathan Lanza (lanza)

Changes

Build out the necessary infrastructure for the main entry point into
ClangIR generation -- CIRGenModule. A set of boilerplate classes exist
to facilitate this -- CIRGenerator, CIRGenAction, EmitCIRAction and
CIRGenConsumer. These all mirror the corresponding types from LLVM
generation by Clang's CodeGen.

The main entry point to CIR generation is
CIRGenModule::buildTopLevelDecl. It is currently just an empty
function. We've added a test to ensure that the pipeline reaches this
point and doesn't fail, but does nothing else. This will be removed in
one of the subsequent patches that'll add basic cir.func emission.

This patch also re-adds -emit-cir to the driver. lib/Driver/Driver.cpp
requires that a driver flag exists to facilirate the selection of the
right actions for the driver to create. Without a driver flag you get
the standard behaviors of -S, -c, etc. If we want to emit CIR IR
and, eventually, bytecode we'll need a driver flag to force this. This
is why -emit-llvm is a driver flag. Notably, -emit-llvm-bc as a cc1
flag doesn't ever do the right thing. Without a driver flag it is
incorrectly ignored and an executable is emitted. With -S a file named
something.s is emitted which actually contains bitcode.


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

16 Files Affected:

  • (added) clang/include/clang/CIR/CIRGenerator.h (+60)
  • (added) clang/include/clang/CIR/FrontendAction/CIRGenAction.h (+60)
  • (modified) clang/include/clang/Driver/Options.td (+1-1)
  • (modified) clang/lib/CIR/CMakeLists.txt (+2)
  • (added) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+32)
  • (added) clang/lib/CIR/CodeGen/CIRGenModule.h (+62)
  • (added) clang/lib/CIR/CodeGen/CIRGenTypeCache.h (+27)
  • (added) clang/lib/CIR/CodeGen/CIRGenerator.cpp (+43)
  • (added) clang/lib/CIR/CodeGen/CMakeLists.txt (+23)
  • (added) clang/lib/CIR/FrontendAction/CIRGenAction.cpp (+72)
  • (added) clang/lib/CIR/FrontendAction/CMakeLists.txt (+17)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+3)
  • (modified) clang/lib/FrontendTool/CMakeLists.txt (+15)
  • (modified) clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+16)
  • (added) clang/test/CIR/hello.c (+5)
  • (added) clang/test/CIR/lit.local.cfg (+2)
diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h
new file mode 100644
index 00000000000000..9a8930ac46ea9c
--- /dev/null
+++ b/clang/include/clang/CIR/CIRGenerator.h
@@ -0,0 +1,60 @@
+//===- CIRGenerator.h - CIR Generation from Clang AST ---------------------===//
+//
+// 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 declares a simple interface to perform CIR generation from Clang
+// AST
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_CIRGENERATOR_H
+#define LLVM_CLANG_CIR_CIRGENERATOR_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CodeGenOptions.h"
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#include <memory>
+
+namespace clang {
+class DeclGroupRef;
+class DiagnosticsEngine;
+} // namespace clang
+
+namespace mlir {
+class MLIRContext;
+} // namespace mlir
+namespace cir {
+class CIRGenModule;
+
+class CIRGenerator : public clang::ASTConsumer {
+  virtual void anchor();
+  clang::DiagnosticsEngine &diags;
+  clang::ASTContext *astCtx;
+  // Only used for debug info.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs;
+
+  const clang::CodeGenOptions &codeGenOpts;
+
+protected:
+  std::unique_ptr<mlir::MLIRContext> mlirCtx;
+  std::unique_ptr<CIRGenModule> cgm;
+
+public:
+  CIRGenerator(clang::DiagnosticsEngine &diags,
+               llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
+               const clang::CodeGenOptions &cgo);
+  ~CIRGenerator() override;
+  void Initialize(clang::ASTContext &astCtx) override;
+  bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
+};
+
+} // namespace cir
+
+#endif // LLVM_CLANG_CIR_CIRGENERATOR_H
diff --git a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
new file mode 100644
index 00000000000000..2ab612613b73da
--- /dev/null
+++ b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
@@ -0,0 +1,60 @@
+//===---- CIRGenAction.h - CIR Code Generation Frontend Action -*- C++ -*--===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_CIRGENACTION_H
+#define LLVM_CLANG_CIR_CIRGENACTION_H
+
+#include "clang/Frontend/FrontendAction.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/OwningOpRef.h"
+
+namespace mlir {
+class MLIRContext;
+class ModuleOp;
+} // namespace mlir
+
+namespace cir {
+class CIRGenConsumer;
+
+class CIRGenAction : public clang::ASTFrontendAction {
+public:
+  enum class OutputType {
+    EmitCIR,
+  };
+
+private:
+  friend class CIRGenConsumer;
+
+  mlir::OwningOpRef<mlir::ModuleOp> MLIRMod;
+
+  mlir::MLIRContext *MLIRCtx;
+
+protected:
+  CIRGenAction(OutputType Action, mlir::MLIRContext *MLIRCtx = nullptr);
+
+  std::unique_ptr<clang::ASTConsumer>
+  CreateASTConsumer(clang::CompilerInstance &CI,
+                    llvm::StringRef InFile) override;
+
+public:
+  ~CIRGenAction() override;
+
+  OutputType Action;
+};
+
+class EmitCIRAction : public CIRGenAction {
+  virtual void anchor();
+
+public:
+  EmitCIRAction(mlir::MLIRContext *MLIRCtx = nullptr);
+};
+
+} // namespace cir
+
+#endif
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 90f0c4f2df2130..9adc0b15f2ea82 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2996,7 +2996,7 @@ defm clangir : BoolFOption<"clangir",
   PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">,
   NegFlag<SetFalse, [], [ClangOption, CC1Option], "Use the AST -> LLVM pipeline to compile">,
   BothFlags<[], [ClangOption, CC1Option], "">>;
-def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>,
+def emit_cir : Flag<["-"], "emit-cir">, Visibility<[ClangOption, CC1Option]>,
   Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR">;
 /// ClangIR-specific options - END
 
diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt
index d2ff200e0da5f5..11cca734808dfa 100644
--- a/clang/lib/CIR/CMakeLists.txt
+++ b/clang/lib/CIR/CMakeLists.txt
@@ -2,3 +2,5 @@ include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
 include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
 
 add_subdirectory(Dialect)
+add_subdirectory(CodeGen)
+add_subdirectory(FrontendAction)
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
new file mode 100644
index 00000000000000..95e62326939fc2
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -0,0 +1,32 @@
+//===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===//
+//
+// 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 is the internal per-translation-unit state used for CIR translation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenModule.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/MLIRContext.h"
+
+using namespace cir;
+CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
+                           clang::ASTContext &astctx,
+                           const clang::CodeGenOptions &cgo,
+                           DiagnosticsEngine &diags)
+    : astCtx(astctx), langOpts(astctx.getLangOpts()),
+      theModule{mlir::ModuleOp::create(mlir::UnknownLoc())},
+      target(astCtx.getTargetInfo()) {}
+
+// Emit code for a single top level declaration.
+void CIRGenModule::buildTopLevelDecl(Decl *decl) {}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
new file mode 100644
index 00000000000000..ab2a1d8864659a
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -0,0 +1,62 @@
+//===--- CIRGenModule.h - Per-Module state for CIR gen ----------*- C++ -*-===//
+//
+// 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 is the internal per-translation-unit state used for CIR translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
+#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
+
+#include "CIRGenTypeCache.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/MLIRContext.h"
+
+namespace clang {
+class ASTContext;
+class CodeGenOptions;
+class Decl;
+class DiagnosticsEngine;
+class LangOptions;
+class TargetInfo;
+} // namespace clang
+
+using namespace clang;
+namespace cir {
+
+/// This class organizes the cross-function state that is used while generating
+/// CIR code.
+class CIRGenModule : public CIRGenTypeCache {
+  CIRGenModule(CIRGenModule &) = delete;
+  CIRGenModule &operator=(CIRGenModule &) = delete;
+
+public:
+  CIRGenModule(mlir::MLIRContext &context, clang::ASTContext &astctx,
+               const clang::CodeGenOptions &cgo,
+               clang::DiagnosticsEngine &diags);
+
+  ~CIRGenModule() = default;
+
+private:
+  /// Hold Clang AST information.
+  clang::ASTContext &astCtx;
+
+  const clang::LangOptions &langOpts;
+
+  /// A "module" matches a c/cpp source file: containing a list of functions.
+  mlir::ModuleOp theModule;
+
+  const clang::TargetInfo &target;
+
+public:
+  void buildTopLevelDecl(clang::Decl *decl);
+};
+} // namespace cir
+
+#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
new file mode 100644
index 00000000000000..6478e0a0780994
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -0,0 +1,27 @@
+//===--- CIRGenTypeCache.h - Commonly used LLVM types and info -*- C++ --*-===//
+//
+// 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 structure provides a set of common types useful during CIR emission.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
+#define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
+
+namespace cir {
+
+/// This structure provides a set of types that are commonly used
+/// during IR emission. It's initialized once in CodeGenModule's
+/// constructor and then copied around into new CIRGenFunction's.
+struct CIRGenTypeCache {
+  CIRGenTypeCache() = default;
+};
+
+} // namespace cir
+
+#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENTYPECACHE_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
new file mode 100644
index 00000000000000..159355a99ece80
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -0,0 +1,43 @@
+//===--- CIRGenerator.cpp - Emit CIR from ASTs ----------------------------===//
+//
+// 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 builds an AST and converts it to CIR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenModule.h"
+
+#include "clang/AST/DeclGroup.h"
+#include "clang/CIR/CIRGenerator.h"
+
+using namespace cir;
+using namespace clang;
+
+void CIRGenerator::anchor() {}
+
+CIRGenerator::CIRGenerator(clang::DiagnosticsEngine &diags,
+                           llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
+                           const CodeGenOptions &cgo)
+    : diags(diags), fs(std::move(vfs)), codeGenOpts{cgo} {}
+CIRGenerator::~CIRGenerator() = default;
+
+void CIRGenerator::Initialize(ASTContext &astCtx) {
+  using namespace llvm;
+
+  this->astCtx = &astCtx;
+
+  cgm = std::make_unique<CIRGenModule>(*mlirCtx, astCtx, codeGenOpts, diags);
+}
+
+bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
+
+  for (Decl *decl : group)
+    cgm->buildTopLevelDecl(decl);
+
+  return true;
+}
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
new file mode 100644
index 00000000000000..17a3aabfbd7f0e
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(
+  LLVM_LINK_COMPONENTS
+  Core
+  Support
+)
+
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_clang_library(clangCIR
+  CIRGenerator.cpp
+  CIRGenModule.cpp
+
+  DEPENDS
+  MLIRCIR
+  ${dialect_libs}
+
+  LINK_LIBS
+  clangAST
+  clangBasic
+  clangLex
+  ${dialect_libs}
+  MLIRCIR
+)
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
new file mode 100644
index 00000000000000..72b9fa0c13c595
--- /dev/null
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -0,0 +1,72 @@
+//===--- CIRGenAction.cpp - LLVM Code generation Frontend Action ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/FrontendAction/CIRGenAction.h"
+#include "clang/CIR/CIRGenerator.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/OwningOpRef.h"
+
+using namespace cir;
+using namespace clang;
+
+namespace cir {
+
+class CIRGenConsumer : public clang::ASTConsumer {
+
+  virtual void anchor();
+
+  std::unique_ptr<raw_pwrite_stream> OutputStream;
+
+  IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
+  std::unique_ptr<CIRGenerator> Gen;
+
+public:
+  CIRGenConsumer(CIRGenAction::OutputType Action,
+                 DiagnosticsEngine &DiagnosticsEngine,
+                 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+                 const HeaderSearchOptions &HeaderSearchOptions,
+                 const CodeGenOptions &CodeGenOptions,
+                 const TargetOptions &TargetOptions,
+                 const LangOptions &LangOptions,
+                 const FrontendOptions &FEOptions,
+                 std::unique_ptr<raw_pwrite_stream> OS)
+      : OutputStream(std::move(OS)), FS(VFS),
+        Gen(std::make_unique<CIRGenerator>(DiagnosticsEngine, std::move(VFS),
+                                           CodeGenOptions)) {}
+
+  bool HandleTopLevelDecl(DeclGroupRef D) override {
+    Gen->HandleTopLevelDecl(D);
+    return true;
+  }
+};
+} // namespace cir
+
+void CIRGenConsumer::anchor() {}
+
+CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
+    : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {}
+
+CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
+
+std::unique_ptr<ASTConsumer>
+CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+  std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
+
+  auto Result = std::make_unique<cir::CIRGenConsumer>(
+      Action, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
+      CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
+      CI.getLangOpts(), CI.getFrontendOpts(), std::move(Out));
+
+  return Result;
+}
+
+void EmitCIRAction::anchor() {}
+EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
+    : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt
new file mode 100644
index 00000000000000..b0616ab5d64b09
--- /dev/null
+++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS
+  Core
+  Support
+  )
+
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_clang_library(clangCIRFrontendAction
+  CIRGenAction.cpp
+
+  LINK_LIBS
+  clangAST
+  clangFrontend
+  clangCIR
+  MLIRCIR
+  MLIRIR
+  )
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 5b09f97c40b485..49b07322a21a52 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5139,6 +5139,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
   }
 
+  if (Args.hasArg(options::OPT_fclangir))
+    CmdArgs.push_back("-fclangir");
+
   if (IsOpenMPDevice) {
     // We have to pass the triple of the host if compiling for an OpenMP device.
     std::string NormalizedTriple =
diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt
index 51c379ade2704c..bfc7652b4c118f 100644
--- a/clang/lib/FrontendTool/CMakeLists.txt
+++ b/clang/lib/FrontendTool/CMakeLists.txt
@@ -12,6 +12,15 @@ set(link_libs
   clangRewriteFrontend
   )
 
+set(deps)
+
+if(CLANG_ENABLE_CIR)
+  list(APPEND link_libs
+    clangCIRFrontendAction
+    MLIRIR
+    )
+endif()
+
 if(CLANG_ENABLE_ARCMT)
   list(APPEND link_libs
     clangARCMigrate
@@ -29,7 +38,13 @@ add_clang_library(clangFrontendTool
 
   DEPENDS
   ClangDriverOptions
+  ${deps}
 
   LINK_LIBS
   ${link_libs}
   )
+
+if(CLANG_ENABLE_CIR)
+  target_include_directories(clangFrontendTool PRIVATE ${LLVM_MAIN_SRC_DIR}/../mlir/include)
+  target_include_directories(clangFrontendTool PRIVATE ${CMAKE_BINARY_DIR}/tools/mlir/include)
+endif()
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 7476b1076d1038..60fde03289cf35 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -31,6 +31,11 @@
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/ErrorHandling.h"
+
+#if CLANG_ENABLE_CIR
+#include "clang/CIR/FrontendAction/CIRGenAction.h"
+#endif
+
 using namespace clang;
 using namespace llvm::opt;
 
@@ -42,6 +47,13 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
   StringRef Action("unknown");
   (void)Action;
 
+  unsigned UseCIR = CI.getFrontendOpts().UseClangIRPipeline;
+  frontend::ActionKind Act = CI.getFrontendOpts().ProgramAction;
+  bool EmitsCIR = Act == EmitCIR;
+
+  if (!UseCIR && EmitsCIR)
+    llvm::report_fatal_error("-emit-cir and only valid when using -fclangir");
+
   switch (CI.getFrontendOpts().ProgramAction) {
   case ASTDeclList:            return std::make_unique<ASTDeclListAction>();
   case ASTDump:                return std::make_unique<ASTDumpAction>();
@@ -54,7 +66,11 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
   case EmitAssembly:           return std::make_unique<EmitAssemblyAction>();
   case EmitBC:                 return std::make_unique<EmitBCAction>();
   case EmitCIR:
+#if CLANG_ENABLE_CIR
+    return std::make_unique<::cir::EmitCIRAction>();
+#else
     llvm_unreachable("CIR suppport not built into clang");
+#endif
   case EmitHTML:               return std::make_unique<HTMLPrintAction>();
   case EmitLLVM:               return std::make_unique<EmitLLVMAction>();
   case EmitLLVMOnly:           return std::make_unique<EmitLLVMOnlyAction>();
diff --git a/clang/test/CIR/hello.c b/clang/test/CIR/hello.c
new file mode 100644
index 00000000000000..61f38d0a5bd01a
--- /dev/null
+++ b/clang/test/CIR/hello.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s | FileCheck --allow-empty %s
+
+// just confirm that we don't crash
+// CHECK-NOT: *
+void foo() {}
diff --git a/clang/test/CIR/lit.local.cfg b/clang/test/CIR/lit.local.cfg
new file mode 100644
index 00000000000000..6afd60f47bff90
--- /dev/null
+++ b/clang/test/CIR/lit.local.cfg
@@ -0,0 +1,2 @@
+if not config.root.clang_enable_cir:
+    config.unsupported = True

@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2024

@llvm/pr-subscribers-clangir

Author: Nathan Lanza (lanza)

Changes

Build out the necessary infrastructure for the main entry point into
ClangIR generation -- CIRGenModule. A set of boilerplate classes exist
to facilitate this -- CIRGenerator, CIRGenAction, EmitCIRAction and
CIRGenConsumer. These all mirror the corresponding types from LLVM
generation by Clang's CodeGen.

The main entry point to CIR generation is
CIRGenModule::buildTopLevelDecl. It is currently just an empty
function. We've added a test to ensure that the pipeline reaches this
point and doesn't fail, but does nothing else. This will be removed in
one of the subsequent patches that'll add basic cir.func emission.

This patch also re-adds -emit-cir to the driver. lib/Driver/Driver.cpp
requires that a driver flag exists to facilirate the selection of the
right actions for the driver to create. Without a driver flag you get
the standard behaviors of -S, -c, etc. If we want to emit CIR IR
and, eventually, bytecode we'll need a driver flag to force this. This
is why -emit-llvm is a driver flag. Notably, -emit-llvm-bc as a cc1
flag doesn't ever do the right thing. Without a driver flag it is
incorrectly ignored and an executable is emitted. With -S a file named
something.s is emitted which actually contains bitcode.


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

16 Files Affected:

  • (added) clang/include/clang/CIR/CIRGenerator.h (+60)
  • (added) clang/include/clang/CIR/FrontendAction/CIRGenAction.h (+60)
  • (modified) clang/include/clang/Driver/Options.td (+1-1)
  • (modified) clang/lib/CIR/CMakeLists.txt (+2)
  • (added) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+32)
  • (added) clang/lib/CIR/CodeGen/CIRGenModule.h (+62)
  • (added) clang/lib/CIR/CodeGen/CIRGenTypeCache.h (+27)
  • (added) clang/lib/CIR/CodeGen/CIRGenerator.cpp (+43)
  • (added) clang/lib/CIR/CodeGen/CMakeLists.txt (+23)
  • (added) clang/lib/CIR/FrontendAction/CIRGenAction.cpp (+72)
  • (added) clang/lib/CIR/FrontendAction/CMakeLists.txt (+17)
  • (modified) clang/lib/Driver/ToolChains/Clang.cpp (+3)
  • (modified) clang/lib/FrontendTool/CMakeLists.txt (+15)
  • (modified) clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (+16)
  • (added) clang/test/CIR/hello.c (+5)
  • (added) clang/test/CIR/lit.local.cfg (+2)
diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h
new file mode 100644
index 00000000000000..9a8930ac46ea9c
--- /dev/null
+++ b/clang/include/clang/CIR/CIRGenerator.h
@@ -0,0 +1,60 @@
+//===- CIRGenerator.h - CIR Generation from Clang AST ---------------------===//
+//
+// 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 declares a simple interface to perform CIR generation from Clang
+// AST
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_CIRGENERATOR_H
+#define LLVM_CLANG_CIR_CIRGENERATOR_H
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CodeGenOptions.h"
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+#include <memory>
+
+namespace clang {
+class DeclGroupRef;
+class DiagnosticsEngine;
+} // namespace clang
+
+namespace mlir {
+class MLIRContext;
+} // namespace mlir
+namespace cir {
+class CIRGenModule;
+
+class CIRGenerator : public clang::ASTConsumer {
+  virtual void anchor();
+  clang::DiagnosticsEngine &diags;
+  clang::ASTContext *astCtx;
+  // Only used for debug info.
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs;
+
+  const clang::CodeGenOptions &codeGenOpts;
+
+protected:
+  std::unique_ptr<mlir::MLIRContext> mlirCtx;
+  std::unique_ptr<CIRGenModule> cgm;
+
+public:
+  CIRGenerator(clang::DiagnosticsEngine &diags,
+               llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
+               const clang::CodeGenOptions &cgo);
+  ~CIRGenerator() override;
+  void Initialize(clang::ASTContext &astCtx) override;
+  bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
+};
+
+} // namespace cir
+
+#endif // LLVM_CLANG_CIR_CIRGENERATOR_H
diff --git a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
new file mode 100644
index 00000000000000..2ab612613b73da
--- /dev/null
+++ b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h
@@ -0,0 +1,60 @@
+//===---- CIRGenAction.h - CIR Code Generation Frontend Action -*- C++ -*--===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CIR_CIRGENACTION_H
+#define LLVM_CLANG_CIR_CIRGENACTION_H
+
+#include "clang/Frontend/FrontendAction.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/OwningOpRef.h"
+
+namespace mlir {
+class MLIRContext;
+class ModuleOp;
+} // namespace mlir
+
+namespace cir {
+class CIRGenConsumer;
+
+class CIRGenAction : public clang::ASTFrontendAction {
+public:
+  enum class OutputType {
+    EmitCIR,
+  };
+
+private:
+  friend class CIRGenConsumer;
+
+  mlir::OwningOpRef<mlir::ModuleOp> MLIRMod;
+
+  mlir::MLIRContext *MLIRCtx;
+
+protected:
+  CIRGenAction(OutputType Action, mlir::MLIRContext *MLIRCtx = nullptr);
+
+  std::unique_ptr<clang::ASTConsumer>
+  CreateASTConsumer(clang::CompilerInstance &CI,
+                    llvm::StringRef InFile) override;
+
+public:
+  ~CIRGenAction() override;
+
+  OutputType Action;
+};
+
+class EmitCIRAction : public CIRGenAction {
+  virtual void anchor();
+
+public:
+  EmitCIRAction(mlir::MLIRContext *MLIRCtx = nullptr);
+};
+
+} // namespace cir
+
+#endif
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 90f0c4f2df2130..9adc0b15f2ea82 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2996,7 +2996,7 @@ defm clangir : BoolFOption<"clangir",
   PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">,
   NegFlag<SetFalse, [], [ClangOption, CC1Option], "Use the AST -> LLVM pipeline to compile">,
   BothFlags<[], [ClangOption, CC1Option], "">>;
-def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>,
+def emit_cir : Flag<["-"], "emit-cir">, Visibility<[ClangOption, CC1Option]>,
   Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR">;
 /// ClangIR-specific options - END
 
diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt
index d2ff200e0da5f5..11cca734808dfa 100644
--- a/clang/lib/CIR/CMakeLists.txt
+++ b/clang/lib/CIR/CMakeLists.txt
@@ -2,3 +2,5 @@ include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
 include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
 
 add_subdirectory(Dialect)
+add_subdirectory(CodeGen)
+add_subdirectory(FrontendAction)
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
new file mode 100644
index 00000000000000..95e62326939fc2
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -0,0 +1,32 @@
+//===- CIRGenModule.cpp - Per-Module state for CIR generation -------------===//
+//
+// 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 is the internal per-translation-unit state used for CIR translation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenModule.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/MLIRContext.h"
+
+using namespace cir;
+CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
+                           clang::ASTContext &astctx,
+                           const clang::CodeGenOptions &cgo,
+                           DiagnosticsEngine &diags)
+    : astCtx(astctx), langOpts(astctx.getLangOpts()),
+      theModule{mlir::ModuleOp::create(mlir::UnknownLoc())},
+      target(astCtx.getTargetInfo()) {}
+
+// Emit code for a single top level declaration.
+void CIRGenModule::buildTopLevelDecl(Decl *decl) {}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
new file mode 100644
index 00000000000000..ab2a1d8864659a
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -0,0 +1,62 @@
+//===--- CIRGenModule.h - Per-Module state for CIR gen ----------*- C++ -*-===//
+//
+// 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 is the internal per-translation-unit state used for CIR translation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
+#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
+
+#include "CIRGenTypeCache.h"
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/MLIRContext.h"
+
+namespace clang {
+class ASTContext;
+class CodeGenOptions;
+class Decl;
+class DiagnosticsEngine;
+class LangOptions;
+class TargetInfo;
+} // namespace clang
+
+using namespace clang;
+namespace cir {
+
+/// This class organizes the cross-function state that is used while generating
+/// CIR code.
+class CIRGenModule : public CIRGenTypeCache {
+  CIRGenModule(CIRGenModule &) = delete;
+  CIRGenModule &operator=(CIRGenModule &) = delete;
+
+public:
+  CIRGenModule(mlir::MLIRContext &context, clang::ASTContext &astctx,
+               const clang::CodeGenOptions &cgo,
+               clang::DiagnosticsEngine &diags);
+
+  ~CIRGenModule() = default;
+
+private:
+  /// Hold Clang AST information.
+  clang::ASTContext &astCtx;
+
+  const clang::LangOptions &langOpts;
+
+  /// A "module" matches a c/cpp source file: containing a list of functions.
+  mlir::ModuleOp theModule;
+
+  const clang::TargetInfo &target;
+
+public:
+  void buildTopLevelDecl(clang::Decl *decl);
+};
+} // namespace cir
+
+#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypeCache.h b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
new file mode 100644
index 00000000000000..6478e0a0780994
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenTypeCache.h
@@ -0,0 +1,27 @@
+//===--- CIRGenTypeCache.h - Commonly used LLVM types and info -*- C++ --*-===//
+//
+// 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 structure provides a set of common types useful during CIR emission.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
+#define LLVM_CLANG_LIB_CIR_CIRGENTYPECACHE_H
+
+namespace cir {
+
+/// This structure provides a set of types that are commonly used
+/// during IR emission. It's initialized once in CodeGenModule's
+/// constructor and then copied around into new CIRGenFunction's.
+struct CIRGenTypeCache {
+  CIRGenTypeCache() = default;
+};
+
+} // namespace cir
+
+#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENTYPECACHE_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
new file mode 100644
index 00000000000000..159355a99ece80
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -0,0 +1,43 @@
+//===--- CIRGenerator.cpp - Emit CIR from ASTs ----------------------------===//
+//
+// 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 builds an AST and converts it to CIR.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CIRGenModule.h"
+
+#include "clang/AST/DeclGroup.h"
+#include "clang/CIR/CIRGenerator.h"
+
+using namespace cir;
+using namespace clang;
+
+void CIRGenerator::anchor() {}
+
+CIRGenerator::CIRGenerator(clang::DiagnosticsEngine &diags,
+                           llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
+                           const CodeGenOptions &cgo)
+    : diags(diags), fs(std::move(vfs)), codeGenOpts{cgo} {}
+CIRGenerator::~CIRGenerator() = default;
+
+void CIRGenerator::Initialize(ASTContext &astCtx) {
+  using namespace llvm;
+
+  this->astCtx = &astCtx;
+
+  cgm = std::make_unique<CIRGenModule>(*mlirCtx, astCtx, codeGenOpts, diags);
+}
+
+bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
+
+  for (Decl *decl : group)
+    cgm->buildTopLevelDecl(decl);
+
+  return true;
+}
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
new file mode 100644
index 00000000000000..17a3aabfbd7f0e
--- /dev/null
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(
+  LLVM_LINK_COMPONENTS
+  Core
+  Support
+)
+
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_clang_library(clangCIR
+  CIRGenerator.cpp
+  CIRGenModule.cpp
+
+  DEPENDS
+  MLIRCIR
+  ${dialect_libs}
+
+  LINK_LIBS
+  clangAST
+  clangBasic
+  clangLex
+  ${dialect_libs}
+  MLIRCIR
+)
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
new file mode 100644
index 00000000000000..72b9fa0c13c595
--- /dev/null
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -0,0 +1,72 @@
+//===--- CIRGenAction.cpp - LLVM Code generation Frontend Action ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/FrontendAction/CIRGenAction.h"
+#include "clang/CIR/CIRGenerator.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/OwningOpRef.h"
+
+using namespace cir;
+using namespace clang;
+
+namespace cir {
+
+class CIRGenConsumer : public clang::ASTConsumer {
+
+  virtual void anchor();
+
+  std::unique_ptr<raw_pwrite_stream> OutputStream;
+
+  IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
+  std::unique_ptr<CIRGenerator> Gen;
+
+public:
+  CIRGenConsumer(CIRGenAction::OutputType Action,
+                 DiagnosticsEngine &DiagnosticsEngine,
+                 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
+                 const HeaderSearchOptions &HeaderSearchOptions,
+                 const CodeGenOptions &CodeGenOptions,
+                 const TargetOptions &TargetOptions,
+                 const LangOptions &LangOptions,
+                 const FrontendOptions &FEOptions,
+                 std::unique_ptr<raw_pwrite_stream> OS)
+      : OutputStream(std::move(OS)), FS(VFS),
+        Gen(std::make_unique<CIRGenerator>(DiagnosticsEngine, std::move(VFS),
+                                           CodeGenOptions)) {}
+
+  bool HandleTopLevelDecl(DeclGroupRef D) override {
+    Gen->HandleTopLevelDecl(D);
+    return true;
+  }
+};
+} // namespace cir
+
+void CIRGenConsumer::anchor() {}
+
+CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
+    : MLIRCtx(MLIRCtx ? MLIRCtx : new mlir::MLIRContext), Action(Act) {}
+
+CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
+
+std::unique_ptr<ASTConsumer>
+CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+  std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
+
+  auto Result = std::make_unique<cir::CIRGenConsumer>(
+      Action, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
+      CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
+      CI.getLangOpts(), CI.getFrontendOpts(), std::move(Out));
+
+  return Result;
+}
+
+void EmitCIRAction::anchor() {}
+EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx)
+    : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {}
diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt
new file mode 100644
index 00000000000000..b0616ab5d64b09
--- /dev/null
+++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS
+  Core
+  Support
+  )
+
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+
+add_clang_library(clangCIRFrontendAction
+  CIRGenAction.cpp
+
+  LINK_LIBS
+  clangAST
+  clangFrontend
+  clangCIR
+  MLIRCIR
+  MLIRIR
+  )
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 5b09f97c40b485..49b07322a21a52 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5139,6 +5139,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
   }
 
+  if (Args.hasArg(options::OPT_fclangir))
+    CmdArgs.push_back("-fclangir");
+
   if (IsOpenMPDevice) {
     // We have to pass the triple of the host if compiling for an OpenMP device.
     std::string NormalizedTriple =
diff --git a/clang/lib/FrontendTool/CMakeLists.txt b/clang/lib/FrontendTool/CMakeLists.txt
index 51c379ade2704c..bfc7652b4c118f 100644
--- a/clang/lib/FrontendTool/CMakeLists.txt
+++ b/clang/lib/FrontendTool/CMakeLists.txt
@@ -12,6 +12,15 @@ set(link_libs
   clangRewriteFrontend
   )
 
+set(deps)
+
+if(CLANG_ENABLE_CIR)
+  list(APPEND link_libs
+    clangCIRFrontendAction
+    MLIRIR
+    )
+endif()
+
 if(CLANG_ENABLE_ARCMT)
   list(APPEND link_libs
     clangARCMigrate
@@ -29,7 +38,13 @@ add_clang_library(clangFrontendTool
 
   DEPENDS
   ClangDriverOptions
+  ${deps}
 
   LINK_LIBS
   ${link_libs}
   )
+
+if(CLANG_ENABLE_CIR)
+  target_include_directories(clangFrontendTool PRIVATE ${LLVM_MAIN_SRC_DIR}/../mlir/include)
+  target_include_directories(clangFrontendTool PRIVATE ${CMAKE_BINARY_DIR}/tools/mlir/include)
+endif()
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 7476b1076d1038..60fde03289cf35 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -31,6 +31,11 @@
 #include "llvm/Support/BuryPointer.h"
 #include "llvm/Support/DynamicLibrary.h"
 #include "llvm/Support/ErrorHandling.h"
+
+#if CLANG_ENABLE_CIR
+#include "clang/CIR/FrontendAction/CIRGenAction.h"
+#endif
+
 using namespace clang;
 using namespace llvm::opt;
 
@@ -42,6 +47,13 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
   StringRef Action("unknown");
   (void)Action;
 
+  unsigned UseCIR = CI.getFrontendOpts().UseClangIRPipeline;
+  frontend::ActionKind Act = CI.getFrontendOpts().ProgramAction;
+  bool EmitsCIR = Act == EmitCIR;
+
+  if (!UseCIR && EmitsCIR)
+    llvm::report_fatal_error("-emit-cir and only valid when using -fclangir");
+
   switch (CI.getFrontendOpts().ProgramAction) {
   case ASTDeclList:            return std::make_unique<ASTDeclListAction>();
   case ASTDump:                return std::make_unique<ASTDumpAction>();
@@ -54,7 +66,11 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
   case EmitAssembly:           return std::make_unique<EmitAssemblyAction>();
   case EmitBC:                 return std::make_unique<EmitBCAction>();
   case EmitCIR:
+#if CLANG_ENABLE_CIR
+    return std::make_unique<::cir::EmitCIRAction>();
+#else
     llvm_unreachable("CIR suppport not built into clang");
+#endif
   case EmitHTML:               return std::make_unique<HTMLPrintAction>();
   case EmitLLVM:               return std::make_unique<EmitLLVMAction>();
   case EmitLLVMOnly:           return std::make_unique<EmitLLVMOnlyAction>();
diff --git a/clang/test/CIR/hello.c b/clang/test/CIR/hello.c
new file mode 100644
index 00000000000000..61f38d0a5bd01a
--- /dev/null
+++ b/clang/test/CIR/hello.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s | FileCheck --allow-empty %s
+
+// just confirm that we don't crash
+// CHECK-NOT: *
+void foo() {}
diff --git a/clang/test/CIR/lit.local.cfg b/clang/test/CIR/lit.local.cfg
new file mode 100644
index 00000000000000..6afd60f47bff90
--- /dev/null
+++ b/clang/test/CIR/lit.local.cfg
@@ -0,0 +1,2 @@
+if not config.root.clang_enable_cir:
+    config.unsupported = True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' 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