From fd38921f9899e3e5ae538a94f123433119919731 Mon Sep 17 00:00:00 2001 From: David Olsen Date: Wed, 23 Oct 2024 11:01:40 -0700 Subject: [PATCH 1/5] [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 traits = []> : + Op, 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 locs = {begin, end}; + mlir::Attribute metadata; + return mlir::FusedLoc::get(locs, metadata, builder.getContext()); +} + +void CIRGenModule::buildGlobal(clang::GlobalDecl gd) { + + const auto *global = cast(gd.getDecl()); + + if (const auto *fd = dyn_cast(global)) { + // Update deferred annotations with the latest declaration if the function + // was already used or defined. + if (fd->hasAttr()) { + 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(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(gd.getDecl()); + + builder.create(getLoc(d->getSourceRange()), + d->getIdentifier()->getName()); +} + +void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd, + mlir::Operation *op) { + const auto *d = cast(gd.getDecl()); + if (const auto *fd = dyn_cast(d)) { + // NYI: Skip generation of CIR for functions with available_externally + // linkage at -O0. + + if (const auto *method = dyn_cast(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(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(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(*mlirCtx, astCtx, codeGenOpts, diags); + mlirCtx = std::make_unique(); + mlirCtx->getOrLoadDialect(); + cgm = std::make_unique(*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 +#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 OutputStream; + ASTContext *Context{nullptr}; IntrusiveRefCntPtr FS; std::unique_ptr Gen; @@ -37,14 +40,39 @@ class CIRGenConsumer : public clang::ASTConsumer { const LangOptions &LangOptions, const FrontendOptions &FEOptions, std::unique_ptr OS) - : OutputStream(std::move(OS)), FS(VFS), + : Action(Action), OutputStream(std::move(OS)), FS(VFS), Gen(std::make_unique(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 +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 CIRGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::unique_ptr Out = CI.takeOutputStream(); + if (!Out) + Out = getOutputStream(CI, InFile, Action); + auto Result = std::make_unique( 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 Date: Thu, 31 Oct 2024 11:12:23 -0700 Subject: [PATCH 2/5] [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 { +// public: +// using OpConversionPattern::OpConversionPattern; +// +// mlir::LogicalResult matchAndRewrite( +// mlir::cir::FooOp op, +// OpAdaptor adaptor, +// mlir::ConversionPatternRewriter &rewriter) const override { +// rewriter.replaceOpWithNewOp( +// 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 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(gd.getDecl()); if (const auto *fd = dyn_cast(global)) { @@ -68,31 +67,29 @@ void CIRGenModule::buildGlobal(clang::GlobalDecl gd) { return; } } else { - const auto *vd = cast(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(gd.getDecl()); - - builder.create(getLoc(d->getSourceRange()), - d->getIdentifier()->getName()); + auto const *funcDecl = cast(gd.getDecl()); + auto funcOp = builder.create( + getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName()); + theModule.push_back(funcOp); } void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd, mlir::Operation *op) { - const auto *d = cast(gd.getDecl()); - if (const auto *fd = dyn_cast(d)) { - // NYI: Skip generation of CIR for functions with available_externally + const auto *decl = cast(gd.getDecl()); + if (const auto *fd = dyn_cast(decl)) { + // TODO(CIR): Skip generation of CIR for functions with available_externally // linkage at -O0. - if (const auto *method = dyn_cast(d)) { + if (const auto *method = dyn_cast(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(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 Date: Thu, 31 Oct 2024 15:46:52 -0700 Subject: [PATCH 3/5] [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 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; } From 61041780943fcd8a57448ebfcf4bb24977d72673 Mon Sep 17 00:00:00 2001 From: David Olsen Date: Fri, 1 Nov 2024 15:18:22 -0700 Subject: [PATCH 4/5] [CIR] Call code gen; create empty cir.func op More followup responding to review comments. Make `CIRGenerator::getModule()` a `const` member function. Call `loadDialect` instead of `getOrLoadDialect` to load MLIR dialects. Fix a typo and remove unnecessary curly braces. --- clang/include/clang/CIR/CIRGenerator.h | 2 +- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 5 ++--- clang/lib/CIR/CodeGen/CIRGenerator.cpp | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h index f72cea6e11692a..aa1a7e64459b35 100644 --- a/clang/include/clang/CIR/CIRGenerator.h +++ b/clang/include/clang/CIR/CIRGenerator.h @@ -53,7 +53,7 @@ class CIRGenerator : public clang::ASTConsumer { ~CIRGenerator() override; void Initialize(clang::ASTContext &astCtx) override; bool HandleTopLevelDecl(clang::DeclGroupRef group) override; - mlir::ModuleOp getModule(); + mlir::ModuleOp getModule() const; }; } // namespace cir diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 588fff77396ccc..c1adc7ecbf74dd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -54,9 +54,8 @@ void CIRGenModule::buildGlobal(clang::GlobalDecl gd) { if (const auto *fd = dyn_cast(global)) { // Update deferred annotations with the latest declaration if the function // was already used or defined. - if (fd->hasAttr()) { - errorNYI(fd->getSourceRange(), "defferedAnnotations"); - } + if (fd->hasAttr()) + errorNYI(fd->getSourceRange(), "deferredAnnotations"); if (!fd->doesThisDeclarationHaveABody()) { if (!fd->doesDeclarationForceExternallyVisibleDefinition()) return; diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index f53b052a151a39..152124a00b2bbd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -35,12 +35,12 @@ void CIRGenerator::Initialize(ASTContext &astCtx) { this->astCtx = &astCtx; mlirCtx = std::make_unique(); - mlirCtx->getOrLoadDialect(); + mlirCtx->loadDialect(); cgm = std::make_unique(*mlirCtx.get(), astCtx, codeGenOpts, diags); } -mlir::ModuleOp CIRGenerator::getModule() { return cgm->getModule(); } +mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); } bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) { From a8f544469e58c44359aa6d3bb3470b012f95b211 Mon Sep 17 00:00:00 2001 From: David Olsen Date: Tue, 5 Nov 2024 09:56:40 -0800 Subject: [PATCH 5/5] Better comment about location conversions Improve the comment about converting `SourceLocation` to `mlir::Location`, being explicit that the presumed location is converted. Part of #113483 [CIR] Call code gen; create empty cir.func op --- clang/lib/CIR/CodeGen/CIRGenModule.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 6def25a054c46b..2bf6a5d9c8f597 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -69,7 +69,8 @@ class CIRGenModule : public CIRGenTypeCache { public: mlir::ModuleOp getModule() const { return theModule; } - /// Helpers to convert Clang's SourceLocation to an MLIR Location. + /// Helpers to convert the presumed location of Clang's SourceLocation to an + /// MLIR Location. mlir::Location getLoc(clang::SourceLocation cLoc); mlir::Location getLoc(clang::SourceRange cRange);