Skip to content

Commit c695a32

Browse files
authored
[CIR] Call code gen; create empty cir.func op (#113483)
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.)
1 parent a33d42a commit c695a32

File tree

13 files changed

+458
-10
lines changed

13 files changed

+458
-10
lines changed

clang/include/clang/CIR/CIRGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class CIRGenerator : public clang::ASTConsumer {
5353
~CIRGenerator() override;
5454
void Initialize(clang::ASTContext &astCtx) override;
5555
bool HandleTopLevelDecl(clang::DeclGroupRef group) override;
56+
mlir::ModuleOp getModule() const;
5657
};
5758

5859
} // namespace cir

clang/include/clang/CIR/Dialect/IR/CIRDialect.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,25 @@
1313
#ifndef LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
1414
#define LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H
1515

16+
#include "mlir/IR/Builders.h"
17+
#include "mlir/IR/BuiltinOps.h"
18+
#include "mlir/IR/BuiltinTypes.h"
19+
#include "mlir/IR/Dialect.h"
20+
#include "mlir/IR/OpDefinition.h"
21+
#include "mlir/Interfaces/CallInterfaces.h"
22+
#include "mlir/Interfaces/ControlFlowInterfaces.h"
23+
#include "mlir/Interfaces/FunctionInterfaces.h"
24+
#include "mlir/Interfaces/InferTypeOpInterface.h"
25+
#include "mlir/Interfaces/LoopLikeInterface.h"
26+
#include "mlir/Interfaces/MemorySlotInterfaces.h"
27+
#include "mlir/Interfaces/SideEffectInterfaces.h"
28+
29+
#include "clang/CIR/Dialect/IR/CIROpsDialect.h.inc"
30+
31+
// TableGen'erated files for MLIR dialects require that a macro be defined when
32+
// they are included. GET_OP_CLASSES tells the file to define the classes for
33+
// the operations of that dialect.
34+
#define GET_OP_CLASSES
35+
#include "clang/CIR/Dialect/IR/CIROps.h.inc"
36+
1637
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIRDIALECT_H

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,86 @@
1616

1717
include "clang/CIR/Dialect/IR/CIRDialect.td"
1818

19+
include "mlir/IR/BuiltinAttributeInterfaces.td"
20+
include "mlir/IR/EnumAttr.td"
21+
include "mlir/IR/SymbolInterfaces.td"
22+
include "mlir/IR/CommonAttrConstraints.td"
23+
include "mlir/Interfaces/ControlFlowInterfaces.td"
24+
include "mlir/Interfaces/FunctionInterfaces.td"
25+
include "mlir/Interfaces/InferTypeOpInterface.td"
26+
include "mlir/Interfaces/LoopLikeInterface.td"
27+
include "mlir/Interfaces/MemorySlotInterfaces.td"
28+
include "mlir/Interfaces/SideEffectInterfaces.td"
29+
30+
//===----------------------------------------------------------------------===//
31+
// CIR Ops
32+
//===----------------------------------------------------------------------===//
33+
34+
// LLVMLoweringInfo is used by cir-tablegen to generate LLVM lowering logic
35+
// automatically for CIR operations. The `llvmOp` field gives the name of the
36+
// LLVM IR dialect operation that the CIR operation will be lowered to. The
37+
// input arguments of the CIR operation will be passed in the same order to the
38+
// lowered LLVM IR operation.
39+
//
40+
// Example:
41+
//
42+
// For the following CIR operation definition:
43+
//
44+
// def FooOp : CIR_Op<"foo"> {
45+
// // ...
46+
// let arguments = (ins CIR_AnyType:$arg1, CIR_AnyType:$arg2);
47+
// let llvmOp = "BarOp";
48+
// }
49+
//
50+
// cir-tablegen will generate LLVM lowering code for the FooOp similar to the
51+
// following:
52+
//
53+
// class CIRFooOpLowering
54+
// : public mlir::OpConversionPattern<mlir::cir::FooOp> {
55+
// public:
56+
// using OpConversionPattern<mlir::cir::FooOp>::OpConversionPattern;
57+
//
58+
// mlir::LogicalResult matchAndRewrite(
59+
// mlir::cir::FooOp op,
60+
// OpAdaptor adaptor,
61+
// mlir::ConversionPatternRewriter &rewriter) const override {
62+
// rewriter.replaceOpWithNewOp<mlir::LLVM::BarOp>(
63+
// op, adaptor.getOperands()[0], adaptor.getOperands()[1]);
64+
// return mlir::success();
65+
// }
66+
// }
67+
//
68+
// If you want fully customized LLVM IR lowering logic, simply exclude the
69+
// `llvmOp` field from your CIR operation definition.
70+
class LLVMLoweringInfo {
71+
string llvmOp = "";
72+
}
73+
74+
class CIR_Op<string mnemonic, list<Trait> traits = []> :
75+
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
76+
77+
//===----------------------------------------------------------------------===//
78+
// FuncOp
79+
//===----------------------------------------------------------------------===//
80+
81+
// TODO(CIR): For starters, cir.func has only name, nothing else. The other
82+
// properties of a function will be added over time as more of ClangIR is
83+
// upstreamed.
84+
85+
def FuncOp : CIR_Op<"func"> {
86+
let summary = "Declare or define a function";
87+
let description = [{
88+
... lots of text to be added later ...
89+
}];
90+
91+
let arguments = (ins SymbolNameAttr:$sym_name);
92+
93+
let skipDefaultBuilders = 1;
94+
95+
let builders = [OpBuilder<(ins "StringRef":$name)>];
96+
97+
let hasCustomAssemblyFormat = 1;
98+
let hasVerifier = 1;
99+
}
100+
19101
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
#include "clang/AST/ASTContext.h"
1616
#include "clang/AST/DeclBase.h"
17+
#include "clang/AST/GlobalDecl.h"
18+
#include "clang/Basic/SourceManager.h"
19+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
1720

1821
#include "mlir/IR/BuiltinOps.h"
1922
#include "mlir/IR/Location.h"
@@ -24,9 +27,134 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
2427
clang::ASTContext &astctx,
2528
const clang::CodeGenOptions &cgo,
2629
DiagnosticsEngine &diags)
27-
: astCtx(astctx), langOpts(astctx.getLangOpts()),
28-
theModule{mlir::ModuleOp::create(mlir::UnknownLoc())},
29-
target(astCtx.getTargetInfo()) {}
30+
: builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
31+
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
32+
diags(diags), target(astCtx.getTargetInfo()) {}
33+
34+
mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
35+
assert(cLoc.isValid() && "expected valid source location");
36+
const SourceManager &sm = astCtx.getSourceManager();
37+
PresumedLoc pLoc = sm.getPresumedLoc(cLoc);
38+
StringRef filename = pLoc.getFilename();
39+
return mlir::FileLineColLoc::get(builder.getStringAttr(filename),
40+
pLoc.getLine(), pLoc.getColumn());
41+
}
42+
43+
mlir::Location CIRGenModule::getLoc(SourceRange cRange) {
44+
assert(cRange.isValid() && "expected a valid source range");
45+
mlir::Location begin = getLoc(cRange.getBegin());
46+
mlir::Location end = getLoc(cRange.getEnd());
47+
mlir::Attribute metadata;
48+
return mlir::FusedLoc::get({begin, end}, metadata, builder.getContext());
49+
}
50+
51+
void CIRGenModule::buildGlobal(clang::GlobalDecl gd) {
52+
const auto *global = cast<ValueDecl>(gd.getDecl());
53+
54+
if (const auto *fd = dyn_cast<FunctionDecl>(global)) {
55+
// Update deferred annotations with the latest declaration if the function
56+
// was already used or defined.
57+
if (fd->hasAttr<AnnotateAttr>())
58+
errorNYI(fd->getSourceRange(), "deferredAnnotations");
59+
if (!fd->doesThisDeclarationHaveABody()) {
60+
if (!fd->doesDeclarationForceExternallyVisibleDefinition())
61+
return;
62+
63+
errorNYI(fd->getSourceRange(),
64+
"function declaration that forces code gen");
65+
return;
66+
}
67+
} else {
68+
errorNYI(global->getSourceRange(), "global variable declaration");
69+
}
70+
71+
// TODO(CIR): Defer emitting some global definitions until later
72+
buildGlobalDefinition(gd);
73+
}
74+
75+
void CIRGenModule::buildGlobalFunctionDefinition(clang::GlobalDecl gd,
76+
mlir::Operation *op) {
77+
auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
78+
auto funcOp = builder.create<mlir::cir::FuncOp>(
79+
getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName());
80+
theModule.push_back(funcOp);
81+
}
82+
83+
void CIRGenModule::buildGlobalDefinition(clang::GlobalDecl gd,
84+
mlir::Operation *op) {
85+
const auto *decl = cast<ValueDecl>(gd.getDecl());
86+
if (const auto *fd = dyn_cast<FunctionDecl>(decl)) {
87+
// TODO(CIR): Skip generation of CIR for functions with available_externally
88+
// linkage at -O0.
89+
90+
if (const auto *method = dyn_cast<CXXMethodDecl>(decl)) {
91+
// Make sure to emit the definition(s) before we emit the thunks. This is
92+
// necessary for the generation of certain thunks.
93+
(void)method;
94+
errorNYI(method->getSourceRange(), "member function");
95+
return;
96+
}
97+
98+
if (fd->isMultiVersion())
99+
errorNYI(fd->getSourceRange(), "multiversion functions");
100+
buildGlobalFunctionDefinition(gd, op);
101+
return;
102+
}
103+
104+
llvm_unreachable("Invalid argument to CIRGenModule::buildGlobalDefinition");
105+
}
30106

31107
// Emit code for a single top level declaration.
32-
void CIRGenModule::buildTopLevelDecl(Decl *decl) {}
108+
void CIRGenModule::buildTopLevelDecl(Decl *decl) {
109+
110+
// Ignore dependent declarations.
111+
if (decl->isTemplated())
112+
return;
113+
114+
switch (decl->getKind()) {
115+
default:
116+
errorNYI(decl->getBeginLoc(), "declaration of kind",
117+
decl->getDeclKindName());
118+
break;
119+
120+
case Decl::Function: {
121+
auto *fd = cast<FunctionDecl>(decl);
122+
// Consteval functions shouldn't be emitted.
123+
if (!fd->isConsteval())
124+
buildGlobal(fd);
125+
break;
126+
}
127+
}
128+
}
129+
130+
DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
131+
unsigned diagID = diags.getCustomDiagID(
132+
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
133+
return diags.Report(diagID) << feature;
134+
}
135+
136+
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
137+
llvm::StringRef feature) {
138+
unsigned diagID = diags.getCustomDiagID(
139+
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
140+
return diags.Report(loc, diagID) << feature;
141+
}
142+
143+
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
144+
llvm::StringRef feature,
145+
llvm::StringRef name) {
146+
unsigned diagID = diags.getCustomDiagID(
147+
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
148+
return diags.Report(loc, diagID) << feature << name;
149+
}
150+
151+
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
152+
llvm::StringRef feature) {
153+
return errorNYI(loc.getBegin(), feature) << loc;
154+
}
155+
156+
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
157+
llvm::StringRef feature,
158+
llvm::StringRef name) {
159+
return errorNYI(loc.getBegin(), feature, name) << loc;
160+
}

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@
1515

1616
#include "CIRGenTypeCache.h"
1717

18+
#include "mlir/IR/Builders.h"
1819
#include "mlir/IR/BuiltinOps.h"
1920
#include "mlir/IR/MLIRContext.h"
21+
#include "llvm/ADT/StringRef.h"
2022

2123
namespace clang {
2224
class ASTContext;
2325
class CodeGenOptions;
2426
class Decl;
27+
class DiagnosticBuilder;
2528
class DiagnosticsEngine;
29+
class GlobalDecl;
2630
class LangOptions;
31+
class SourceLocation;
32+
class SourceRange;
2733
class TargetInfo;
2834
} // namespace clang
2935

@@ -44,6 +50,10 @@ class CIRGenModule : public CIRGenTypeCache {
4450
~CIRGenModule() = default;
4551

4652
private:
53+
// TODO(CIR) 'builder' will change to CIRGenBuilderTy once that type is
54+
// defined
55+
mlir::OpBuilder builder;
56+
4757
/// Hold Clang AST information.
4858
clang::ASTContext &astCtx;
4959

@@ -52,10 +62,34 @@ class CIRGenModule : public CIRGenTypeCache {
5262
/// A "module" matches a c/cpp source file: containing a list of functions.
5363
mlir::ModuleOp theModule;
5464

65+
clang::DiagnosticsEngine &diags;
66+
5567
const clang::TargetInfo &target;
5668

5769
public:
70+
mlir::ModuleOp getModule() const { return theModule; }
71+
72+
/// Helpers to convert the presumed location of Clang's SourceLocation to an
73+
/// MLIR Location.
74+
mlir::Location getLoc(clang::SourceLocation cLoc);
75+
mlir::Location getLoc(clang::SourceRange cRange);
76+
5877
void buildTopLevelDecl(clang::Decl *decl);
78+
79+
/// Emit code for a single global function or variable declaration. Forward
80+
/// declarations are emitted lazily.
81+
void buildGlobal(clang::GlobalDecl gd);
82+
83+
void buildGlobalDefinition(clang::GlobalDecl gd,
84+
mlir::Operation *op = nullptr);
85+
void buildGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
86+
87+
/// Helpers to emit "not yet implemented" error diagnostics
88+
DiagnosticBuilder errorNYI(llvm::StringRef);
89+
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
90+
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
91+
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
92+
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);
5993
};
6094
} // namespace cir
6195

clang/lib/CIR/CodeGen/CIRGenerator.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212

1313
#include "CIRGenModule.h"
1414

15+
#include "mlir/IR/MLIRContext.h"
16+
1517
#include "clang/AST/DeclGroup.h"
1618
#include "clang/CIR/CIRGenerator.h"
19+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
1720

1821
using namespace cir;
1922
using namespace clang;
@@ -31,9 +34,14 @@ void CIRGenerator::Initialize(ASTContext &astCtx) {
3134

3235
this->astCtx = &astCtx;
3336

34-
cgm = std::make_unique<CIRGenModule>(*mlirCtx, astCtx, codeGenOpts, diags);
37+
mlirCtx = std::make_unique<mlir::MLIRContext>();
38+
mlirCtx->loadDialect<mlir::cir::CIRDialect>();
39+
cgm = std::make_unique<CIRGenModule>(*mlirCtx.get(), astCtx, codeGenOpts,
40+
diags);
3541
}
3642

43+
mlir::ModuleOp CIRGenerator::getModule() const { return cgm->getModule(); }
44+
3745
bool CIRGenerator::HandleTopLevelDecl(DeclGroupRef group) {
3846

3947
for (Decl *decl : group)

0 commit comments

Comments
 (0)