Author: Morris Hafner
Date: 2025-03-18T09:51:13-07:00
New Revision: 1ae307a709f81e57356cd135f6a30c3c6174cd70

URL: 
https://github.com/llvm/llvm-project/commit/1ae307a709f81e57356cd135f6a30c3c6174cd70
DIFF: 
https://github.com/llvm/llvm-project/commit/1ae307a709f81e57356cd135f6a30c3c6174cd70.diff

LOG: [CIR] Add cir-translate and cir-lsp-server tools (#131181)

Adds two new clang tools to the tree.

* cir-translate: Translates CIR to LLVM, similar to mlir-translate
* cir-lsp-server: Implementation of the Language Server Protocol for
ClangIR, similar to fir-lsp-server

---------

Co-authored-by: Morris Hafner <mhaf...@nvidia.com>

Added: 
    clang/test/CIR/Tools/cir-translate-triple.cir
    clang/test/CIR/Tools/has-triple-and-data-layout.cir
    clang/test/CIR/Tools/has-triple-no-data-layout.cir
    clang/test/CIR/Tools/invalid-translate-triple.cir
    clang/test/CIR/Tools/no-triple-has-data-layout.cir
    clang/test/CIR/Tools/no-triple-no-data-layout.cir
    clang/test/CIR/Tools/warn-default-triple.cir
    clang/tools/cir-lsp-server/CMakeLists.txt
    clang/tools/cir-lsp-server/cir-lsp-server.cpp
    clang/tools/cir-translate/CMakeLists.txt
    clang/tools/cir-translate/cir-translate.cpp

Modified: 
    clang/tools/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/test/CIR/Tools/cir-translate-triple.cir 
b/clang/test/CIR/Tools/cir-translate-triple.cir
new file mode 100644
index 0000000000000..fa653ef3de25f
--- /dev/null
+++ b/clang/test/CIR/Tools/cir-translate-triple.cir
@@ -0,0 +1,11 @@
+// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu 
--disable-cc-lowering %s -o %t.ll
+// RUN: FileCheck %s -input-file %t.ll -check-prefix=LLVM
+
+module {
+  cir.func @foo() {
+    cir.return
+  }
+}
+
+// LLVM-DAG: target triple = "x86_64-unknown-linux-gnu"
+// LLVM-DAG: target datalayout = "{{.*}}"

diff  --git a/clang/test/CIR/Tools/has-triple-and-data-layout.cir 
b/clang/test/CIR/Tools/has-triple-and-data-layout.cir
new file mode 100644
index 0000000000000..81da113f1d648
--- /dev/null
+++ b/clang/test/CIR/Tools/has-triple-and-data-layout.cir
@@ -0,0 +1,24 @@
+// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu 
--disable-cc-lowering %s -o %t.x86.ll
+// RUN: FileCheck %s -input-file %t.x86.ll -check-prefix=X86
+// RUN: cir-translate --cir-to-llvmir --target spirv64-unknown-unknown 
--disable-cc-lowering %s -o %t.spirv64.ll
+// RUN: FileCheck %s -input-file %t.spirv64.ll -check-prefix=SPIRV64
+// RUN: cir-translate --cir-to-llvmir --disable-cc-lowering %s -o %t.default.ll
+// RUN: FileCheck %s -input-file %t.default.ll -check-prefix=DEFAULT
+
+module attributes {
+  cir.triple = "spirv64-unknown-unknown",
+  dlti.dl_spec = #dlti.dl_spec<"dlti.global_memory_space" = 7 : ui64>
+} {
+  cir.func @foo() {
+    cir.return
+  }
+}
+
+// X86-NOT: target datalayout = "G7"
+// X86-DAG: target triple = "x86_64-unknown-linux-gnu"
+
+// SPIRV64-NOT: target datalayout = "G7"
+// SPIRV64-DAG: target triple = "spirv64-unknown-unknown"
+
+// DEFAULT-DAG: target datalayout = "G7"
+// DEFAULT-DAG: target triple = "spirv64-unknown-unknown"

diff  --git a/clang/test/CIR/Tools/has-triple-no-data-layout.cir 
b/clang/test/CIR/Tools/has-triple-no-data-layout.cir
new file mode 100644
index 0000000000000..34c543362bed1
--- /dev/null
+++ b/clang/test/CIR/Tools/has-triple-no-data-layout.cir
@@ -0,0 +1,23 @@
+// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu 
--disable-cc-lowering %s -o %t.x86.ll
+// RUN: FileCheck %s -input-file %t.x86.ll -check-prefix=X86
+// RUN: cir-translate --cir-to-llvmir --target spirv64-unknown-unknown 
--disable-cc-lowering %s -o %t.spirv64.ll
+// RUN: FileCheck %s -input-file %t.spirv64.ll -check-prefix=SPIRV64
+// RUN: cir-translate --cir-to-llvmir --disable-cc-lowering %s -o %t.default.ll
+// RUN: FileCheck %s -input-file %t.default.ll -check-prefix=DEFAULT
+
+module attributes {
+  cir.triple = "spirv64-unknown-unknown"
+} {
+  cir.func @foo() {
+    cir.return
+  }
+}
+
+// X86-DAG: target triple = "x86_64-unknown-linux-gnu"
+// X86-DAG: target datalayout = "{{.*}}"
+
+// SPIRV64-DAG: target triple = "spirv64-unknown-unknown"
+// SPIRV64-DAG: target datalayout = "{{.*}}"
+
+// DEFAULT-DAG: target triple = "spirv64-unknown-unknown"
+// DEFAULT-DAG: target datalayout = "{{.*}}"

diff  --git a/clang/test/CIR/Tools/invalid-translate-triple.cir 
b/clang/test/CIR/Tools/invalid-translate-triple.cir
new file mode 100644
index 0000000000000..07bd766a37875
--- /dev/null
+++ b/clang/test/CIR/Tools/invalid-translate-triple.cir
@@ -0,0 +1,8 @@
+// RUN: cir-translate -verify-diagnostics --cir-to-llvmir --target foobar 
--disable-cc-lowering %s 2>&1
+
+// expected-error@below {{invalid target triple 'foobar'}}
+module {
+  cir.func @foo() {
+    cir.return
+  }
+}

diff  --git a/clang/test/CIR/Tools/no-triple-has-data-layout.cir 
b/clang/test/CIR/Tools/no-triple-has-data-layout.cir
new file mode 100644
index 0000000000000..5dc2fdb75a7cc
--- /dev/null
+++ b/clang/test/CIR/Tools/no-triple-has-data-layout.cir
@@ -0,0 +1,18 @@
+// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu 
--disable-cc-lowering %s -o %t.x86.ll
+// RUN: FileCheck %s -input-file %t.x86.ll -check-prefix=X86
+// RUN: cir-translate --cir-to-llvmir --target spirv64-unknown-unknown 
--disable-cc-lowering %s -o %t.spirv64.ll
+// RUN: FileCheck %s -input-file %t.spirv64.ll -check-prefix=SPIRV64
+
+module attributes {
+  dlti.dl_spec = #dlti.dl_spec<"dlti.global_memory_space" = 7 : ui64>
+} {
+  cir.func @foo() {
+    cir.return
+  }
+}
+
+// X86-NOT: target datalayout = "G7"
+// X86-DAG: target triple = "x86_64-unknown-linux-gnu"
+
+// SPIRV64-NOT: target datalayout = "G7"
+// SPIRV64-DAG: target triple = "spirv64-unknown-unknown"

diff  --git a/clang/test/CIR/Tools/no-triple-no-data-layout.cir 
b/clang/test/CIR/Tools/no-triple-no-data-layout.cir
new file mode 100644
index 0000000000000..2e336a797c6a7
--- /dev/null
+++ b/clang/test/CIR/Tools/no-triple-no-data-layout.cir
@@ -0,0 +1,16 @@
+// RUN: cir-translate --cir-to-llvmir --target x86_64-unknown-linux-gnu 
--disable-cc-lowering %s -o %t.x86.ll
+// RUN: FileCheck %s -input-file %t.x86.ll -check-prefix=X86
+// RUN: cir-translate --cir-to-llvmir --target spirv64-unknown-unknown 
--disable-cc-lowering %s -o %t.spirv64.ll
+// RUN: FileCheck %s -input-file %t.spirv64.ll -check-prefix=SPIRV64
+
+module {
+  cir.func @foo() {
+    cir.return
+  }
+}
+
+// X86-DAG: target triple = "x86_64-unknown-linux-gnu"
+// X86-DAG: target datalayout = "{{.*}}"
+
+// SPIRV64-DAG: target triple = "spirv64-unknown-unknown"
+// SPIRV64-DAG: target datalayout = "{{.*}}"

diff  --git a/clang/test/CIR/Tools/warn-default-triple.cir 
b/clang/test/CIR/Tools/warn-default-triple.cir
new file mode 100644
index 0000000000000..9eeba69e98973
--- /dev/null
+++ b/clang/test/CIR/Tools/warn-default-triple.cir
@@ -0,0 +1,8 @@
+// RUN: cir-translate -verify-diagnostics --cir-to-llvmir 
--disable-cc-lowering %s
+
+// expected-warning@below {{no target triple provided, assuming}}
+module {
+  cir.func @foo() {
+    cir.return
+  }
+}

diff  --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index ae3414e177192..e3557c1328d53 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -5,6 +5,8 @@ add_clang_subdirectory(driver)
 add_clang_subdirectory(apinotes-test)
 if(CLANG_ENABLE_CIR)
   add_clang_subdirectory(cir-opt)
+  add_clang_subdirectory(cir-translate)
+  add_clang_subdirectory(cir-lsp-server)
 endif()
 add_clang_subdirectory(clang-
diff )
 add_clang_subdirectory(clang-format)

diff  --git a/clang/tools/cir-lsp-server/CMakeLists.txt 
b/clang/tools/cir-lsp-server/CMakeLists.txt
new file mode 100644
index 0000000000000..aad2646ce0187
--- /dev/null
+++ b/clang/tools/cir-lsp-server/CMakeLists.txt
@@ -0,0 +1,34 @@
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS)
+
+include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
+include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
+
+set(LIBS
+  ${dialect_libs}
+  ${conversion_libs}
+  ${test_libs}
+  clangCIR
+  clangCIRLoweringDirectToLLVM
+  MLIRCIR
+  MLIRAffineAnalysis
+  MLIRAnalysis
+  MLIRDialect
+  MLIRLspServerLib
+  MLIRParser
+  MLIRPass
+  MLIRTransforms
+  MLIRTransformUtils
+  MLIRSupport
+  MLIRIR
+  )
+
+add_mlir_tool(cir-lsp-server
+  cir-lsp-server.cpp
+
+  DEPENDS
+  ${LIBS}
+)
+
+target_link_libraries(cir-lsp-server PRIVATE ${LIBS})
+llvm_update_compile_flags(cir-lsp-server)

diff  --git a/clang/tools/cir-lsp-server/cir-lsp-server.cpp 
b/clang/tools/cir-lsp-server/cir-lsp-server.cpp
new file mode 100644
index 0000000000000..555967a5a21d5
--- /dev/null
+++ b/clang/tools/cir-lsp-server/cir-lsp-server.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A language server for ClangIR
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/InitAllDialects.h"
+#include "mlir/Tools/mlir-lsp-server/MlirLspServerMain.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+int main(int argc, char **argv) {
+  mlir::DialectRegistry registry;
+  mlir::registerAllDialects(registry);
+  registry.insert<cir::CIRDialect>();
+  return failed(mlir::MlirLspServerMain(argc, argv, registry));
+}

diff  --git a/clang/tools/cir-translate/CMakeLists.txt 
b/clang/tools/cir-translate/CMakeLists.txt
new file mode 100644
index 0000000000000..21834799ea82f
--- /dev/null
+++ b/clang/tools/cir-translate/CMakeLists.txt
@@ -0,0 +1,35 @@
+get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
+get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS)
+get_property(translation_libs GLOBAL PROPERTY MLIR_TRANSLATION_LIBS)
+
+include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
+include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
+
+add_clang_tool(cir-translate
+  cir-translate.cpp
+)
+
+clang_target_link_libraries(cir-translate
+  PRIVATE
+  clangCIR
+  clangCIRLoweringDirectToLLVM
+  MLIRCIR
+  MLIRCIRTransforms
+)
+
+target_link_libraries(cir-translate
+  PRIVATE
+  ${dialect_libs}
+  ${conversion_libs}
+  ${translation_libs}
+  MLIRAnalysis
+  MLIRDialect
+  MLIRIR
+  MLIROptLib
+  MLIRParser
+  MLIRPass
+  MLIRTransforms
+  MLIRTransformUtils
+  MLIRTranslateLib
+  MLIRSupport
+)

diff  --git a/clang/tools/cir-translate/cir-translate.cpp 
b/clang/tools/cir-translate/cir-translate.cpp
new file mode 100644
index 0000000000000..e0e9414602a16
--- /dev/null
+++ b/clang/tools/cir-translate/cir-translate.cpp
@@ -0,0 +1,166 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Converts CIR directly to LLVM IR, similar to mlir-translate or LLVM llc.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/InitAllTranslations.h"
+#include "mlir/Support/LogicalResult.h"
+#include "mlir/Target/LLVMIR/Dialect/All.h"
+#include "mlir/Target/LLVMIR/Import.h"
+#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
+#include "mlir/Tools/mlir-translate/Translation.h"
+
+#include "llvm/IR/Module.h"
+#include "llvm/TargetParser/Host.h"
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/Passes.h"
+#include "clang/CIR/LowerToLLVM.h"
+#include "clang/CIR/MissingFeatures.h"
+
+namespace cir {
+namespace direct {
+extern void registerCIRDialectTranslation(mlir::DialectRegistry &registry);
+} // namespace direct
+
+namespace {
+
+/// The goal of this option is to ensure that the triple and data layout specs
+/// are always available in the ClangIR module. With this requirement met, the
+/// behavior of this option is designed to be as intuitive as possible, as 
shown
+/// in the table below:
+///
+/// +--------+--------+-------------+-----------------+-----------------------+
+/// | Option | Triple | Data Layout | Behavior Triple | Behavior Data Layout  |
+/// +========+========+=============+=================+=======================+
+/// | T      | T      | T           | Overwrite       | Derive from triple    |
+/// | T      | T      | F           | Overwrite       | Derive from triple    |
+/// | T      | F      | T           | Overwrite       | Derive from triple    |
+/// | T      | F      | F           | Overwrite       | Derive from triple    |
+/// | F      | T      | T           |                 |                       |
+/// | F      | T      | F           |                 | Derive from triple    |
+/// | F      | F      | T           | Set default     | Derive from triple    |
+/// | F      | F      | F           | Set default     | Derive from triple    |
+/// +--------+--------+-------------+-----------------+-----------------------+
+llvm::cl::opt<std::string>
+    targetTripleOption("target",
+                       llvm::cl::desc("Specify a default target triple when "
+                                      "it's not available in the module"),
+                       llvm::cl::init(""));
+
+std::string prepareCIRModuleTriple(mlir::ModuleOp mod) {
+  std::string triple = targetTripleOption;
+
+  // Treat "" as the default target machine.
+  if (triple.empty()) {
+    triple = llvm::sys::getDefaultTargetTriple();
+
+    mod.emitWarning() << "no target triple provided, assuming " << triple;
+  }
+
+  mod->setAttr(cir::CIRDialect::getTripleAttrName(),
+               mlir::StringAttr::get(mod.getContext(), triple));
+  return triple;
+}
+
+llvm::LogicalResult prepareCIRModuleDataLayout(mlir::ModuleOp mod,
+                                               llvm::StringRef rawTriple) {
+  auto *context = mod.getContext();
+
+  // Data layout is fully determined by the target triple. Here we only pass 
the
+  // triple to get the data layout.
+  llvm::Triple triple(rawTriple);
+  clang::TargetOptions targetOptions;
+  targetOptions.Triple = rawTriple;
+  // FIXME: AllocateTarget is a big deal. Better make it a global state.
+  std::unique_ptr<clang::TargetInfo> targetInfo =
+      clang::targets::AllocateTarget(llvm::Triple(rawTriple), targetOptions);
+  if (!targetInfo) {
+    mod.emitError() << "error: invalid target triple '" << rawTriple << "'\n";
+    return llvm::failure();
+  }
+  std::string layoutString = targetInfo->getDataLayoutString();
+
+  // Registered dialects may not be loaded yet, ensure they are.
+  context->loadDialect<mlir::DLTIDialect, mlir::LLVM::LLVMDialect>();
+
+  mlir::DataLayoutSpecInterface dlSpec =
+      mlir::translateDataLayout(llvm::DataLayout(layoutString), context);
+  mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
+
+  return llvm::success();
+}
+
+/// Prepare requirements like cir.triple and data layout.
+llvm::LogicalResult prepareCIRModuleForTranslation(mlir::ModuleOp mod) {
+  auto modTriple = mod->getAttrOfType<mlir::StringAttr>(
+      cir::CIRDialect::getTripleAttrName());
+  auto modDataLayout = mod->getAttr(mlir::DLTIDialect::kDataLayoutAttrName);
+  bool hasTargetOption = targetTripleOption.getNumOccurrences() > 0;
+
+  // Skip the situation where nothing should be done.
+  if (!hasTargetOption && modTriple && modDataLayout)
+    return llvm::success();
+
+  std::string triple;
+
+  if (!hasTargetOption && modTriple) {
+    // Do nothing if it's already set.
+    triple = modTriple.getValue();
+  } else {
+    // Otherwise, overwrite or set default.
+    triple = prepareCIRModuleTriple(mod);
+  }
+
+  // If the data layout is not set, derive it from the triple.
+  return prepareCIRModuleDataLayout(mod, triple);
+}
+} // namespace
+} // namespace cir
+
+void registerToLLVMTranslation() {
+  static llvm::cl::opt<bool> disableCCLowering(
+      "disable-cc-lowering",
+      llvm::cl::desc("Disable calling convention lowering pass"),
+      llvm::cl::init(false));
+
+  mlir::TranslateFromMLIRRegistration registration(
+      "cir-to-llvmir", "Translate CIR to LLVMIR",
+      [](mlir::Operation *op, mlir::raw_ostream &output) {
+        auto cirModule = llvm::dyn_cast<mlir::ModuleOp>(op);
+
+        if (mlir::failed(cir::prepareCIRModuleForTranslation(cirModule)))
+          return mlir::failure();
+
+        llvm::LLVMContext llvmContext;
+        std::unique_ptr<llvm::Module> llvmModule =
+            cir::direct::lowerDirectlyFromCIRToLLVMIR(cirModule, llvmContext);
+        if (!llvmModule)
+          return mlir::failure();
+        llvmModule->print(output, nullptr);
+        return mlir::success();
+      },
+      [](mlir::DialectRegistry &registry) {
+        registry.insert<mlir::DLTIDialect, mlir::func::FuncDialect>();
+        mlir::registerAllToLLVMIRTranslations(registry);
+        cir::direct::registerCIRDialectTranslation(registry);
+      });
+}
+
+int main(int argc, char **argv) {
+  registerToLLVMTranslation();
+  return failed(mlir::mlirTranslateMain(argc, argv, "CIR Translation Tool"));
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to