Skip to content

Commit 607a1f2

Browse files
authored
[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.
1 parent be5c66d commit 607a1f2

File tree

9 files changed

+278
-3
lines changed

9 files changed

+278
-3
lines changed

clang/include/clang/CIR/Passes.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file exposes the entry points to create compiler passes for ClangIR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef CLANG_CIR_PASSES_H
14+
#define CLANG_CIR_PASSES_H
15+
16+
#include "mlir/Pass/Pass.h"
17+
18+
#include <memory>
19+
20+
namespace cir {
21+
namespace direct {
22+
/// Create a pass that fully lowers CIR to the LLVMIR dialect.
23+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass();
24+
25+
/// Adds passes that fully lower CIR to the LLVMIR dialect.
26+
void populateCIRToLLVMPasses(mlir::OpPassManager &pm);
27+
28+
} // namespace direct
29+
} // end namespace cir
30+
31+
#endif // CLANG_CIR_PASSES_H

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "clang/CIR/Dialect/IR/CIRAttrVisitor.h"
2828
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2929
#include "clang/CIR/MissingFeatures.h"
30+
#include "clang/CIR/Passes.h"
3031
#include "llvm/IR/Module.h"
3132
#include "llvm/Support/TimeProfiler.h"
3233

@@ -304,11 +305,11 @@ void ConvertCIRToLLVMPass::runOnOperation() {
304305
signalPassFailure();
305306
}
306307

307-
static std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
308+
std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
308309
return std::make_unique<ConvertCIRToLLVMPass>();
309310
}
310311

311-
static void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {
312+
void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {
312313
pm.addPass(createConvertCIRToLLVMPass());
313314
}
314315

clang/test/CIR/IR/func.cir

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// RUN: cir-opt %s | FileCheck %s
2+
3+
module {
4+
// void empty() { }
5+
cir.func @empty() -> !cir.void {
6+
cir.return
7+
}
8+
// CHECK: cir.func @empty() -> !cir.void {
9+
// CHECK: cir.return
10+
// CHECK: }
11+
12+
// void voidret() { return; }
13+
cir.func @voidret() -> !cir.void {
14+
cir.return
15+
}
16+
// CHECK: cir.func @voidret() -> !cir.void {
17+
// CHECK: cir.return
18+
// CHECK: }
19+
20+
// int intfunc() { return 42; }
21+
cir.func @intfunc() -> !cir.int<s, 32> {
22+
%0 = cir.const #cir.int<42> : !cir.int<s, 32>
23+
cir.return %0 : !cir.int<s, 32>
24+
}
25+
// CHECK: cir.func @intfunc() -> !cir.int<s, 32> {
26+
// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<s, 32>
27+
// CHECK: cir.return %[[VAL]] : !cir.int<s, 32>
28+
// CHECK: }
29+
30+
// int scopes() {
31+
// {
32+
// {
33+
// return 99;
34+
// }
35+
// }
36+
//}
37+
cir.func @scopes() -> !cir.int<s, 32> {
38+
cir.scope {
39+
cir.scope {
40+
%0 = cir.const #cir.int<99> : !cir.int<s, 32>
41+
cir.return %0 : !cir.int<s, 32>
42+
}
43+
}
44+
cir.trap
45+
}
46+
// CHECK: cir.func @scopes() -> !cir.int<s, 32> {
47+
// CHECK: cir.scope {
48+
// CHECK: cir.scope {
49+
// CHECK: %[[VAL:.*]] = cir.const #cir.int<99> : !cir.int<s, 32>
50+
// CHECK: cir.return %[[VAL]] : !cir.int<s, 32>
51+
// CHECK: }
52+
// CHECK: }
53+
// CHECK: cir.trap
54+
// CHECK: }
55+
56+
// long longfunc() { return 42l; }
57+
cir.func @longfunc() -> !cir.int<s, 64> {
58+
%0 = cir.const #cir.int<42> : !cir.int<s, 64>
59+
cir.return %0 : !cir.int<s, 64>
60+
}
61+
// CHECK: cir.func @longfunc() -> !cir.int<s, 64>
62+
// CHECK: %0 = cir.const #cir.int<42> : !cir.int<s, 64>
63+
// CHECK: cir.return %0 : !cir.int<s, 64>
64+
// CHECK: }
65+
66+
// unsigned unsignedfunc() { return 42u; }
67+
cir.func @unsignedfunc() -> !cir.int<u, 32> {
68+
%0 = cir.const #cir.int<42> : !cir.int<u, 32>
69+
cir.return %0 : !cir.int<u, 32>
70+
}
71+
// CHECK: cir.func @unsignedfunc() -> !cir.int<u, 32>
72+
// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<u, 32>
73+
// CHECK: cir.return %[[VAL]] : !cir.int<u, 32>
74+
// CHECK: }
75+
76+
// unsigned long long ullfunc() { return 42ull; }
77+
cir.func @ullfunc() -> !cir.int<u, 64> {
78+
%0 = cir.const #cir.int<42> : !cir.int<u, 64>
79+
cir.return %0 : !cir.int<u, 64>
80+
}
81+
// CHECK: cir.func @ullfunc() -> !cir.int<u, 64>
82+
// CHECK: %[[VAL:.*]] = cir.const #cir.int<42> : !cir.int<u, 64>
83+
// CHECK: cir.return %[[VAL:.*]] : !cir.int<u, 64>
84+
// CHECK: }
85+
}

clang/test/CIR/IR/global.cir

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: cir-opt %s -o - | FileCheck %s
2+
3+
module attributes {cir.triple = "x86_64-unknown-linux-gnu"} {
4+
cir.global @c : !cir.int<s, 8>
5+
cir.global @sc : !cir.int<s, 8>
6+
cir.global @uc : !cir.int<u, 8>
7+
cir.global @ss : !cir.int<s, 16>
8+
cir.global @us = #cir.int<100> : !cir.int<u, 16>
9+
cir.global @si = #cir.int<42> : !cir.int<s, 32>
10+
cir.global @ui : !cir.int<u, 32>
11+
cir.global @sl : !cir.int<s, 64>
12+
cir.global @ul : !cir.int<u, 64>
13+
cir.global @sll : !cir.int<s, 64>
14+
cir.global @ull = #cir.int<123456> : !cir.int<u, 64>
15+
cir.global @s128 : !cir.int<s, 128>
16+
cir.global @u128 : !cir.int<u, 128>
17+
cir.global @wc : !cir.int<s, 32>
18+
cir.global @c8 : !cir.int<u, 8>
19+
cir.global @c16 : !cir.int<u, 16>
20+
cir.global @c32 : !cir.int<u, 32>
21+
cir.global @sb20 : !cir.int<s, 20>
22+
cir.global @ub48 : !cir.int<u, 48>
23+
cir.global @f16 : !cir.f16
24+
cir.global @bf16 : !cir.bf16
25+
cir.global @f : !cir.float
26+
cir.global @d = #cir.fp<1.250000e+00> : !cir.double
27+
cir.global @ld : !cir.long_double<!cir.f80>
28+
cir.global @f128 : !cir.f128
29+
cir.global @vp : !cir.ptr<!cir.void>
30+
cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
31+
cir.global @dp : !cir.ptr<!cir.double>
32+
cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
33+
cir.global @fp : !cir.ptr<!cir.func<!cir.void ()>>
34+
cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<!cir.int<s, 32> (!cir.int<s, 32>)>>
35+
cir.global @fpvar : !cir.ptr<!cir.func<!cir.void (!cir.int<s, 32>, ...)>>
36+
}
37+
38+
// CHECK: cir.global @c : !cir.int<s, 8>
39+
// CHECK: cir.global @sc : !cir.int<s, 8>
40+
// CHECK: cir.global @uc : !cir.int<u, 8>
41+
// CHECK: cir.global @ss : !cir.int<s, 16>
42+
// CHECK: cir.global @us = #cir.int<100>
43+
// CHECK: cir.global @si = #cir.int<42>
44+
// CHECK: cir.global @ui : !cir.int<u, 32>
45+
// CHECK: cir.global @sl : !cir.int<s, 64>
46+
// CHECK: cir.global @ul : !cir.int<u, 64>
47+
// CHECK: cir.global @sll : !cir.int<s, 64>
48+
// CHECK: cir.global @ull = #cir.int<123456> : !cir.int<u, 64>
49+
// CHECK: cir.global @s128 : !cir.int<s, 128>
50+
// CHECK: cir.global @u128 : !cir.int<u, 128>
51+
// CHECK: cir.global @wc : !cir.int<s, 32>
52+
// CHECK: cir.global @c8 : !cir.int<u, 8>
53+
// CHECK: cir.global @c16 : !cir.int<u, 16>
54+
// CHECK: cir.global @c32 : !cir.int<u, 32>
55+
// CHECK: cir.global @sb20 : !cir.int<s, 20>
56+
// CHECK: cir.global @ub48 : !cir.int<u, 48>
57+
// CHECK: cir.global @f16 : !cir.f16
58+
// CHECK: cir.global @bf16 : !cir.bf16
59+
// CHECK: cir.global @f : !cir.float
60+
// CHECK: cir.global @d = #cir.fp<1.250000e+00> : !cir.double
61+
// CHECK: cir.global @ld : !cir.long_double<!cir.f80>
62+
// CHECK: cir.global @f128 : !cir.f128
63+
// CHECK: cir.global @vp : !cir.ptr<!cir.void>
64+
// CHECK: cir.global @ip = #cir.ptr<null> : !cir.ptr<!cir.int<s, 32>>
65+
// CHECK: cir.global @dp : !cir.ptr<!cir.double>
66+
// CHECK: cir.global @cpp : !cir.ptr<!cir.ptr<!cir.int<s, 8>>>
67+
// CHECK: cir.global @fp : !cir.ptr<!cir.func<!cir.void ()>>
68+
// CHECK: cir.global @fpii = #cir.ptr<null> : !cir.ptr<!cir.func<!cir.int<s, 32> (!cir.int<s, 32>)>>
69+
// CHECK: cir.global @fpvar : !cir.ptr<!cir.func<!cir.void (!cir.int<s, 32>, ...)>>

clang/test/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,13 @@ list(APPEND CLANG_TEST_DEPS
8585
diagtool
8686
hmaptool
8787
)
88-
88+
89+
if(CLANG_ENABLE_CIR)
90+
list(APPEND CLANG_TEST_DEPS
91+
cir-opt
92+
)
93+
endif()
94+
8995
if(CLANG_ENABLE_STATIC_ANALYZER)
9096
list(APPEND CLANG_TEST_DEPS
9197
clang-check

clang/test/lit.cfg.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
".c",
3030
".cpp",
3131
".i",
32+
".cir",
3233
".cppm",
3334
".m",
3435
".mm",
@@ -85,6 +86,7 @@
8586
tools = [
8687
"apinotes-test",
8788
"c-index-test",
89+
"cir-opt",
8890
"clang-diff",
8991
"clang-format",
9092
"clang-repl",

clang/tools/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ create_subdirectory_options(CLANG TOOL)
33
add_clang_subdirectory(diagtool)
44
add_clang_subdirectory(driver)
55
add_clang_subdirectory(apinotes-test)
6+
if(CLANG_ENABLE_CIR)
7+
add_clang_subdirectory(cir-opt)
8+
endif()
69
add_clang_subdirectory(clang-diff)
710
add_clang_subdirectory(clang-format)
811
add_clang_subdirectory(clang-fuzzer)

clang/tools/cir-opt/CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS)
2+
get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS)
3+
4+
include_directories(${LLVM_MAIN_SRC_DIR}/../mlir/include)
5+
include_directories(${CMAKE_BINARY_DIR}/tools/mlir/include)
6+
7+
add_clang_tool(cir-opt
8+
cir-opt.cpp
9+
)
10+
11+
clang_target_link_libraries(cir-opt
12+
PRIVATE
13+
clangCIR
14+
clangCIRLoweringDirectToLLVM
15+
MLIRCIR
16+
)
17+
18+
target_link_libraries(cir-opt
19+
PRIVATE
20+
${dialect_libs}
21+
${conversion_libs}
22+
MLIRAnalysis
23+
MLIRDialect
24+
MLIRIR
25+
MLIRMemRefDialect
26+
MLIROptLib
27+
MLIRParser
28+
MLIRPass
29+
MLIRSideEffectInterfaces
30+
MLIRTransforms
31+
MLIRTransformUtils
32+
)

clang/tools/cir-opt/cir-opt.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Similar to MLIR/LLVM's "opt" tools but also deals with analysis and custom
10+
// arguments. TODO: this is basically a copy from MlirOptMain.cpp, but capable
11+
// of module emission as specified by the user.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
16+
#include "mlir/Dialect/Func/IR/FuncOps.h"
17+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
18+
#include "mlir/Dialect/MemRef/IR/MemRef.h"
19+
#include "mlir/InitAllPasses.h"
20+
#include "mlir/Pass/PassManager.h"
21+
#include "mlir/Pass/PassOptions.h"
22+
#include "mlir/Pass/PassRegistry.h"
23+
#include "mlir/Tools/mlir-opt/MlirOptMain.h"
24+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
25+
#include "clang/CIR/Passes.h"
26+
27+
struct CIRToLLVMPipelineOptions
28+
: public mlir::PassPipelineOptions<CIRToLLVMPipelineOptions> {};
29+
30+
int main(int argc, char **argv) {
31+
// TODO: register needed MLIR passes for CIR?
32+
mlir::DialectRegistry registry;
33+
registry.insert<mlir::BuiltinDialect, cir::CIRDialect,
34+
mlir::memref::MemRefDialect, mlir::LLVM::LLVMDialect>();
35+
36+
mlir::PassPipelineRegistration<CIRToLLVMPipelineOptions> pipeline(
37+
"cir-to-llvm", "",
38+
[](mlir::OpPassManager &pm, const CIRToLLVMPipelineOptions &options) {
39+
cir::direct::populateCIRToLLVMPasses(pm);
40+
});
41+
42+
mlir::registerTransformsPasses();
43+
44+
return mlir::asMainReturnCode(MlirOptMain(
45+
argc, argv, "Clang IR analysis and optimization tool\n", registry));
46+
}

0 commit comments

Comments
 (0)