Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions clang/include/clang/CIR/Passes.h
Original file line number Diff line number Diff line change
@@ -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 {
Comment on lines +20 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
namespace cir {
namespace direct {
namespace cir::direct {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There will eventually be things in this file that are in the cir namespace, but not in the cir::direct namespace, so I'd prefer to keep it separate.

/// 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
5 changes: 3 additions & 2 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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());
}

Expand Down
85 changes: 85 additions & 0 deletions clang/test/CIR/IR/func.cir
Original file line number Diff line number Diff line change
@@ -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: }
}
69 changes: 69 additions & 0 deletions clang/test/CIR/IR/global.cir
Original file line number Diff line number Diff line change
@@ -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>, ...)>>
8 changes: 7 additions & 1 deletion clang/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions clang/test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
".c",
".cpp",
".i",
".cir",
".cppm",
".m",
".mm",
Expand Down Expand Up @@ -85,6 +86,7 @@
tools = [
"apinotes-test",
"c-index-test",
"cir-opt",
"clang-diff",
"clang-format",
"clang-repl",
Expand Down
3 changes: 3 additions & 0 deletions clang/tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
32 changes: 32 additions & 0 deletions clang/tools/cir-opt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: MLIRCIR comes transitively from clangCIR no need for it here

Copy link
Contributor Author

@andykaylor andykaylor Feb 24, 2025

Choose a reason for hiding this comment

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

A shared library build fails with _ZN4mlir6detail14TypeIDResolverIN3cir10CIRDialectEvE2idE as an unresolved symbol if I remove this.

)

target_link_libraries(cir-opt
PRIVATE
${dialect_libs}
${conversion_libs}
MLIRAnalysis
MLIRDialect
MLIRIR
MLIRMemRefDialect
MLIROptLib
MLIRParser
MLIRPass
MLIRSideEffectInterfaces
MLIRTransforms
MLIRTransformUtils
)
46 changes: 46 additions & 0 deletions clang/tools/cir-opt/cir-opt.cpp
Original file line number Diff line number Diff line change
@@ -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));
}