[clang] [CIR] Call code gen; create empty cir.func op (PR #113483)
David Olsen via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 31 15:48:18 PDT 2024
https://github.com/dkolsen-pgi updated https://github.com/llvm/llvm-project/pull/113483
>From fd38921f9899e3e5ae538a94f123433119919731 Mon Sep 17 00:00:00 2001
From: David Olsen <dolsen at nvidia.com>
Date: Wed, 23 Oct 2024 11:01:40 -0700
Subject: [PATCH 1/3] [CIR] Call code gen; create empty cir.func op
Finish hooking up ClangIR code gen into the Clang control flow,
initializing enough that basic code gen is possible.
Add an almost empty cir.func op to the ClangIR dialect. Currently the
only property of the function is its name. Add the code necessary to
code gen a cir.func op.
Create essentially empty files
clang/lib/CIR/Dialect/IR/{CIRAttrs.cpp,CIRTypes.cpp}. These will be
filled in later as attributes and types are defined in the ClangIR
dialect.
(Part of upstreaming the ClangIR incubator project into LLVM.)
---
clang/include/clang/CIR/CIRGenerator.h | 1 +
.../include/clang/CIR/Dialect/IR/CIRDialect.h | 18 +++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 46 ++++++
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 151 +++++++++++++++++-
clang/lib/CIR/CodeGen/CIRGenModule.h | 31 ++++
clang/lib/CIR/CodeGen/CIRGenerator.cpp | 10 +-
clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 38 +++++
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 52 +++++-
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 37 +++++
clang/lib/CIR/Dialect/IR/CMakeLists.txt | 2 +
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 43 ++++-
clang/lib/Driver/ToolChains/Clang.cpp | 2 +
12 files changed, 424 insertions(+), 7 deletions(-)
create mode 100644 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
create mode 100644 clang/lib/CIR/Dialect/IR/CIRTypes.cpp
diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h
index 9a8930ac46ea9c..f72cea6e11692a 100644
--- a/clang/include/clang/CIR/CIRGenerator.h
+++ b/clang/include/clang/CIR/CIRGenerator.h
@@ -53,6 +53,7 @@ class CIRGenerator : public clang::ASTConsumer {
~CIRGenerator() override;
void Initialize(clang::ASTContext &astCtx) override;
bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
+ mlir::ModuleOp getModule();
};
} // namespace cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index d53e5d1663d62a..5c00225013d81e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -13,4 +13,22 @@
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/Dialect.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/Interfaces/CallInterfaces.h"
+#include "mlir/Interfaces/ControlFlowInterfaces.h"
+#include "mlir/Interfaces/FunctionInterfaces.h"
+#include "mlir/Interfaces/InferTypeOpInterface.h"
+#include "mlir/Interfaces/LoopLikeInterface.h"
+#include "mlir/Interfaces/MemorySlotInterfaces.h"
+#include "mlir/Interfaces/SideEffectInterfaces.h"
+
+#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"
+
+#define GET_OP_CLASSES
+#include "clang/CIR/Dialect/IR/CIROps.h.inc"
+
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7311c8db783e06..06554bf4717c81 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -16,4 +16,50 @@
include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "mlir/Interfaces/ControlFlowInterfaces.td"
+include "mlir/Interfaces/FunctionInterfaces.td"
+include "mlir/Interfaces/InferTypeOpInterface.td"
+include "mlir/Interfaces/LoopLikeInterface.td"
+include "mlir/Interfaces/MemorySlotInterfaces.td"
+include "mlir/Interfaces/SideEffectInterfaces.td"
+
+include "mlir/IR/BuiltinAttributeInterfaces.td"
+include "mlir/IR/EnumAttr.td"
+include "mlir/IR/SymbolInterfaces.td"
+include "mlir/IR/CommonAttrConstraints.td"
+
+//===----------------------------------------------------------------------===//
+// CIR Ops
+//===----------------------------------------------------------------------===//
+
+class LLVMLoweringInfo {
+ string llvmOp = "";
+}
+
+class CIR_Op<string mnemonic, list<Trait> traits = []> :
+ Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
+
+//===----------------------------------------------------------------------===//
+// FuncOp
+//===----------------------------------------------------------------------===//
+
+// For starters, cir.func has only name, nothing else. The other properties
+// of a function will be added over time as more of ClangIR is upstreamed.
+
+def FuncOp : CIR_Op<"func"> {
+ let summary = "Declare or define a function";
+ let description = [{
+ ... lots of text to be added later ...
+ }];
+
+ let arguments = (ins SymbolNameAttr:$sym_name);
+
+ let skipDefaultBuilders = 1;
+
+ let builders = [OpBuilder<(ins "StringRef":$name)>];
+
+ let hasCustomAssemblyFormat = 1;
+ let hasVerifier = 1;
+}
+
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 95e62326939fc2..1722ad8d2b1413 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -14,6 +14,9 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/GlobalDecl.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Location.h"
@@ -24,9 +27,149 @@ 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()) {}
+ : builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
+ theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
+ diags(diags), target(astCtx.getTargetInfo()) {}
+
+mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
+ assert(cLoc.isValid() && "expected valid source location");
+ const SourceManager &sm = astCtx.getSourceManager();
+ PresumedLoc pLoc = sm.getPresumedLoc(cLoc);
+ StringRef filename = pLoc.getFilename();
+ return mlir::FileLineColLoc::get(builder.getStringAttr(filename),
+ pLoc.getLine(), pLoc.getColumn());
+}
+
+mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
+ assert(cRange.isValid() && "expected a valid source range");
+ mlir::Location begin = getLoc(cRange.getBegin());
+ mlir::Location end = getLoc(cRange.getEnd());
+ SmallVector<mlir::Location, 2> locs = {begin, end};
+ mlir::Attribute metadata;
+ return mlir::FusedLoc::get(locs, metadata, builder.getContext());
+}
+
+void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
+
+ const auto *global = cast<ValueDecl>(gd.getDecl());
+
+ if (const auto *fd = dyn_cast<FunctionDecl>(global)) {
+ // Update deferred annotations with the latest declaration if the function
+ // was already used or defined.
+ if (fd->hasAttr<AnnotateAttr>()) {
+ errorNYI(fd->getSourceRange(), "defferedAnnotations");
+ }
+ if (!fd->doesThisDeclarationHaveABody()) {
+ if (!fd->doesDeclarationForceExternallyVisibleDefinition())
+ return;
+
+ errorNYI(fd->getSourceRange(),
+ "function declaration that forces code gen");
+ return;
+ }
+ } else {
+ const auto *vd = cast<VarDecl>(global);
+ assert(vd->isFileVarDecl() && "Cannot emit local var decl as global.");
+ errorNYI(vd->getSourceRange(), "global variable declaration");
+ }
+
+ // NYI: Defer emitting some global definitions until later
+ buildGlobalDefinition(gd);
+}
+
+void CIRGenModule::buildGlobalFunctionDefinition(clang::GlobalDecl gd,
+ mlir::Operation *op) {
+ auto const *d = cast<FunctionDecl>(gd.getDecl());
+
+ builder.create<mlir::cir::FuncOp>(getLoc(d->getSourceRange()),
+ d->getIdentifier()->getName());
+}
+
+void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd,
+ mlir::Operation *op) {
+ const auto *d = cast<ValueDecl>(gd.getDecl());
+ if (const auto *fd = dyn_cast<FunctionDecl>(d)) {
+ // NYI: Skip generation of CIR for functions with available_externally
+ // linkage at -O0.
+
+ if (const auto *method = dyn_cast<CXXMethodDecl>(d)) {
+ // Make sure to emit the definition(s) before we emit the thunks. This is
+ // necessary for the generation of certain thunks.
+ (void)method;
+ errorNYI(method->getSourceRange(), "member function");
+ return;
+ }
+
+ if (fd->isMultiVersion())
+ errorNYI(fd->getSourceRange(), "multiversion functions");
+ buildGlobalFunctionDefinition(gd, op);
+ return;
+ }
+
+ if (const auto *vd = dyn_cast<VarDecl>(d)) {
+ (void)vd;
+ errorNYI(vd->getSourceRange(), "global variable definition");
+ return;
+ }
+
+ llvm_unreachable("Invalid argument to CIRGenModule::buildGlobalDefinition");
+}
// Emit code for a single top level declaration.
-void CIRGenModule::buildTopLevelDecl(Decl *decl) {}
+void CIRGenModule::buildTopLevelDecl(Decl *decl) {
+
+ // Ignore dependent declarations.
+ if (decl->isTemplated())
+ return;
+
+ switch (decl->getKind()) {
+ default:
+ errorNYI(decl->getBeginLoc(), "declaration of kind",
+ decl->getDeclKindName());
+ break;
+
+ case Decl::Function: {
+ auto *fd = cast<FunctionDecl>(decl);
+ // Consteval functions shouldn't be emitted.
+ if (!fd->isConsteval())
+ buildGlobal(fd);
+ break;
+ }
+ }
+}
+
+DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
+ unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "ClangIR code gen NYI: %0");
+ return diags.Report(diagID) << feature;
+}
+
+DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
+ llvm::StringRef feature) {
+ unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "ClangIR code gen NYI: %0");
+ return diags.Report(loc, diagID) << feature;
+}
+
+DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
+ llvm::StringRef feature,
+ llvm::StringRef name) {
+ unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "ClangIR code gen NYI: %0: %1");
+ return diags.Report(loc, diagID) << feature << name;
+}
+
+DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
+ llvm::StringRef feature) {
+ unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "ClangIR code gen NYI: %0");
+ return diags.Report(loc.getBegin(), diagID) << feature << loc;
+}
+
+DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
+ llvm::StringRef feature,
+ llvm::StringRef name) {
+ unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "ClangIR code gen NYI: %0: %1");
+ return diags.Report(loc.getBegin(), diagID) << feature << name << loc;
+}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index ab2a1d8864659a..8c90182bab08c9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -15,15 +15,21 @@
#include "CIRGenTypeCache.h"
+#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
class ASTContext;
class CodeGenOptions;
class Decl;
+class DiagnosticBuilder;
class DiagnosticsEngine;
+class GlobalDecl;
class LangOptions;
+class SourceLocation;
+class SourceRange;
class TargetInfo;
} // namespace clang
@@ -44,6 +50,9 @@ class CIRGenModule : public CIRGenTypeCache {
~CIRGenModule() = default;
private:
+ // TODO 'builder' will change to CIRGenBuilderTy once that type is defined
+ mlir::OpBuilder builder;
+
/// Hold Clang AST information.
clang::ASTContext &astCtx;
@@ -52,10 +61,32 @@ class CIRGenModule : public CIRGenTypeCache {
/// A "module" matches a c/cpp source file: containing a list of functions.
mlir::ModuleOp theModule;
+ clang::DiagnosticsEngine &diags;
+
const clang::TargetInfo ⌖
public:
+ mlir::ModuleOp getModule() const { return theModule; }
+
+ /// Helpers to convert Clang's SourceLocation to an MLIR Location.
+ mlir::Location getLoc(clang::SourceLocation cLoc);
+ mlir::Location getLoc(clang::SourceRange cRange);
+
void buildTopLevelDecl(clang::Decl *decl);
+
+ /// Emit code for a single global function or variable declaration. Forward
+ /// declarations are emitted lazily.
+ void buildGlobal(clang::GlobalDecl gd);
+
+ void buildGlobalDefinition(clang::GlobalDecl gd,
+ mlir::Operation *op = nullptr);
+ void buildGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
+
+ DiagnosticBuilder errorNYI(llvm::StringRef);
+ DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
+ DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
+ DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
+ DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);
};
} // namespace cir
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
index 159355a99ece80..f53b052a151a39 100644
--- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -12,8 +12,11 @@
#include "CIRGenModule.h"
+#include "mlir/IR/MLIRContext.h"
+
#include "clang/AST/DeclGroup.h"
#include "clang/CIR/CIRGenerator.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
using namespace cir;
using namespace clang;
@@ -31,9 +34,14 @@ void CIRGenerator::Initialize(ASTContext &astCtx) {
this->astCtx = &astCtx;
- cgm = std::make_unique<CIRGenModule>(*mlirCtx, astCtx, codeGenOpts, diags);
+ mlirCtx = std::make_unique<mlir::MLIRContext>();
+ mlirCtx->getOrLoadDialect<mlir::cir::CIRDialect>();
+ cgm = std::make_unique<CIRGenModule>(*mlirCtx.get(), astCtx, codeGenOpts,
+ diags);
}
+mlir::ModuleOp CIRGenerator::getModule() { return cgm->getModule(); }
+
bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
for (Decl *decl : group)
diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
new file mode 100644
index 00000000000000..6d74d72b77dca7
--- /dev/null
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -0,0 +1,38 @@
+//===- CIRAttrs.cpp - MLIR CIR Attributes ---------------------------------===//
+//
+// 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 defines the attributes in the CIR dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+using namespace mlir;
+using namespace mlir::cir;
+
+//===----------------------------------------------------------------------===//
+// General CIR parsing / printing
+//===----------------------------------------------------------------------===//
+
+Attribute CIRDialect::parseAttribute(DialectAsmParser &parser,
+ Type type) const {
+ // No attributes yet to parse
+ return Attribute{};
+}
+
+void CIRDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
+ // No attributes yet to print
+}
+
+//===----------------------------------------------------------------------===//
+// CIR Dialect
+//===----------------------------------------------------------------------===//
+
+void CIRDialect::registerAttributes() {
+ // No attributes yet to register
+}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index c2829c3ff2af8c..fc79879000a8bc 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -10,4 +10,54 @@
//
//===----------------------------------------------------------------------===//
-#include <clang/CIR/Dialect/IR/CIRDialect.h>
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+#include "mlir/Support/LogicalResult.h"
+
+#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"
+
+using namespace mlir;
+using namespace mlir::cir;
+
+//===----------------------------------------------------------------------===//
+// CIR Dialect
+//===----------------------------------------------------------------------===//
+
+void mlir::cir::CIRDialect::initialize() {
+ registerTypes();
+ registerAttributes();
+ addOperations<
+#define GET_OP_LIST
+#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"
+ >();
+}
+
+//===----------------------------------------------------------------------===//
+// FuncOp
+//===----------------------------------------------------------------------===//
+
+void mlir::cir::FuncOp::build(OpBuilder &builder, OperationState &result,
+ StringRef name) {}
+
+ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
+ StringAttr nameAttr;
+ if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
+ state.attributes))
+ return failure();
+ return success();
+}
+
+void cir::FuncOp::print(OpAsmPrinter &p) {
+ p << ' ';
+ // For now the only property a function has is its name
+ p.printSymbolName(getSymName());
+}
+
+mlir::LogicalResult mlir::cir::FuncOp::verify() { return success(); }
+
+//===----------------------------------------------------------------------===//
+// TableGen'd op method definitions
+//===----------------------------------------------------------------------===//
+
+#define GET_OP_CLASSES
+#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
new file mode 100644
index 00000000000000..167c237ae5515c
--- /dev/null
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -0,0 +1,37 @@
+//===- CIRTypes.cpp - MLIR CIR Types --------------------------------------===//
+//
+// 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 defines the types in the CIR dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+
+using namespace mlir;
+using namespace mlir::cir;
+
+//===----------------------------------------------------------------------===//
+// General CIR parsing / printing
+//===----------------------------------------------------------------------===//
+
+Type CIRDialect::parseType(DialectAsmParser &parser) const {
+ // No types yet to parse
+ return Type{};
+}
+
+void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
+ // No types yet to print
+}
+
+//===----------------------------------------------------------------------===//
+// CIR Dialect
+//===----------------------------------------------------------------------===//
+
+void CIRDialect::registerTypes() {
+ // No types yet to register
+}
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index 0d7476b555705d..eaa5a6a9c8617b 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -1,3 +1,5 @@
add_clang_library(MLIRCIR
+ CIRAttrs.cpp
CIRDialect.cpp
+ CIRTypes.cpp
)
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 72b9fa0c13c595..9cda62f6be52b0 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -22,8 +22,11 @@ class CIRGenConsumer : public clang::ASTConsumer {
virtual void anchor();
+ CIRGenAction::OutputType Action;
+
std::unique_ptr<raw_pwrite_stream> OutputStream;
+ ASTContext *Context{nullptr};
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
std::unique_ptr<CIRGenerator> Gen;
@@ -37,14 +40,39 @@ class CIRGenConsumer : public clang::ASTConsumer {
const LangOptions &LangOptions,
const FrontendOptions &FEOptions,
std::unique_ptr<raw_pwrite_stream> OS)
- : OutputStream(std::move(OS)), FS(VFS),
+ : Action(Action), OutputStream(std::move(OS)), FS(VFS),
Gen(std::make_unique<CIRGenerator>(DiagnosticsEngine, std::move(VFS),
CodeGenOptions)) {}
+ void Initialize(ASTContext &Ctx) override {
+ assert(!Context && "initialized multiple times");
+
+ Context = &Ctx;
+
+ Gen->Initialize(Ctx);
+ }
+
bool HandleTopLevelDecl(DeclGroupRef D) override {
Gen->HandleTopLevelDecl(D);
return true;
}
+
+ void HandleTranslationUnit(ASTContext &C) override {
+ Gen->HandleTranslationUnit(C);
+ mlir::ModuleOp MlirModule = Gen->getModule();
+ switch (Action) {
+ case CIRGenAction::OutputType::EmitCIR:
+ if (OutputStream && MlirModule) {
+ mlir::OpPrintingFlags Flags;
+ Flags.enableDebugInfo(/*enable=*/true, /*prettyForm=*/false);
+ MlirModule->print(*OutputStream, Flags);
+ }
+ break;
+ default:
+ llvm_unreachable("NYI: CIRGenAction other than EmitCIR");
+ break;
+ }
+ }
};
} // namespace cir
@@ -55,10 +83,23 @@ CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx)
CIRGenAction::~CIRGenAction() { MLIRMod.release(); }
+static std::unique_ptr<raw_pwrite_stream>
+getOutputStream(CompilerInstance &CI, StringRef InFile,
+ CIRGenAction::OutputType Action) {
+ switch (Action) {
+ case CIRGenAction::OutputType::EmitCIR:
+ return CI.createDefaultOutputFile(false, InFile, "cir");
+ }
+ llvm_unreachable("Invalid CIRGenAction::OutputType");
+}
+
std::unique_ptr<ASTConsumer>
CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<llvm::raw_pwrite_stream> Out = CI.takeOutputStream();
+ if (!Out)
+ Out = getOutputStream(CI, InFile, Action);
+
auto Result = std::make_unique<cir::CIRGenConsumer>(
Action, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 06c44a660e98fb..da8b3a2b25bc5d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5337,6 +5337,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (JA.getType() == types::TY_RewrittenLegacyObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_Fragile;
+ } else if (JA.getType() == types::TY_CIR) {
+ CmdArgs.push_back("-emit-cir");
} else {
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
}
>From 88873f1575b7a6c8244b12d498b2c93bc9faa1c7 Mon Sep 17 00:00:00 2001
From: David Olsen <dolsen at nvidia.com>
Date: Thu, 31 Oct 2024 11:12:23 -0700
Subject: [PATCH 2/3] [CIR] Call code gen; create empty cir.func op
Followup commit:
Improve comments, variable names, and formatting. Some other code
cleanup.
Fix bugs in the creation of the `cir.func` op: add it to the module, and
correctly store its name.
Update the hello.c test to check that a `cir.func` op is generated.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 41 ++++++++++++++++++-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 29 +++++--------
clang/lib/CIR/CodeGen/CIRGenModule.h | 4 +-
clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 5 ++-
clang/lib/CIR/Dialect/IR/CMakeLists.txt | 3 ++
clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 2 -
clang/test/CIR/hello.c | 6 +--
7 files changed, 62 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 06554bf4717c81..67c18b20f53f03 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -32,6 +32,42 @@ include "mlir/IR/CommonAttrConstraints.td"
// CIR Ops
//===----------------------------------------------------------------------===//
+// LLVMLoweringInfo is used by cir-tablegen to generate LLVM lowering logic
+// automatically for CIR operations. The `llvmOp` field gives the name of the
+// LLVM IR dialect operation that the CIR operation will be lowered to. The
+// input arguments of the CIR operation will be passed in the same order to the
+// lowered LLVM IR operation.
+//
+// Example:
+//
+// For the following CIR operation definition:
+//
+// def FooOp : CIR_Op<"foo"> {
+// // ...
+// let arguments = (ins CIR_AnyType:$arg1, CIR_AnyType:$arg2);
+// let llvmOp = "BarOp";
+// }
+//
+// cir-tablegen will generate LLVM lowering code for the FooOp similar to the
+// following:
+//
+// class CIRFooOpLowering
+// : public mlir::OpConversionPattern<mlir::cir::FooOp> {
+// public:
+// using OpConversionPattern<mlir::cir::FooOp>::OpConversionPattern;
+//
+// mlir::LogicalResult matchAndRewrite(
+// mlir::cir::FooOp op,
+// OpAdaptor adaptor,
+// mlir::ConversionPatternRewriter &rewriter) const override {
+// rewriter.replaceOpWithNewOp<mlir::LLVM::BarOp>(
+// op, adaptor.getOperands()[0], adaptor.getOperands()[1]);
+// return mlir::success();
+// }
+// }
+//
+// If you want fully customized LLVM IR lowering logic, simply exclude the
+// `llvmOp` field from your CIR operation definition.
class LLVMLoweringInfo {
string llvmOp = "";
}
@@ -43,8 +79,9 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
// FuncOp
//===----------------------------------------------------------------------===//
-// For starters, cir.func has only name, nothing else. The other properties
-// of a function will be added over time as more of ClangIR is upstreamed.
+// TODO(CIR): For starters, cir.func has only name, nothing else. The other
+// properties of a function will be added over time as more of ClangIR is
+// upstreamed.
def FuncOp : CIR_Op<"func"> {
let summary = "Declare or define a function";
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 1722ad8d2b1413..0d0fdf8e76080c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -50,7 +50,6 @@ mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
}
void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
-
const auto *global = cast<ValueDecl>(gd.getDecl());
if (const auto *fd = dyn_cast<FunctionDecl>(global)) {
@@ -68,31 +67,29 @@ void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
return;
}
} else {
- const auto *vd = cast<VarDecl>(global);
- assert(vd->isFileVarDecl() && "Cannot emit local var decl as global.");
- errorNYI(vd->getSourceRange(), "global variable declaration");
+ errorNYI(global->getSourceRange(), "global variable declaration");
}
- // NYI: Defer emitting some global definitions until later
+ // TODO(CIR): Defer emitting some global definitions until later
buildGlobalDefinition(gd);
}
void CIRGenModule::buildGlobalFunctionDefinition(clang::GlobalDecl gd,
mlir::Operation *op) {
- auto const *d = cast<FunctionDecl>(gd.getDecl());
-
- builder.create<mlir::cir::FuncOp>(getLoc(d->getSourceRange()),
- d->getIdentifier()->getName());
+ auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
+ auto funcOp = builder.create<mlir::cir::FuncOp>(
+ getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName());
+ theModule.push_back(funcOp);
}
void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd,
mlir::Operation *op) {
- const auto *d = cast<ValueDecl>(gd.getDecl());
- if (const auto *fd = dyn_cast<FunctionDecl>(d)) {
- // NYI: Skip generation of CIR for functions with available_externally
+ const auto *decl = cast<ValueDecl>(gd.getDecl());
+ if (const auto *fd = dyn_cast<FunctionDecl>(decl)) {
+ // TODO(CIR): Skip generation of CIR for functions with available_externally
// linkage at -O0.
- if (const auto *method = dyn_cast<CXXMethodDecl>(d)) {
+ if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) {
// Make sure to emit the definition(s) before we emit the thunks. This is
// necessary for the generation of certain thunks.
(void)method;
@@ -106,12 +103,6 @@ void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd,
return;
}
- if (const auto *vd = dyn_cast<VarDecl>(d)) {
- (void)vd;
- errorNYI(vd->getSourceRange(), "global variable definition");
- return;
- }
-
llvm_unreachable("Invalid argument to CIRGenModule::buildGlobalDefinition");
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 8c90182bab08c9..6def25a054c46b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -50,7 +50,8 @@ class CIRGenModule : public CIRGenTypeCache {
~CIRGenModule() = default;
private:
- // TODO 'builder' will change to CIRGenBuilderTy once that type is defined
+ // TODO(CIR) 'builder' will change to CIRGenBuilderTy once that type is
+ // defined
mlir::OpBuilder builder;
/// Hold Clang AST information.
@@ -82,6 +83,7 @@ class CIRGenModule : public CIRGenTypeCache {
mlir::Operation *op = nullptr);
void buildGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
+ /// Helpers to emit "not yet implemented" error diagnostics
DiagnosticBuilder errorNYI(llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index fc79879000a8bc..e0b38a2902bdbb 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -37,7 +37,10 @@ void mlir::cir::CIRDialect::initialize() {
//===----------------------------------------------------------------------===//
void mlir::cir::FuncOp::build(OpBuilder &builder, OperationState &result,
- StringRef name) {}
+ StringRef name) {
+ result.addAttribute(SymbolTable::getSymbolAttrName(),
+ builder.getStringAttr(name));
+}
ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
StringAttr nameAttr;
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index eaa5a6a9c8617b..1518e8c760609c 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -2,4 +2,7 @@ add_clang_library(MLIRCIR
CIRAttrs.cpp
CIRDialect.cpp
CIRTypes.cpp
+
+ LINK_LIBS PUBLIC
+ MLIRIR
)
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 9cda62f6be52b0..5a31e207081936 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -46,9 +46,7 @@ class CIRGenConsumer : public clang::ASTConsumer {
void Initialize(ASTContext &Ctx) override {
assert(!Context && "initialized multiple times");
-
Context = &Ctx;
-
Gen->Initialize(Ctx);
}
diff --git a/clang/test/CIR/hello.c b/clang/test/CIR/hello.c
index 61f38d0a5bd01a..4b07c04994aa8f 100644
--- a/clang/test/CIR/hello.c
+++ b/clang/test/CIR/hello.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s | FileCheck --allow-empty %s
+// Smoke test for ClangIR code generation
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o - | FileCheck %s
-// just confirm that we don't crash
-// CHECK-NOT: *
void foo() {}
+// CHECK: cir.func @foo
>From d8d9ccebab2c3c9c6463f81529567363bbe9284e Mon Sep 17 00:00:00 2001
From: David Olsen <dolsen at nvidia.com>
Date: Thu, 31 Oct 2024 15:46:52 -0700
Subject: [PATCH 3/3] [CIR] Call code gen; create empty cir.func op
Followup change responding to code review comments. There are no
behavior changes, just small cleanup.
---
.../include/clang/CIR/Dialect/IR/CIRDialect.h | 3 +++
clang/include/clang/CIR/Dialect/IR/CIROps.td | 9 ++++----
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 23 ++++++++-----------
3 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
index 5c00225013d81e..0b71bdad29a3af 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h
@@ -28,6 +28,9 @@
#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"
+// TableGen'erated files for MLIR dialects require that a macro be defined when
+// they are included. GET_OP_CLASSES tells the file to define the classes for
+// the operations of that dialect.
#define GET_OP_CLASSES
#include "clang/CIR/Dialect/IR/CIROps.h.inc"
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 67c18b20f53f03..c0440faa3c7b17 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -16,6 +16,10 @@
include "clang/CIR/Dialect/IR/CIRDialect.td"
+include "mlir/IR/BuiltinAttributeInterfaces.td"
+include "mlir/IR/EnumAttr.td"
+include "mlir/IR/SymbolInterfaces.td"
+include "mlir/IR/CommonAttrConstraints.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
@@ -23,11 +27,6 @@ include "mlir/Interfaces/LoopLikeInterface.td"
include "mlir/Interfaces/MemorySlotInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
-include "mlir/IR/BuiltinAttributeInterfaces.td"
-include "mlir/IR/EnumAttr.td"
-include "mlir/IR/SymbolInterfaces.td"
-include "mlir/IR/CommonAttrConstraints.td"
-
//===----------------------------------------------------------------------===//
// CIR Ops
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0d0fdf8e76080c..588fff77396ccc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -44,9 +44,8 @@ mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
assert(cRange.isValid() && "expected a valid source range");
mlir::Location begin = getLoc(cRange.getBegin());
mlir::Location end = getLoc(cRange.getEnd());
- SmallVector<mlir::Location, 2> locs = {begin, end};
mlir::Attribute metadata;
- return mlir::FusedLoc::get(locs, metadata, builder.getContext());
+ return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext());
}
void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
@@ -130,37 +129,33 @@ void CIRGenModule::buildTopLevelDecl(Decl *decl) {
}
DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
- unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
- "ClangIR code gen NYI: %0");
+ unsigned diagID = diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
return diags.Report(diagID) << feature;
}
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature) {
- unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
- "ClangIR code gen NYI: %0");
+ unsigned diagID = diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
return diags.Report(loc, diagID) << feature;
}
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
llvm::StringRef feature,
llvm::StringRef name) {
- unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
- "ClangIR code gen NYI: %0: %1");
+ unsigned diagID = diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
return diags.Report(loc, diagID) << feature << name;
}
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature) {
- unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
- "ClangIR code gen NYI: %0");
- return diags.Report(loc.getBegin(), diagID) << feature << loc;
+ return errorNYI(loc.getBegin(), feature) << loc;
}
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
llvm::StringRef feature,
llvm::StringRef name) {
- unsigned diagID = diags.getCustomDiagID(DiagnosticsEngine::Error,
- "ClangIR code gen NYI: %0: %1");
- return diags.Report(loc.getBegin(), diagID) << feature << name << loc;
+ return errorNYI(loc.getBegin(), feature, name) << loc;
}
More information about the cfe-commits
mailing list