diff --git a/clang/include/clang/CIR/CIRGenerator.h b/clang/include/clang/CIR/CIRGenerator.h index 9a8930ac46ea9c..aa1a7e64459b35 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() const; }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h index d53e5d1663d62a..0b71bdad29a3af 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.h +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.h @@ -13,4 +13,25 @@ #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" + +// 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" + #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..c0440faa3c7b17 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -16,4 +16,86 @@ 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" +include "mlir/Interfaces/LoopLikeInterface.td" +include "mlir/Interfaces/MemorySlotInterfaces.td" +include "mlir/Interfaces/SideEffectInterfaces.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 = ""; +} + +class CIR_Op traits = []> : + Op, LLVMLoweringInfo; + +//===----------------------------------------------------------------------===// +// FuncOp +//===----------------------------------------------------------------------===// + +// 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"; + 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..c1adc7ecbf74dd 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,134 @@ 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()); + mlir::Attribute metadata; + return mlir::FusedLoc::get({begin, end}, 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(), "deferredAnnotations"); + if (!fd->doesThisDeclarationHaveABody()) { + if (!fd->doesDeclarationForceExternallyVisibleDefinition()) + return; + + errorNYI(fd->getSourceRange(), + "function declaration that forces code gen"); + return; + } + } else { + errorNYI(global->getSourceRange(), "global variable declaration"); + } + + // TODO(CIR): Defer emitting some global definitions until later + buildGlobalDefinition(gd); +} + +void CIRGenModule::buildGlobalFunctionDefinition(clang::GlobalDecl gd, + mlir::Operation *op) { + 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 *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(decl)) { + // 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; + } + + 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 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 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 Not Yet Implemented: %0: %1"); + return diags.Report(loc, diagID) << feature << name; +} + +DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, + llvm::StringRef feature) { + return errorNYI(loc.getBegin(), feature) << loc; +} + +DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc, + llvm::StringRef feature, + llvm::StringRef name) { + return errorNYI(loc.getBegin(), feature, name) << loc; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index ab2a1d8864659a..2bf6a5d9c8f597 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,10 @@ class CIRGenModule : public CIRGenTypeCache { ~CIRGenModule() = default; private: + // TODO(CIR) 'builder' will change to CIRGenBuilderTy once that type is + // defined + mlir::OpBuilder builder; + /// Hold Clang AST information. clang::ASTContext &astCtx; @@ -52,10 +62,34 @@ 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 the presumed location of 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); + + /// Helpers to emit "not yet implemented" error diagnostics + 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..152124a00b2bbd 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->loadDialect(); + cgm = std::make_unique(*mlirCtx.get(), astCtx, codeGenOpts, + diags); } +mlir::ModuleOp CIRGenerator::getModule() const { 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..e0b38a2902bdbb 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -10,4 +10,57 @@ // //===----------------------------------------------------------------------===// -#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) { + result.addAttribute(SymbolTable::getSymbolAttrName(), + builder.getStringAttr(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..1518e8c760609c 100644 --- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt @@ -1,3 +1,8 @@ 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 72b9fa0c13c595..5a31e207081936 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,37 @@ 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 +81,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 04b3832327a99c..35b8a5a2f30894 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!"); } 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