Skip to content

Commit a43b2e1

Browse files
authored
[CIR] Integral types; simple global variables (#118743)
Add integral types to ClangIR. These are the first ClangIR types, so the change includes some infrastructure for managing ClangIR types. So that the integral types can be used somewhere, generate ClangIR for global variables using the new `cir.global` op. As with the current support for functions, global variables are just a stub at the moment. The only properties that global variables have are a name and a type. Add a new ClangIR code gen test global-var-simple.cpp, which defines global variables with most of the integral types. (Part of upstreaming the ClangIR incubator project into LLVM.)
1 parent 1bdb0a4 commit a43b2e1

File tree

12 files changed

+583
-38
lines changed

12 files changed

+583
-38
lines changed

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

+33-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_CIR_DIALECT_IR_CIROPS
1616

1717
include "clang/CIR/Dialect/IR/CIRDialect.td"
18+
include "clang/CIR/Dialect/IR/CIRTypes.td"
1819

1920
include "mlir/IR/BuiltinAttributeInterfaces.td"
2021
include "mlir/IR/EnumAttr.td"
@@ -74,6 +75,35 @@ class LLVMLoweringInfo {
7475
class CIR_Op<string mnemonic, list<Trait> traits = []> :
7576
Op<CIR_Dialect, mnemonic, traits>, LLVMLoweringInfo;
7677

78+
//===----------------------------------------------------------------------===//
79+
// GlobalOp
80+
//===----------------------------------------------------------------------===//
81+
82+
// TODO(CIR): For starters, cir.global has only name and type. The other
83+
// properties of a global variable will be added over time as more of ClangIR
84+
// is upstreamed.
85+
86+
def GlobalOp : CIR_Op<"global"> {
87+
let summary = "Declare or define a global variable";
88+
let description = [{
89+
The `cir.global` operation declares or defines a named global variable.
90+
91+
The backing memory for the variable is allocated statically and is
92+
described by the type of the variable.
93+
}];
94+
95+
let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$sym_type);
96+
97+
let assemblyFormat = [{ $sym_name `:` $sym_type attr-dict }];
98+
99+
let skipDefaultBuilders = 1;
100+
101+
let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name,
102+
"mlir::Type":$sym_type)>];
103+
104+
let hasVerifier = 1;
105+
}
106+
77107
//===----------------------------------------------------------------------===//
78108
// FuncOp
79109
//===----------------------------------------------------------------------===//
@@ -85,14 +115,15 @@ class CIR_Op<string mnemonic, list<Trait> traits = []> :
85115
def FuncOp : CIR_Op<"func"> {
86116
let summary = "Declare or define a function";
87117
let description = [{
88-
... lots of text to be added later ...
118+
The `cir.func` operation defines a function, similar to the `mlir::FuncOp`
119+
built-in.
89120
}];
90121

91122
let arguments = (ins SymbolNameAttr:$sym_name);
92123

93124
let skipDefaultBuilders = 1;
94125

95-
let builders = [OpBuilder<(ins "llvm::StringRef":$name)>];
126+
let builders = [OpBuilder<(ins "llvm::StringRef":$sym_name)>];
96127

97128
let hasCustomAssemblyFormat = 1;
98129
let hasVerifier = 1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares the types in the CIR dialect.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef MLIR_DIALECT_CIR_IR_CIRTYPES_H_
14+
#define MLIR_DIALECT_CIR_IR_CIRTYPES_H_
15+
16+
#include "mlir/IR/BuiltinAttributes.h"
17+
#include "mlir/IR/Types.h"
18+
#include "mlir/Interfaces/DataLayoutInterfaces.h"
19+
20+
//===----------------------------------------------------------------------===//
21+
// CIR Dialect Tablegen'd Types
22+
//===----------------------------------------------------------------------===//
23+
24+
#define GET_TYPEDEF_CLASSES
25+
#include "clang/CIR/Dialect/IR/CIROpsTypes.h.inc"
26+
27+
#endif // MLIR_DIALECT_CIR_IR_CIRTYPES_H_
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//===- CIRTypes.td - CIR dialect types ---------------------*- tablegen -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file declares the CIR dialect types.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef MLIR_CIR_DIALECT_CIR_TYPES
14+
#define MLIR_CIR_DIALECT_CIR_TYPES
15+
16+
include "clang/CIR/Dialect/IR/CIRDialect.td"
17+
include "mlir/Interfaces/DataLayoutInterfaces.td"
18+
include "mlir/IR/AttrTypeBase.td"
19+
20+
//===----------------------------------------------------------------------===//
21+
// CIR Types
22+
//===----------------------------------------------------------------------===//
23+
24+
class CIR_Type<string name, string typeMnemonic, list<Trait> traits = [],
25+
string baseCppClass = "::mlir::Type">
26+
: TypeDef<CIR_Dialect, name, traits, baseCppClass> {
27+
let mnemonic = typeMnemonic;
28+
}
29+
30+
//===----------------------------------------------------------------------===//
31+
// IntType
32+
//===----------------------------------------------------------------------===//
33+
34+
def CIR_IntType : CIR_Type<"Int", "int",
35+
[DeclareTypeInterfaceMethods<DataLayoutTypeInterface>]> {
36+
let summary = "Integer type with arbitrary precision up to a fixed limit";
37+
let description = [{
38+
CIR type that represents integer types with arbitrary precision, including
39+
standard integral types such as `int` and `long`, extended integral types
40+
such as `__int128`, and arbitrary width types such as `_BitInt(n)`.
41+
42+
Those integer types that are directly available in C/C++ standard are called
43+
primitive integer types. Said types are: `signed char`, `short`, `int`,
44+
`long`, `long long`, and their unsigned variations.
45+
}];
46+
let parameters = (ins "unsigned":$width, "bool":$isSigned);
47+
let hasCustomAssemblyFormat = 1;
48+
let extraClassDeclaration = [{
49+
/// Return true if this is a signed integer type.
50+
bool isSigned() const { return getIsSigned(); }
51+
/// Return true if this is an unsigned integer type.
52+
bool isUnsigned() const { return !getIsSigned(); }
53+
/// Return type alias.
54+
std::string getAlias() const {
55+
return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
56+
}
57+
/// Return true if this is a primitive integer type (i.e. signed or unsigned
58+
/// integer types whose bit width is 8, 16, 32, or 64).
59+
bool isPrimitive() const {
60+
return isValidPrimitiveIntBitwidth(getWidth());
61+
}
62+
bool isSignedPrimitive() const {
63+
return isPrimitive() && isSigned();
64+
}
65+
66+
/// Returns a minimum bitwidth of cir::IntType
67+
static unsigned minBitwidth() { return 1; }
68+
/// Returns a maximum bitwidth of cir::IntType
69+
static unsigned maxBitwidth() { return 128; }
70+
71+
/// Returns true if cir::IntType that represents a primitive integer type
72+
/// can be constructed from the provided bitwidth.
73+
static bool isValidPrimitiveIntBitwidth(unsigned width) {
74+
return width == 8 || width == 16 || width == 32 || width == 64;
75+
}
76+
}];
77+
let genVerifyDecl = 1;
78+
}
79+
80+
// Constraints
81+
82+
// Unsigned integer type of a specific width.
83+
class UInt<int width>
84+
: Type<And<[
85+
CPred<"::mlir::isa<::cir::IntType>($_self)">,
86+
CPred<"::mlir::cast<::cir::IntType>($_self).isUnsigned()">,
87+
CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
88+
]>, width # "-bit unsigned integer", "::cir::IntType">,
89+
BuildableType<
90+
"cir::IntType::get($_builder.getContext(), "
91+
# width # ", /*isSigned=*/false)"> {
92+
int bitwidth = width;
93+
}
94+
95+
def UInt1 : UInt<1>;
96+
def UInt8 : UInt<8>;
97+
def UInt16 : UInt<16>;
98+
def UInt32 : UInt<32>;
99+
def UInt64 : UInt<64>;
100+
101+
// Signed integer type of a specific width.
102+
class SInt<int width>
103+
: Type<And<[
104+
CPred<"::mlir::isa<::cir::IntType>($_self)">,
105+
CPred<"::mlir::cast<::cir::IntType>($_self).isSigned()">,
106+
CPred<"::mlir::cast<::cir::IntType>($_self).getWidth() == " # width>
107+
]>, width # "-bit signed integer", "::cir::IntType">,
108+
BuildableType<
109+
"cir::IntType::get($_builder.getContext(), "
110+
# width # ", /*isSigned=*/true)"> {
111+
int bitwidth = width;
112+
}
113+
114+
def SInt1 : SInt<1>;
115+
def SInt8 : SInt<8>;
116+
def SInt16 : SInt<16>;
117+
def SInt32 : SInt<32>;
118+
def SInt64 : SInt<64>;
119+
120+
def PrimitiveUInt
121+
: AnyTypeOf<[UInt8, UInt16, UInt32, UInt64], "primitive unsigned int",
122+
"::cir::IntType">;
123+
124+
def PrimitiveSInt
125+
: AnyTypeOf<[SInt8, SInt16, SInt32, SInt64], "primitive signed int",
126+
"::cir::IntType">;
127+
128+
def PrimitiveInt
129+
: AnyTypeOf<[UInt8, UInt16, UInt32, UInt64, SInt8, SInt16, SInt32, SInt64],
130+
"primitive int", "::cir::IntType">;
131+
132+
#endif // MLIR_CIR_DIALECT_CIR_TYPES

clang/lib/CIR/CodeGen/CIRGenModule.cpp

+33-25
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &context,
3131
DiagnosticsEngine &diags)
3232
: builder(&context), astCtx(astctx), langOpts(astctx.getLangOpts()),
3333
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))},
34-
diags(diags), target(astCtx.getTargetInfo()) {}
34+
diags(diags), target(astCtx.getTargetInfo()), genTypes(*this) {}
3535

3636
mlir::Location CIRGenModule::getLoc(SourceLocation cLoc) {
3737
assert(cLoc.isValid() && "expected valid source location");
@@ -67,7 +67,8 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
6767
return;
6868
}
6969
} else {
70-
errorNYI(global->getSourceRange(), "global variable declaration");
70+
assert(cast<VarDecl>(global)->isFileVarDecl() &&
71+
"Cannot emit local var decl as global");
7172
}
7273

7374
// TODO(CIR): Defer emitting some global definitions until later
@@ -77,9 +78,27 @@ void CIRGenModule::emitGlobal(clang::GlobalDecl gd) {
7778
void CIRGenModule::emitGlobalFunctionDefinition(clang::GlobalDecl gd,
7879
mlir::Operation *op) {
7980
auto const *funcDecl = cast<FunctionDecl>(gd.getDecl());
80-
auto funcOp = builder.create<cir::FuncOp>(
81-
getLoc(funcDecl->getSourceRange()), funcDecl->getIdentifier()->getName());
82-
theModule.push_back(funcOp);
81+
if (clang::IdentifierInfo *identifier = funcDecl->getIdentifier()) {
82+
auto funcOp = builder.create<cir::FuncOp>(
83+
getLoc(funcDecl->getSourceRange()), identifier->getName());
84+
theModule.push_back(funcOp);
85+
} else {
86+
errorNYI(funcDecl->getSourceRange().getBegin(),
87+
"function definition with a non-identifier for a name");
88+
}
89+
}
90+
91+
void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
92+
bool isTentative) {
93+
mlir::Type type = getTypes().convertType(vd->getType());
94+
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
95+
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
96+
identifier->getName(), type);
97+
theModule.push_back(varOp);
98+
} else {
99+
errorNYI(vd->getSourceRange().getBegin(),
100+
"variable definition with a non-identifier for a name");
101+
}
83102
}
84103

85104
void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
@@ -103,6 +122,9 @@ void CIRGenModule::emitGlobalDefinition(clang::GlobalDecl gd,
103122
return;
104123
}
105124

125+
if (const auto *vd = dyn_cast<VarDecl>(decl))
126+
return emitGlobalVarDefinition(vd, !vd->hasDefinition());
127+
106128
llvm_unreachable("Invalid argument to CIRGenModule::emitGlobalDefinition");
107129
}
108130

@@ -126,13 +148,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) {
126148
emitGlobal(fd);
127149
break;
128150
}
129-
}
130-
}
131151

132-
DiagnosticBuilder CIRGenModule::errorNYI(llvm::StringRef feature) {
133-
unsigned diagID = diags.getCustomDiagID(
134-
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0");
135-
return diags.Report(diagID) << feature;
152+
case Decl::Var: {
153+
auto *vd = cast<VarDecl>(decl);
154+
emitGlobal(vd);
155+
break;
156+
}
157+
}
136158
}
137159

138160
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
@@ -142,21 +164,7 @@ DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
142164
return diags.Report(loc, diagID) << feature;
143165
}
144166

145-
DiagnosticBuilder CIRGenModule::errorNYI(SourceLocation loc,
146-
llvm::StringRef feature,
147-
llvm::StringRef name) {
148-
unsigned diagID = diags.getCustomDiagID(
149-
DiagnosticsEngine::Error, "ClangIR code gen Not Yet Implemented: %0: %1");
150-
return diags.Report(loc, diagID) << feature << name;
151-
}
152-
153167
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
154168
llvm::StringRef feature) {
155169
return errorNYI(loc.getBegin(), feature) << loc;
156170
}
157-
158-
DiagnosticBuilder CIRGenModule::errorNYI(SourceRange loc,
159-
llvm::StringRef feature,
160-
llvm::StringRef name) {
161-
return errorNYI(loc.getBegin(), feature, name) << loc;
162-
}

clang/lib/CIR/CodeGen/CIRGenModule.h

+26-7
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,22 @@
1414
#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENMODULE_H
1515

1616
#include "CIRGenTypeCache.h"
17+
#include "CIRGenTypes.h"
1718

1819
#include "mlir/IR/Builders.h"
1920
#include "mlir/IR/BuiltinOps.h"
2021
#include "mlir/IR/MLIRContext.h"
22+
#include "clang/Basic/SourceManager.h"
2123
#include "llvm/ADT/StringRef.h"
2224

2325
namespace clang {
2426
class ASTContext;
2527
class CodeGenOptions;
2628
class Decl;
27-
class DiagnosticBuilder;
28-
class DiagnosticsEngine;
2929
class GlobalDecl;
3030
class LangOptions;
31-
class SourceLocation;
32-
class SourceRange;
3331
class TargetInfo;
32+
class VarDecl;
3433

3534
namespace CIRGen {
3635

@@ -64,8 +63,13 @@ class CIRGenModule : public CIRGenTypeCache {
6463

6564
const clang::TargetInfo &target;
6665

66+
CIRGenTypes genTypes;
67+
6768
public:
6869
mlir::ModuleOp getModule() const { return theModule; }
70+
mlir::OpBuilder &getBuilder() { return builder; }
71+
clang::ASTContext &getASTContext() const { return astCtx; }
72+
CIRGenTypes &getTypes() { return genTypes; }
6973

7074
/// Helpers to convert the presumed location of Clang's SourceLocation to an
7175
/// MLIR Location.
@@ -81,13 +85,28 @@ class CIRGenModule : public CIRGenTypeCache {
8185
void emitGlobalDefinition(clang::GlobalDecl gd,
8286
mlir::Operation *op = nullptr);
8387
void emitGlobalFunctionDefinition(clang::GlobalDecl gd, mlir::Operation *op);
88+
void emitGlobalVarDefinition(const clang::VarDecl *vd,
89+
bool isTentative = false);
8490

8591
/// Helpers to emit "not yet implemented" error diagnostics
86-
DiagnosticBuilder errorNYI(llvm::StringRef);
8792
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef);
88-
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef, llvm::StringRef);
93+
94+
template <typename T>
95+
DiagnosticBuilder errorNYI(SourceLocation loc, llvm::StringRef feature,
96+
const T &name) {
97+
unsigned diagID =
98+
diags.getCustomDiagID(DiagnosticsEngine::Error,
99+
"ClangIR code gen Not Yet Implemented: %0: %1");
100+
return diags.Report(loc, diagID) << feature << name;
101+
}
102+
89103
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef);
90-
DiagnosticBuilder errorNYI(SourceRange, llvm::StringRef, llvm::StringRef);
104+
105+
template <typename T>
106+
DiagnosticBuilder errorNYI(SourceRange loc, llvm::StringRef feature,
107+
const T &name) {
108+
return errorNYI(loc.getBegin(), feature, name) << loc;
109+
}
91110
};
92111
} // namespace CIRGen
93112

0 commit comments

Comments
 (0)