Author: Andy Kaylor Date: 2025-02-24T11:22:58-08:00 New Revision: 607a1f2ace77fffb67a1f62df5ac6caa1c568f51
URL: https://github.com/llvm/llvm-project/commit/607a1f2ace77fffb67a1f62df5ac6caa1c568f51 DIFF: https://github.com/llvm/llvm-project/commit/607a1f2ace77fffb67a1f62df5ac6caa1c568f51.diff LOG: [CIR] Add cir-opt tool to exercise CIR dialect parsing (#128254) We need to be able to read in and parse files using the ClangIR dialect in order to test this part of the functionality. This change adds the minimum cir-opt tool needed to read and parse cir files and write them back to text. This tool will later be extended to add features for lowering from CIR to other MLIR dialects and to run CIR passes as they are upstreamed. Added: clang/include/clang/CIR/Passes.h clang/test/CIR/IR/func.cir clang/test/CIR/IR/global.cir clang/tools/cir-opt/CMakeLists.txt clang/tools/cir-opt/cir-opt.cpp Modified: clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/test/CMakeLists.txt clang/test/lit.cfg.py clang/tools/CMakeLists.txt Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Passes.h b/clang/include/clang/CIR/Passes.h new file mode 100644 index 0000000000000..1d202ce5bfb52 --- /dev/null +++ b/clang/include/clang/CIR/Passes.h @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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 exposes the entry points to create compiler passes for ClangIR. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CIR_PASSES_H +#define CLANG_CIR_PASSES_H + +#include "mlir/Pass/Pass.h" + +#include <memory> + +namespace cir { +namespace direct { +/// Create a pass that fully lowers CIR to the LLVMIR dialect. +std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass(); + +/// Adds passes that fully lower CIR to the LLVMIR dialect. +void populateCIRToLLVMPasses(mlir::OpPassManager &pm); + +} // namespace direct +} // end namespace cir + +#endif // CLANG_CIR_PASSES_H diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 235b5a057852a..ba7fab2865116 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -27,6 +27,7 @@ #include "clang/CIR/Dialect/IR/CIRAttrVisitor.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/MissingFeatures.h" +#include "clang/CIR/Passes.h" #include "llvm/IR/Module.h" #include "llvm/Support/TimeProfiler.h" @@ -304,11 +305,11 @@ void ConvertCIRToLLVMPass::runOnOperation() { signalPassFailure(); } -static std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { +std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { return std::make_unique<ConvertCIRToLLVMPass>(); } -static void populateCIRToLLVMPasses(mlir::OpPassManager &pm) { +void populateCIRToLLVMPasses(mlir::OpPassManager &pm) { pm.addPass(createConvertCIRToLLVMPass()); } diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir new file mode 100644 index 0000000000000..a32c3e697ed25 --- /dev/null +++ b/clang/test/CIR/IR/func.cir @@ -0,0 +1,85 @@ +// RUN: cir-opt %s | FileCheck %s + +module { +// void empty() { } +cir.func @empty() -> !cir.void { + cir.return +} +// CHECK: cir.func @empty() -> !cir.void { +// CHECK: cir.return +// CHECK: } + +// void voidret() { return; } +cir.func @voidret() -> !cir.void { + cir.return +} +// CHECK: cir.func @voidret() -> !cir.void { +// CHECK: cir.return +// CHECK: } + +// int intfunc() { return 42; } +cir.func @intfunc() -> !cir.int<s, 32> { + %0 = cir.const #cir.int<42> : !cir.int<s, 32> + cir.return %0 : !cir.int<s, 32> +} +// CHECK: cir.func @intfunc() -> !cir.int<s, 32> { +// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<s, 32> +// CHECK: cir.return %[[VAL]] : !cir.int<s, 32> +// CHECK: } + +// int scopes() { +// { +// { +// return 99; +// } +// } +//} +cir.func @scopes() -> !cir.int<s, 32> { + cir.scope { + cir.scope { + %0 = cir.const #cir.int<99> : !cir.int<s, 32> + cir.return %0 : !cir.int<s, 32> + } + } + cir.trap +} +// CHECK: cir.func @scopes() -> !cir.int<s, 32> { +// CHECK: cir.scope { +// CHECK: cir.scope { +// CHECK: %[[VAL:.*]] = cir.const #cir.int<99> : !cir.int<s, 32> +// CHECK: cir.return %[[VAL]] : !cir.int<s, 32> +// CHECK: } +// CHECK: } +// CHECK: cir.trap +// CHECK: } + +// long longfunc() { return 42l; } +cir.func @longfunc() -> !cir.int<s, 64> { + %0 = cir.const #cir.int<42> : !cir.int<s, 64> + cir.return %0 : !cir.int<s, 64> +} +// CHECK: cir.func @longfunc() -> !cir.int<s, 64> +// CHECK: %0 = cir.const #cir.int<42> : !cir.int<s, 64> +// CHECK: cir.return %0 : !cir.int<s, 64> +// CHECK: } + +// unsigned unsignedfunc() { return 42u; } +cir.func @unsignedfunc() -> !cir.int<u, 32> { + %0 = cir.const #cir.int<42> : !cir.int<u, 32> + cir.return %0 : !cir.int<u, 32> +} +// CHECK: cir.func @unsignedfunc() -> !cir.int<u, 32> +// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<u, 32> +// CHECK: cir.return %[[VAL]] : !cir.int<u, 32> +// CHECK: } + +// unsigned long long ullfunc() { return 42ull; } +cir.func @ullfunc() -> !cir.int<u, 64> { + %0 = cir.const #cir.int<42> : !cir.int<u, 64> + cir.return %0 : !cir.int<u, 64> +} +// CHECK: cir.func @ullfunc() -> !cir.int<u, 64> +// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<u, 64> +// CHECK: cir.return %[[VAL:.*]] : !cir.int<u, 64> +// CHECK: } +} diff --git a/clang/test/CIR/IR/global.cir b/clang/test/CIR/IR/global.cir new file mode 100644 index 0000000000000..6c68ab0a501ff --- /dev/null +++ b/clang/test/CIR/IR/global.cir @@ -0,0 +1,69 @@ +// RUN: cir-opt %s -o - | FileCheck %s + +module attributes {cir.triple = "x86_64-unknown-linux-gnu"} { + cir.global @c : !cir.int<s, 8> + cir.global @sc : !cir.int<s, 8> + cir.global @uc : !cir.int<u, 8> + cir.global @ss : !cir.int<s, 16> + cir.global @us = #cir.int<100> : !cir.int<u, 16> + cir.global @si = #cir.int<42> : !cir.int<s, 32> + cir.global @ui : !cir.int<u, 32> + cir.global @sl : !cir.int<s, 64> + cir.global @ul : !cir.int<u, 64> + cir.global @sll : !cir.int<s, 64> + cir.global @ull = #cir.int<123456> : !cir.int<u, 64> + cir.global @s128 : !cir.int<s, 128> + cir.global @u128 : !cir.int<u, 128> + cir.global @wc : !cir.int<s, 32> + cir.global @c8 : !cir.int<u, 8> + cir.global @c16 : !cir.int<u, 16> + cir.global @c32 : !cir.int<u, 32> + cir.global @sb20 : !cir.int<s, 20> + cir.global @ub48 : !cir.int<u, 48> + cir.global @f16 : !cir.f16 + cir.global @bf16 : !cir.bf16 + cir.global @f : !cir.float + cir.global @d = #cir.fp<1.250000e+00> : !cir.double + cir.global @ld : !cir.long_double<!cir.f80> + cir.global @f128 : !cir.f128 + cir.global @vp : !cir.ptr<!cir.void> + cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>> + cir.global @dp : !cir.ptr<!cir.double> + cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>> + cir.global @fp : !cir.ptr<!cir.func<!cir.void ()>> + cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<!cir.int<s, 32> (!cir.int<s, 32>)>> + cir.global @fpvar : !cir.ptr<!cir.func<!cir.void (!cir.int<s, 32>, ...)>> +} + +// CHECK: cir.global @c : !cir.int<s, 8> +// CHECK: cir.global @sc : !cir.int<s, 8> +// CHECK: cir.global @uc : !cir.int<u, 8> +// CHECK: cir.global @ss : !cir.int<s, 16> +// CHECK: cir.global @us = #cir.int<100> +// CHECK: cir.global @si = #cir.int<42> +// CHECK: cir.global @ui : !cir.int<u, 32> +// CHECK: cir.global @sl : !cir.int<s, 64> +// CHECK: cir.global @ul : !cir.int<u, 64> +// CHECK: cir.global @sll : !cir.int<s, 64> +// CHECK: cir.global @ull = #cir.int<123456> : !cir.int<u, 64> +// CHECK: cir.global @s128 : !cir.int<s, 128> +// CHECK: cir.global @u128 : !cir.int<u, 128> +// CHECK: cir.global @wc : !cir.int<s, 32> +// CHECK: cir.global @c8 : !cir.int<u, 8> +// CHECK: cir.global @c16 : !cir.int<u, 16> +// CHECK: cir.global @c32 : !cir.int<u, 32> +// CHECK: cir.global @sb20 : !cir.int<s, 20> +// CHECK: cir.global @ub48 : !cir.int<u, 48> +// CHECK: cir.global @f16 : !cir.f16 +// CHECK: cir.global @bf16 : !cir.bf16 +// CHECK: cir.global @f : !cir.float +// CHECK: cir.global @d = #cir.fp<1.250000e+00> : !cir.double +// CHECK: cir.global @ld : !cir.long_double<!cir.f80> +// CHECK: cir.global @f128 : !cir.f128 +// CHECK: cir.global @vp : !cir.ptr<!cir.void> +// CHECK: cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>> +// CHECK: cir.global @dp : !cir.ptr<!cir.double> +// CHECK: cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>> +// CHECK: cir.global @fp : !cir.ptr<!cir.func<!cir.void ()>> +// CHECK: cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<!cir.int<s, 32> (!cir.int<s, 32>)>> +// CHECK: cir.global @fpvar : !cir.ptr<!cir.func<!cir.void (!cir.int<s, 32>, ...)>> diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index 4ff81e7055c57..1c93e2b0d9844 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -85,7 +85,13 @@ list(APPEND CLANG_TEST_DEPS diagtool hmaptool ) - + +if(CLANG_ENABLE_CIR) + list(APPEND CLANG_TEST_DEPS + cir-opt + ) +endif() + if(CLANG_ENABLE_STATIC_ANALYZER) list(APPEND CLANG_TEST_DEPS clang-check diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index e4b39c4f71597..9820ddd1f14af 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -29,6 +29,7 @@ ".c", ".cpp", ".i", + ".cir", ".cppm", ".m", ".mm", @@ -85,6 +86,7 @@ tools = [ "apinotes-test", "c-index-test", + "cir-opt", "clang- diff ", "clang-format", "clang-repl", diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt index de0b47f3751f1..ae3414e177192 100644 --- a/clang/tools/CMakeLists.txt +++ b/clang/tools/CMakeLists.txt @@ -3,6 +3,9 @@ create_subdirectory_options(CLANG TOOL) add_clang_subdirectory(diagtool) add_clang_subdirectory(driver) add_clang_subdirectory(apinotes-test) +if(CLANG_ENABLE_CIR) + add_clang_subdirectory(cir-opt) +endif() add_clang_subdirectory(clang- diff ) add_clang_subdirectory(clang-format) add_clang_subdirectory(clang-fuzzer) diff --git a/clang/tools/cir-opt/CMakeLists.txt b/clang/tools/cir-opt/CMakeLists.txt new file mode 100644 index 0000000000000..75bec5f4e1b0b --- /dev/null +++ b/clang/tools/cir-opt/CMakeLists.txt @@ -0,0 +1,32 @@ +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) + +add_clang_tool(cir-opt + cir-opt.cpp +) + +clang_target_link_libraries(cir-opt + PRIVATE + clangCIR + clangCIRLoweringDirectToLLVM + MLIRCIR +) + +target_link_libraries(cir-opt + PRIVATE + ${dialect_libs} + ${conversion_libs} + MLIRAnalysis + MLIRDialect + MLIRIR + MLIRMemRefDialect + MLIROptLib + MLIRParser + MLIRPass + MLIRSideEffectInterfaces + MLIRTransforms + MLIRTransformUtils +) diff --git a/clang/tools/cir-opt/cir-opt.cpp b/clang/tools/cir-opt/cir-opt.cpp new file mode 100644 index 0000000000000..0c0f6dcd9eecf --- /dev/null +++ b/clang/tools/cir-opt/cir-opt.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Similar to MLIR/LLVM's "opt" tools but also deals with analysis and custom +// arguments. TODO: this is basically a copy from MlirOptMain.cpp, but capable +// of module emission as specified by the user. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h" +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/MemRef/IR/MemRef.h" +#include "mlir/InitAllPasses.h" +#include "mlir/Pass/PassManager.h" +#include "mlir/Pass/PassOptions.h" +#include "mlir/Pass/PassRegistry.h" +#include "mlir/Tools/mlir-opt/MlirOptMain.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Passes.h" + +struct CIRToLLVMPipelineOptions + : public mlir::PassPipelineOptions<CIRToLLVMPipelineOptions> {}; + +int main(int argc, char **argv) { + // TODO: register needed MLIR passes for CIR? + mlir::DialectRegistry registry; + registry.insert<mlir::BuiltinDialect, cir::CIRDialect, + mlir::memref::MemRefDialect, mlir::LLVM::LLVMDialect>(); + + mlir::PassPipelineRegistration<CIRToLLVMPipelineOptions> pipeline( + "cir-to-llvm", "", + [](mlir::OpPassManager &pm, const CIRToLLVMPipelineOptions &options) { + cir::direct::populateCIRToLLVMPasses(pm); + }); + + mlir::registerTransformsPasses(); + + return mlir::asMainReturnCode(MlirOptMain( + argc, argv, "Clang IR analysis and optimization tool\n", registry)); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits